Day 1 - Dev Containers


Introduction
You know the drill. It happened to the best of us.
You clone a project, you’re excited to get started... and then it hits you - missing SDKs, version mismatches, half an hour fighting Docker installs, weird Windows file paths, and that nagging voice inside saying, "Wasn’t tech supposed to make life easier?"
The answer to that question is yes: Dev Containers fix those issues for you.
They wrap your entire dev environment — tools, SDKs, extensions, the works — inside a portable Docker container. No more "works on my machine" moments. No more cluttering your laptop with random dependencies.
Just code, clean and simple.
And if you’re on Windows?
Well, Microsoft realized the benefits of this technology and they created a Windows Subsystem for Linux - I am not making this up, that is literally what it is called: WSL. There is even a second version of it. This technology makes running dev containers smooth - especially if you are using a Windows machine.
In this mini-course, you're going from Zero to Hero in two days:
Day 1: Build a real C# app inside a container — and run it. Why C#? I did say, I like Microsoft. Joking aside, the language does not matter. The principles apply just the same.
Day 2: Customize, debug, and extend your environment without losing your mind.
Alright, enough talk. Let’s get coding. The code is not going to write itself (unless you are using AI, but even then you need to understand what’s going on).
The goal here is to get this running as fast as possible. So, we are going to do this in 5 easy steps.
Step 1: Prep Your Machine (WSL + Docker)
If you already have WSL 2 and Docker Desktop installed, you can skip this part. If not, here’s the bare minimum to get going:
\=> Install WSL 2
Open PowerShell as Admin and run:
wsl --install
This installs Ubuntu and sets it to WSL 2 by default. Done.
\==> Install Docker Desktop
Grab it from docker.com. During setup, make sure you enable “Use WSL 2 based engine.”
\===> Connect Docker to WSL
In Docker Desktop settings:
Go to Settings > Resources > WSL Integration
Turn it ON for your Ubuntu distro.
wsl --install
, Windows Terminal will automatically add Ubuntu as a new shell option. You can open it anytime, just like you would PowerShell or Command Prompt — but this one is a full Linux environment running inside Windows. (On the terminal window, just click on the chevron).Quick test to verify that docker is installed:
docker --version
If you see the Docker version from inside WSL, you’re ready.
That’s it. No deep dive into Linux. No lectures about kernels. You now have a clean environment ready for containers.
Step 2: Create a Minimal C# Web API Project
Now that we have our environment ready, let’s make something real.
In your WSL shell or normal terminal - this will create a folder and solution in that folder so do this where you want this to happen:
dotnet new webapi -n DevContainerDemo
cd DevContainerDemo
code .
This spins up a simple ASP.NET Core Web API project and opens it in VS Code.
Done and dusted. It’s easy isn’t it?
Step 3: Add Dev Container Support
Here’s where the magic happens.
In VS Code:
Hit
Cmd+Shift+P
(orCtrl+Shift+P
on Windows)Make sure you see a
>
character in the top search box. If not, manually add it.Type: Dev Containers: Add Dev Container Configuration Files
Pick: C# (.NET)
Pick: .NET 8.0 (or whatever you’re targeting)
After asking a bunch of other questions (don’t worry most of them are self-explanatory and you can just breeze through them), you will see a little message on the bottom right:
Just click that button (not the Don’t Show Again
one). VSC will inform you that it is working but go ahead and click on that Show Log
link and watch magic happen.
When VSC is done, you will see that it created a .devcontainer
folder for you with some files in it, such as devcontainer.json
and a Dockerfile
.
Don’t worry about these files. You’ll barely touch them — VS Code handles most of the heavy lifting.
🚨Alarm: Things Did Not Go As Expected
You may run into an issue and VSC may tell you that it ran into a problem. If your error contains the following text;
Unable to find fallback package folder 'C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages'.
it means the language server (called Omnisharp) inside VS Code throws a fit trying to load your .csproj
project because it expects local Windows paths that don't exist inside your container. That path that starts with C:/Program Files…
does not exist in Linux.
So, let’s tell Omnisharp to relax and follow our instructions and everything is going to be alright:
- In your project workspace (root folder — next to your
.sln
file), create a file called: omnisharp.json and add this content to it:
{
"RoslynExtensionsOptions": {
"enableAnalyzersSupport": true,
"enableImportCompletion": true,
"locationPaths": []
},
"MSBuild": {
"LoadProjectsOnDemand": true,
"UseLegacySdkResolver": false
}
}
This will tell Omnisharp to run in standalone mode and not try to load a full Visual Studio MSBuild environment.
Let’s also update .devcontainer/devcontainer.json
and add (or uncomment - see below)postCreateCommand
like this:
"postCreateCommand": "dotnet restore"
Chances are you already have this line but it is commented out. Just uncomment it and do not forget to add a comma after the line before it as it can get confusing with all the comments in that file.
This is optional but just for good measure, let’s also force Omnisharp to run with the Linux SDK. Add this line to .vscode/settings.json
file (create the file if it does not exist):
{
"omnisharp.useModernNet": true
}
appsettings.json
— that's for your C# app itself, not for VS Code settings.Once you did all that, type this at the top in the text box in VSC:
>Dev Containers: Rebuild and Reopen in Container
Once you hit enter, VSC will rebuild the docker image if needed, restart the container, reload your project inside it and refresh Omnisharp and all the extensions inside the container.
Seems complicated, but in about 3 minutes, you will be done.
devcontainer
settings, always use "Dev Containers: Rebuild and Reopen in Container" to reload your project cleanly inside the updated container. No need to fully restart VS Code!Step 4: Open Inside the Dev Container
If you ran into a problem above (Omnisharp freaking out), you may skip this step as we already took care of this. If not, please read on.
In VS Code:
Hit
Cmd+Shift+P
Type: Dev Containers: Reopen in Container
VS Code will build the Docker image, create a container, install the right SDKs inside it and, reopen your project inside that container.
You’ll barely notice except your terminal prompt might change slightly (as it’s now running inside Linux like the screenshot below).
Step 5: Run Your App Inside the Container
Now let’s run our app. Run this command in your VSC terminal:
dotnet run
You should see VSC informing you that it is listening at some port. Make a note of that port and then visit this address on your browser
http://localhost:5000/weatherforecast
Boom!
Your C# app is running — inside a Docker container — inside WSL — without wrecking your machine.
Quick Recap
Let’s see what we have just done:
We ran Linux under Windows
We did not clone any SDKs
Nor did we install anything in Linux
We didn’t have to manage versions, global settings, weird environment paths
Yet, still our C# app built and ran, in Linux. We are running .NET inside a fresh, isolated Linux container -
not our host Windows, not WSL, not Docker Desktop directly - but inside a brand new Linux world spun up just for us by the Dev Container.
This is the experience we would have had, if this was an app developed by another developer and given to us. Now, think what we would have to do to make it run without a dev container. This is the real power of these dev containers. Our Windows environment is clean. Our Linux container is ready to rock.
Once you do it this way, you may not want to go back.
What's Next (Day 2)
Tomorrow, we’ll make it even better:
Customize the container
Add auto-restore commands
Install useful extensions
Set up proper debugging
Maybe even spin up a lightweight database
Because if you're going to containerize your dev environment, you might as well do it right.
End of Day 1
Yay, we survived. Let’s go grab a coffee or tea. ☕ 🎉
Subscribe to my newsletter
Read articles from TJ Gokken directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

TJ Gokken
TJ Gokken
TJ Gokken is an Enterprise AI/ML Integration Engineer with a passion for bridging the gap between technology and practical application. Specializing in .NET frameworks and machine learning, TJ helps software teams operationalize AI to drive innovation and efficiency. With over two decades of experience in programming and technology integration, he is a trusted advisor and thought leader in the AI community