Debugging .NET Containers with Visual Studio Code Docker Tools

Chet Husk

The Docker tools for Visual Studio Code has released version 1.26.0, bringing built-in support for building and debugging container images using the .NET SDK.

Docker Debugging in VS Code

The Docker tools for Visual Studio Code are a set of tools that make it easy for developers to get started with containers. It provides scaffolding of Dockerfiles, integrations to build, run and debug the containers generated from those Dockerfiles, and provides in-editor access to a number of other Docker- and Container-related tools. You can learn more about this tooling at the Visual Studio Marketplace.

Previously, the Docker tools provided the ability to scaffold a Dockerfile for a .NET project. This Dockerfile looked something like this:

FROM AS base

USER app
FROM AS build
ARG configuration=Release
COPY ["MinimalApiSharp.csproj", "./"]
RUN dotnet restore "MinimalApiSharp.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "MinimalApiSharp.csproj" -c $configuration -o /app/build

FROM build AS publish
ARG configuration=Release
RUN dotnet publish "MinimalApiSharp.csproj" -c $configuration -o /app/publish /p:UseAppHost=false

FROM base AS final
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "MinimalApiSharp.dll"]

This is a great foundation for building an efficient container image, but there’s a lot to understand out of the box. Users are immediately faced with understanding multi-stage Dockerfiles, container build args, and ensuring that paths align across stages for the build and publish outputs.

Building containers with the .NET SDK

Starting in .NET 7, the .NET SDK has had the ability to create container images easily via dotnet publish. With a single PackageReference (or no package at all if you’re using 7.0.300 or later SDKs!), a single dotnet publish -p PublishProfile=DefaultContainer command results in a working container image for your application. It has secure defaults out of the box, and lets users customize almost every aspect of the generated container.

However, integrating these generated containers into tooling was a gap. This new version of the Docker tools for Visual Studio Code bridges that gap seamlessly – making it trivial to debug your containerized applications via the launch configuration mechanism in Visual Studio Code.

Bringing it together

Let’s take a look at what it takes to bring the SDK tooling and the Docker tooling together in VSCode.

First, create a new web project using the .NET SDK and open it in Visual Studio Code. I’ll be using the .NET 8 preveiw 6 SDK here.

> dotnet new web -n MyContainerizedApp
The template "ASP.NET Core Empty" was created successfully.

Processing post-creation actions...
Restoring D:\Code\Scratch\MyContainerizedApp\MyContainerizedApp.csproj:
Restore complete (1.0s)

Build succeeded in 1.4s
Restore succeeded.
> cd MyContainerizedApp
> code .

After the editor has launched, you should be able to press F5 (or whatever key combination you’ve bound to the workbench.action.debug.start command) and get a selection menu much like the one below:

select launch method dialog

The key item to look for on this menu is the Docker: Debug in Container launch method. This launch method will build your app into a container, then automatically launch that container with the debugging tools attached! If you select it from this menu, you’ll see another important decision:

select net sdk

This is where the new integration with the .NET SDK appears. If you select Use a Dockerfile here, then you’ll build the container with Docker according to a Dockerfile checked into your repo, but if you select the new Use .NET SDK option, the built-in containerization tooling in the .NET SDK will be used to build your container, then Docker will be used to run and debug that container.

As soon as you choose the Use .NET SDK option, you should see the tooling building the container. It will appear in the task terminal (typically at the bottom of your editor window), and it’ll look something like this:

* Executing task: dotnet-container-sdk: debug

> dotnet publish --os "linux" --arch "x64" -p: PublishProfile=Defau1tContainer --configuration "Debug" -p:ContainerImageTag=dev

MSBui1d version 17.7.0+5785ed5c2 for .NET
 Determining projects to restore...
 Restored d:\Code\Scratch\MyContainerizedApp\MyContainerizedApp.csproj (in 2.03 sec).
C:\Progran Files\dotnet\sdk\8.0.100-preview.6.23330.14\Sdks\microsoft.NET.sdk\targets\microsoft.NET.Runtimeldentifierlnference.
targets(314,5): message NETSDK1057: You are using a preview version of .NET. 
  See: [d:\Code\Scratch\MyContainerizedApp\MyContainerizedApp.csproj]
  MyContainerizedApp -> d:\Code\Scratch\MyContainerizedApp\bin\Debug\net8.0\linux-x64\MyContainerizedApp.dll
  MyContainerizedApp -> d:\Code\Scratch\MyContainerizedApp\bin\Debug\net8.0\linux-x64\publish\
  Building image 'mycontainerizedapp' with tags dev on top of base image

The terminal output here shows a few interesting things – the dotnet publish command used to build the container, as well as the MSBuild output sharing more about how the app container is being created.

After a brief moment while the container is being built, the VSCode Docker tooling will launch the generated container, and additionally open a browser window pointing to your newly-launched application:

running app

That was pretty easy, don’t you think? From here you can interact with the running container using all of the existing features of the Visual Studio Code Docker tooling.

What’s next?

This is just the beginning for the integration between the Docker tooling for Visual Studio Code and the .NET SDK. Future enhancements to the SDK containers tooling will allow for automatically mapping ports from your SDK-generated containers, and the SDK containers team is looking to deepen the integration with Docker to allow for easier use with Docker Compose.

If you’re not containinerizing your applications with the .NET SDK, we’d love to have you give that a try as well! You can learn more about how to containerize a .NET app with dotnet publish, and then learn how to customize the generated container.

Give the new features of the Docker Extension for Visual Studio code a try and let the team know what you think, and if you have feedback for the .NET SDK Container tooling, make sure to visit the repo and start a discussion!


Discussion is closed. Login to edit/delete existing comments.

  • Mystery Man 0

    I love containerization. Too bad it’s not available for Windows.

    • Igor Nesterov 4

      hm, are you sure? we use win containers

    • Chet HuskMicrosoft employee 4

      I’ve moderated most of the chats on this thread due to the content of those posts. Mystery Man was making a point about how many large Windows apps can be hard to move to Windows Containers, and other commenters were refuting that statement with examples of their own where apps had been successfully moved into Windows containers.

      Both can be true, but the name calling and tone of the thread is not appropriate for this venue. Windows Containers are a viable technology for many users and use cases AND it can be hard to migrate large and complex applications to a new hosting mechanism.

      • Mystery Man 0

        Mystery Man was making a point about how many large Windows apps can be hard to move to Windows Containers

        Size was never one of my concerns. No.

        1. Visual Studio (from Microsoft) is a GUI app and thus impossible to containerize with Windows Containers.
        2. PotPlayer (from Daum) is a GUI app that calls VMR and EVR.
        3. Final Fantasy VII (1992 video game from Square Enix) is a video game.
        4. Most importantly, Windows Containers offers containerization on Windows Server but is limited to virtualization on Windows.

        other commenters were refuting that statement with examples of their own

        Oh, did they? It must have escaped my notice. Would you kindly reproduce those “examples”?

        • Igor Nesterov 1

          There is a clean list of things which can’t be containerized. You can read about it here

          Regarding GUI apps:
          “Containers aren’t a solution equivalent to desktop application virtualization. They support only server-side applications that don’t require an interactive session. Because they run on specialized container images, they support only those applications that don’t need a graphical front end.”
          Other apps can be containerized.
          Mostly developers use it to containerize server side web services. In our case it’s web api apps, wcf apps

          • Mystery Man 0

            Yes, containerization is as disappointing as you said on Windows Server and entirely unavailable on the mainstream Windows family, i.e., 10 and 11.

    • Stuart Ballard 0

      The page linked near the bottom of the original article as “learn more about how to containerize a .NET app with dotnet publish” does include a highlighted alert saying “Important: currently, only Linux containers are supported”, so in the specific context of what this article is referring to, it does indeed appear to not support Windows. Which is kind of weird and disappointing for a Microsoft product, to be honest!

      • Chet HuskMicrosoft employee 3

        Great catch – I’m happy to report that Windows containers are supported with the tooling (you can target specific architectures via the RuntimeIdentifier MSBuild property as you might expect from other publish methods, or specify -r win-x64, etc from the command line) and we just need to update that docs page. I’ll get with that team ASAP to get that updated.

  • Jean Gatto 0

    In the latest VS Code updates, I’m no longer able to debug ASP.NET Core projects with docker-compose, anyone with the same problem?

    • anonymous 0

      this comment has been deleted.

    • Alex Yang (CONTAINER TOOLS)Microsoft employee 0

      Can you open an issue here and provide more details? We can then triage and take a look at the issue.

  • Will 保哥 0

    I’m using .NET SDK 7.0.306. I still need to install Microsoft.Net.Build.Containers package to build container when I use the “Use .NET SDK” option.

    • Chet HuskMicrosoft employee 0

      Can you tell me more about the kinds of projects you’re using? The happy path here is for WebSDK projects (those that use the “Microsoft.NET.Sdk.Web” SDK) – that shouldn’t require the package. Console applications and Worker templates will still need the package at this time. The team is planning on ‘lighting up’ support for Console and Worker projects in the future, though.

      • Will 保哥 0

        I run the following 3 commands:

        dotnet new web -n MyContainerizedApp
        cd MyContainerizedApp
        dotnet publish --os "linux" --arch "x64" -p:PublishProfile=DefaultContainer --configuration "Debug" -p:ContainerImageTag=dev

        I got this error:

        MSBuild version 17.6.8+c70978d4d for .NET
          Determining projects to restore...
          Restored G:\Projects\MyContainerizedApp\MyContainerizedApp.csproj (in 123 ms).
          MyContainerizedApp -> G:\Projects\MyContainerizedApp\bin\Debug\net7.0\linux-x64\MyContainerizedApp.dll
          MyContainerizedApp -> G:\Projects\MyContainerizedApp\bin\Debug\net7.0\linux-x64\publish\
        C:\Program Files\dotnet\sdk\7.0.306\Sdks\Microsoft.NET.Sdk.Publish\targets\DotNetCLIToolTargets\Microsoft.NET.Sdk.DotNe
        tCLITool.targets(104,11): error MSB4057: The target "PublishContainer" does not exist in the project. [G:\Projects\MyCo

        If I add this pacakge:

        dotnet add package Microsoft.Net.Build.Containers

        Then the image could be built.

        MSBuild version 17.6.8+c70978d4d for .NET
          Determining projects to restore...
          Restored G:\Projects\MyContainerizedApp\MyContainerizedApp.csproj (in 205 ms).
          MyContainerizedApp -> G:\Projects\MyContainerizedApp\bin\Debug\net7.0\linux-x64\MyContainerizedApp.dll
          MyContainerizedApp -> G:\Projects\MyContainerizedApp\bin\Debug\net7.0\linux-x64\publish\
          Building image 'mycontainerizedapp' with tags dev on top of base image
          Pushed container 'mycontainerizedapp:dev' to local daemon
        • Chet HuskMicrosoft employee 0

          Can you try removing the package and adding the following property to your project file:


          then retrying your publish command?

          • Will 保哥 0

            Yes, it works! Finally. Thanks!

            This also works:

            dotnet publish --os "linux" --arch "x64" -p:PublishProfile=DefaultContainer --configuration "Debug" -p:ContainerImageTag=dev -p:EnableSdkContainerSupport=true

            I think this property should be mentioned somewhere in the article or docs.

          • Chet HuskMicrosoft employee 1

            Gald to hear that worked @Will 保哥! I believe in 7.0.400 SDKs (and 8.0.100 this fall) we do automatically add the EnableSdkContainerSupport for Web projects, I got my timelines mixed up. I’ll work with the docs teams to get it all straightened out.

          • Will 保哥 0

            There is a bug in Visual Studio Code support for Container.

            Would you please watch my recorded video below:

            When I hit “Restart” the debugger, the container will be removed and unable to run again. It because “docker run” use the “–rm” argument.

Feedback usabilla icon