What you will learn
Containers make development, testing, and deployment more consistent by packaging your application with the runtime environment it needs. In this lesson, you will learn the practical Docker workflow for .NET developers using Visual Studio: build, run, debug, compose, inspect, and prepare for deployment.
Why containers matter for .NET projects
A container packages your application, runtime, environment settings, and dependencies into a repeatable unit. This reduces the common “works on my machine” problem because development, testing, and deployment environments become more similar.
| Problem | How containers help | Example |
|---|---|---|
| Different runtime versions | Image defines the runtime | .NET runtime image |
| Missing dependencies | Dockerfile installs and copies what is needed | Published app files |
| Multi-service setup | Compose starts services together | API + SQL Server |
| Deployment drift | Same image can move through environments | Dev → staging → production |
Prepare Visual Studio for Docker development
Before adding Docker support, make sure the container runtime is installed and running. Open Visual Studio, load your ASP.NET Core project, and confirm the app can run normally before containerizing it.
Install Docker Desktop or another supported runtime and verify it is running before starting Visual Studio container debugging.
Run the API locally with F5 or Ctrl+F5. Fix normal build or runtime errors before adding Docker.
docker --version
docker info
dotnet --infoAdd Docker support in Visual Studio
For an ASP.NET Core project, Visual Studio can add Docker support from the project context menu. This usually creates a Dockerfile and adds a Docker launch profile so you can build and debug the project inside a container.
- Right-click the ASP.NET Core project in Solution Explorer.
- Choose Add → Docker Support.
- Select the target operating system, usually Linux for cloud deployment scenarios.
- Build the project and select the Docker launch profile.
- Press F5 to start debugging inside the container.
Understand the multi-stage Dockerfile
A multi-stage Dockerfile keeps the final image smaller by using one stage to build the app and another stage to run only the published output. This is common for ASP.NET Core applications.
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
WORKDIR /app
EXPOSE 8080
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
COPY ["OrdersApi.csproj", "."]
RUN dotnet restore "OrdersApi.csproj"
COPY . .
RUN dotnet publish "OrdersApi.csproj" -c Release -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "OrdersApi.dll"]| Stage | Purpose | Why it matters |
|---|---|---|
base | Runtime environment | Defines where the app will run |
build | SDK build environment | Restores, builds, and publishes the project |
final | Final image | Contains only published app files and runtime |
Debug an app running inside a container
Visual Studio can build the image, start the container, attach the debugger, and route the browser to the mapped port. From the developer’s point of view, the debugging workflow is similar to local debugging, but the process runs inside the container.
Place breakpoints in controller actions, Minimal API handlers, services, and middleware.
Use Watch, Locals, Call Stack, and Exception Helper just as you would for local debugging.
Use Output, terminal logs, or the Containers window to see startup and runtime messages.
If the container is stale, rebuild the image or remove old containers before testing again.
docker ps
docker logs orders-api
docker exec -it orders-api /bin/shUse Docker Compose for multi-service development
Real applications often need more than one container. Docker Compose lets you describe the API, database, cache, message broker, or background worker in a single file, then start them together.
services:
orders-api:
build: .
ports:
- "8080:8080"
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ConnectionStrings__Default=Server=sql;Database=OrdersDb;User Id=sa;Password=${SA_PASSWORD};TrustServerCertificate=True
depends_on:
- sql
sql:
image: mcr.microsoft.com/mssql/server:2022-latest
environment:
- ACCEPT_EULA=Y
- SA_PASSWORD=${SA_PASSWORD}
ports:
- "1433:1433"
volumes:
- sql-data:/var/opt/mssql
volumes:
sql-data:Manage environment variables, ports, and volumes
Containers should be configurable without rebuilding the image. Use environment variables for settings, mapped ports for local access, and volumes for data that should survive container restarts.
| Item | Use case | Example |
|---|---|---|
| Environment variable | Change app settings per environment | ASPNETCORE_ENVIRONMENT=Development |
| Port mapping | Access container service from host | 8080:8080 |
| Volume | Persist database or file data | sql-data:/var/opt/mssql |
| Network | Allow services to reach one another | orders-api calls sql |
Inspect containers, images, logs, and files
Visual Studio’s container tooling helps you see running containers, images, ports, environment values, logs, and file systems. This is useful when a service starts locally but behaves differently inside the container.
Check status
Confirm the container is running and the expected ports are mapped.
Read logs
Look for startup failures, missing configuration, connection errors, or unhandled exceptions.
Inspect environment
Verify that connection strings and environment names are what you expect.
Rebuild when needed
If code or Dockerfile changes are not reflected, rebuild the image and restart the containers.
Where .NET Aspire fits
.NET Aspire is useful when a .NET solution has several services and infrastructure dependencies. Instead of manually remembering how every service is started, an Aspire AppHost can describe the application model and help you run the distributed system during development.
var builder = DistributedApplication.CreateBuilder(args);
var database = builder.AddSqlServer("sql")
.AddDatabase("OrdersDb");
builder.AddProject<Projects.OrdersApi>("orders-api")
.WithReference(database)
.WaitFor(database);
builder.Build().Run();Prepare a containerized API for deployment
Before deployment, the container image should be predictable, secure, and easy to monitor. The goal is not merely to make the image run locally, but to make it safe enough for staging and production environments.
| Checklist item | Why it matters |
|---|---|
| Use production app settings | Avoid running production with development behavior |
| Keep secrets outside the image | Prevents passwords or tokens from being copied into image layers |
| Add health endpoints | Lets platforms detect whether the service is ready |
| Log to standard output | Container platforms can collect logs cleanly |
| Use small runtime images | Reduces attack surface and deployment time |
| Scan dependencies and images | Finds known security issues before deployment |
Use Copilot to review container configuration
Copilot can explain Dockerfiles, suggest improvements, and help identify risky configuration. It should not replace manual review, especially for secrets, networking, ports, and production settings.
Review this Dockerfile for an ASP.NET Core API.
Look for unnecessary image layers, missing production settings, exposed ports, and security risks.
Do not rewrite it yet; explain the issues first.Review this docker-compose.yml file.
Check whether the API can reach the database, whether secrets are handled safely, and whether volume usage is appropriate for local development.My API works locally but fails inside Docker.
Here are the logs and environment variables. Help me identify whether the problem is ports, connection strings, HTTPS, or missing dependencies.Hands-on exercise: Containerize the Orders API
- Open the Orders API project from Lessons 5–9.
- Run it normally first and confirm the API endpoint works.
- Add Docker support from Visual Studio.
- Read the generated Dockerfile and identify the build, publish, and final stages.
- Run the app using the Docker launch profile and hit a breakpoint.
- Add Docker Compose with a database service.
- Move connection strings into environment variables.
- Use container logs to confirm the API connects to the database.
- Ask Copilot to review the Dockerfile and Compose file, then verify suggestions manually.
Visual Studio 2026 Made Easy
Visual Studio 2026 Made Easy gives you a structured path for learning Visual Studio, C#, .NET, debugging, testing, web development, databases, profiling, Git source control, deployment, containers, and AI-assisted workflows.