https://devblogs.microsoft.com/dotnet/announcing-builtin-container-support-for-the-dotnet-sdk/
Skip to main content
[RE1Mu3b] Microsoft
.NET Blog
.NET Blog
.NET Blog
* Home
* DevBlogs
* Developer
+ Visual Studio
+ Visual Studio Code
+ Visual Studio for Mac
+ DevOps
+ Developer support
+ CSE Developer
+ Engineering@Microsoft
+ Azure SDK
+ IoT
+ Command Line
+ Perf and Diagnostics
+ Dr. International
+ Notification Hubs
+ Math in Office
* Technology
+ DirectX
+ PIX
+ SurfaceDuo
+ Startups
+ Sustainable Engineering
+ Windows AI Platform
* Languages
+ C++
+ C#
+ F#
+ Visual Basic
+ TypeScript
+ PowerShell Community
+ PowerShell Team
+ Python
+ Q#
+ JavaScript
+ Java
+ Java Blog in Chinese
* .NET
+ .NET
+ .NET MAUI
+ Blazor
+ ASP.NET
+ NuGet
+ Xamarin
* Platform Development
+ #ifdef Windows
+ Apps for Windows
+ Azure Depth Platform
+ Azure Government
+ Bing Dev Center
+ Microsoft Edge Dev
+ Microsoft Azure
+ Microsoft 365 Developer
+ Old New Thing
+ Windows MIDI and Music dev
+ Windows Search Platform
* Data Development
+ Azure Cosmos DB
+ Azure Data Studio
+ Azure SQL Database
+ OData
+ Revolutions R
+ SQL Server Data Tools
* More
[ ] Search Search
Cancel
Announcing built-in container support for the .NET SDK
[png]
Chet Husk
August 25th, 202221 6
Containers have become one of the easiest ways to distribute and run
a wide suite of applications and services in the cloud. The .NET
Runtime was hardened for containers years ago. You can now create
containerized versions of your applications with just dotnet publish.
Container images are now a supported output type of the .NET SDK.
TL;DR
Before we go into the details of how this works, I want to show what
a zero-to-running containerized ASP.NET Core application looks like:
# create a new project and move to its directory
dotnet new mvc -n my-awesome-container-app
cd my-awesome-container-app
# add a reference to a (temporary) package that creates the container
dotnet add package Microsoft.NET.Build.Containers
# publish your project for linux-x64
dotnet publish --os linux --arch x64 -p:PublishProfile=DefaultContainer
# run your app using the new container
docker run -it --rm -p 5010:80 my-awesome-container-app:1.0.0
Now you can go to http://localhost:5010 and you should see the sample
MVC application, rendered in all its glory.
For this release, you must have Docker installed and running for this
sample to work. Additionally, only Linux-x64 containers are
supported.
Motivation
Containers are an excellent way to bundle and ship applications. A
popular way to build container images is through a Dockerfile - a
special file that describes how to create and configure a container
image. Let's look at one of our samples for an ASP.NET Core
application's Dockerfile here:
# https://hub.docker.com/_/microsoft-dotnet
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /source
# copy csproj and restore as distinct layers
COPY aspnetapp/*.csproj .
RUN dotnet restore --use-current-runtime
# copy everything else and build app
COPY aspnetapp/. .
RUN dotnet publish -c Release -o /app --use-current-runtime --self-contained false --no-restore
# final stage/image
FROM mcr.microsoft.com/dotnet/aspnet:7.0
WORKDIR /app
COPY --from=build /app .
ENTRYPOINT ["dotnet", "aspnetapp.dll"]
This project uses a multi-stage build to both build and run the app.
It uses the 7.0 SDK image to restore the application's dependencies,
publish the application to a folder, and finally create the final
runtime image from that directory.
This Dockerfile works very well, but there are a few caveats to it
that aren't immediately apparent, which arise from the concept of a
Docker build context. The build context is a the set of files that
are accessible inside of a Dockerfile, and is often (though not
always) the same directory as the Dockerfile. If you have a
Dockerfile located beside your project file, but your project file is
underneath a solution root, it's very easy for your Docker build
context to not include configuration files like
Directory.Packages.props or NuGet.config that would be included in a
regular dotnet build. You would have this same situation with any
hierarchical configuration model, like EditorConfig or
repository-local git configurations.
This mismatch between the explicitly-defined Docker build context and
the .NET build process was one of the driving motivators for this
feature. All of the information required to build an image is present
in a standard dotnet build, we just needed to figure out the right
way to represent that data in a way that container runtimes like
Docker could use.
How does it work
A container image is made of two primary parts: some JSON
configuration containing metadata about how the image can be run, and
a list of tarball archives that represent the file system. In .NET 7,
we added several APIs to the .NET Runtime for handling TAR files and
streams, and that opened the door to manipulating container images
programmatically.
This approach has been demonstrated very successfully in projects
like Jib in the Java ecosystem, Ko for Go, and even in .NET with
projects like konet. It's obvious that a simple tool-driven approach
to generate container images is becoming more popular.
We built the .NET SDK solution with the following goals:
* Provide seamless integration with existing build logic, to
prevent the kinds of context gaps mentioned earlier
* Implement in C#, to take advantage of our own tool and benefit
from .NET runtime performance improvements
* Integrated into the .NET SDK, so that it is straightforward for
the .NET team to improve and service in the existing .NET SDK
processes
Customization
Those of you with experience writing Dockerfiles are probably
wondering where all of the complexity of the Dockerfile has gone.
Where is the FROM base image declared? What tags are used? Many
aspects of the generated image are customizable by you through the
use of MSBuild properties and items (you can read about that in
detail at the documentation), but we've shipped a few defaults to
make getting started easier.
Base Image
The base image defines which functionality you will have available
and which OS and version you will be using. The following base images
are automatically chosen:
* for ASP.NET Core apps, mcr.microsoft.com/dotnet/aspnet
* for self-contained apps, mcr.microsoft.com/dotnet/runtime-deps
* for all other apps, mcr.microsoft.com/dotnet/runtime
In all cases, the tag used for the base image is the version portion
of the TargetFramework that has been chosen for the application - for
example, a TargetFramework of net7.0 would result in a tag of 7.0
being used. These simple-version tags are based on Debian
distributions of linux - if you want to use a different supported
distro like Alpine or Ubuntu then you would need to manually specify
that tag (see the ContainerBaseImage example below).
We think that the choice of defaulting to the Debian-based versions
of the runtime images is the best choice for broad compatibility with
most applications' needs. Of course, you are free to choose any base
image for your containers. Simply set the ContainerBaseImage property
to any image name and we'll do the rest. For example, maybe you want
to run your web application on Alpine Linux. That would look like
this:
mcr.microsoft.com/dotnet/aspnet:7.0-alpine
Image name and version
The name of your image will be based on the AssemblyName of your
project by default. If that's not a good fit for you, the name of the
image can be explicitly set by using the ContainerImageName property.
An image also needs a tag, so we default to the value of the Version
property. This defaults to 1.0.0, but you are free to customize this
in any way and we'll make use of it. This fits especially well with
automated versioning schemes like GitVersioning, where the version is
derived from some configuration data in the repository. This helps
ensure that you always have a unique version of your application to
run. Unique version tags are especially important for images, because
pushing an image with the same tag to a registry will overwrite the
image that was previously stored as that tag.
Everything else
Many other properties can be set on an image, like custom
Entrypoints, Environment Variables, and even arbitrary Labels (which
are often used for tracking metadata like SDK version, or who built
the image). In addition, images are often pushed to destination
registries by specifying a different base registry. In subsequent
versions of the .NET SDK we plan to add support for these
capabilities in a similar manner as described above - all controlled
through MSBuild project properties.
When should you use this
Local development
If you need a container for local development, now you can have one
with a single command. dotnet publish --os linux --arch x64
-p:PublishProfile=DefaultContainer will make a Debug-configuration
container image named after your project. Some users have made this
even simpler by putting these properties into a Directory.Build.props
and simply running dotnet publish:
linux-x64
DefaultContainer
You could also use other SDK and MSBuild features like response files
or PublishProfiles to create groups of these properties for easier
use.
CI Pipelines
Overall, building container images with the SDK should integrate
seamlessly into your existing build processes. A sample of a minimal
GitHub Actions workflow to containerize an app is just about 30 lines
of configuration:
name: Containerize ASP.NET Core application
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup .NET SDK
uses: actions/setup-dotnet@v2
# Package the app into a linux-x64 container based on the dotnet/aspnet image
- name: Publish
run: dotnet publish --os linux --arch x64 --configuration Release -p:PublishProfile=DefaultContainer
# Because we don't yet support pushing to authenticated registries, we have to use docker to
# login, tag and push the image. In the future none of these steps will be required!
# 1. Login to our registry so we can push the image. Could use a raw docker command as well.
- name: Docker Login
uses: actions-hub/docker/login@master
env:
DOCKER_REGISTRY_URL: sdkcontainerdemo.azurecr.io
DOCKER_USERNAME: ${{ secrets.ACR_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.ACR_PAT }}
# 2. Use the tag command to rename the local container to match our Azure Container Registry URL
- name: Tag built container with Azure Container Registry url
uses: actions-hub/docker/cli@master
with:
args: tag sdk-container-demo:1.0.0 sdkcontainerdemo.azurecr.io/baronfel/sdk-container-demo:latest
# 3. Push the renamed container to ACR.
- name: Push built container to Azure Container Registry
uses: actions-hub/docker/cli@master
with:
args: push sdkcontainerdemo.azurecr.io/baronfel/sdk-container-demo:latest
This is part of an example repo called baronfel/sdk-container-demo
made to demonstrate this end-to-end process.
There is one major scenario that we won't be able to handle at all
with SDK-built containers, though.
RUN commands
There's no way of performing RUN commands with the .NET SDK. These
commands are often used to install some OS packages or create a new
OS user, or any number of arbitrary things. If you would like to keep
using the SDK container building feature, you can instead create a
custom base image with these changes and then using this base image
as the ContainerBaseImage as described above.
As an example, let's say I'm working on a library that needs the
libxml2 library installed on the host in order to do some custom XML
processing. I could write a Dockerfile like this to capture this
native dependency:
FROM mcr.microsoft.com/dotnet/runtime:7.0
RUN apt-get update && \
apt-get install -y libxml2 && \
rm -rf /var/lib/apt/lists/*
Now, I can build, tag, and push this image to my registry and use it
as a base for my application:
docker build -f Dockerfile . -t registry.contoso.com/my-base-image:1.0.0
docker push registry.contoso.com/my-base-image:1.0.0
In the project file of my application I'd set the ContainerBaseImage
property to this new image:
...
registry.contoso.com/my-base-image:1.0.0
...
Temporary gaps
This is the initial preview of SDK-built container images, so there
are some features that we haven't yet been able to deliver.
Windows images and non-x64 architectures
We have focused on the Linux-x64 image deployment scenario for this
initial release. Windows images and other architectures are key
scenarios we plan to support for the full release, so watch out for
new developments there.
Pushing to remote registries
We have not yet implemented support for authentication, which is
critical for many users. This is one of our highest priority items.
In the interim, we suggest pushing to your local Docker daemon, then
using docker tag and docker push to push the generated images to your
destination. The sample GitHub Action above shows how this can be
done.
Some image customization
Several image metadata customizations have not been implemented yet.
This includes custom Entrypoints, environment variables, and custom
user/group information. A full list can be seen on dotnet/
sdk-container-builds.
Next Steps
Over the release candidate phases of the .NET 7 release we will be
adding new image metadata, support for pushing images to remote
registries, and support for Windows images. You can track that
progress at the milestone we've created for this.
We also plan on integrating this work directly into the SDK
throughout the release. When that happens, we'll be releasing a
'final' version of the package on NuGet that will warn you of the
change, and ask you to remove the Package entirely from your project.
If you are interested in cutting-edge builds of the tool, we also
have a GitHub package feed where you can opt into trying the latest
work.
If you encounter issues using the SDK container image builder, let us
know and we'll do our best to help you out.
Closing thoughts
We would love for those of you building Linux containers to try
building them with the .NET SDK. I've personally had a blast trying
them out locally - I had a good time going to some of my demo
repositories and containerizing them with a single command, and I
hope you all feel the same!
Happy image building!
[png]
Chet Husk Program Manager, .NET Tools Team
Follow
Posted in .NET .NET Core ASP.NET Core Containers Docker
Read next
.NET MAUI eBook Now Available - Enterprise Application Patterns
Looking to get started with .NET MAUI and need architecture guidance?
The new free .NET MAUI eBook on enterprise application patterns is
now available.
[png]Michael Stonis
August 25, 2022
2 comments
.NET Framework August 2022 Cumulative Update Preview Updates
August 2022 Cumulative Update Preview Updates for .NET Framework.
[png]Salini Agarwal
August 26, 2022
0 comment
21 comments
Leave a commentCancel reply
Log in to join the discussion.
* [png]
William Liu August 25, 2022 5:04 pm
collapse this comment
Does the sample at the beginning of the article require .net 7
SDK, right?
Log in to Reply
+ [png]
Chet HuskMicrosoft employee August 25, 2022 5:35 pm
collapse this comment
That's right - specifically it requires .NET 7 preview 7 or
greater.
Log in to Reply
* [png]
Dan Friedman August 25, 2022 5:05 pm
collapse this comment
Nice work. Thanks for always simplifying things for us.
Log in to Reply
+ [png]
Chet HuskMicrosoft employee August 26, 2022 6:50 am
collapse this comment
That's what we're here for! Have you had a chance to give
container builds a try?
Log in to Reply
* [png]
Amit E August 25, 2022 8:29 pm
collapse this comment
This is a great addition and should greatly simplify
containerization in some scerios. I hope to see an even deeper
integration, maybe by adding a dedicated command (dotnet
container?) or parameter (dotnet publish -container?) and reduce
the need to use more obscure switches (specifically
-p:PublishProfile=DefaultContainer).
Would also be great to have a simple way to generate the
dockerfile that will generate the same image that the publish
command creates.
Log in to Reply
+ [png]
Chet HuskMicrosoft employee August 25, 2022 8:51 pm
collapse this comment
I completely agree! I logged a dotnet/sdk issue a while back
about making Publish Profiles feel more first-class (in a way
that doesn't compromise the overall generic nature of the
.NET CLI): https://github.com/dotnet/sdk/issues/26161 Any
feedback you have on that would be very welcome.
Log in to Reply
o [png]
Amit E August 26, 2022 8:51 am
collapse this comment
So assuming the publish profile is named "container":
dotnet publish --profile container
That would definitely be an improvement.
Log in to Reply
* [png]
Diego Bonura August 25, 2022 11:53 pm
collapse this comment
So cool! what about ARM images support?
Log in to Reply
+ [png]
Chet HuskMicrosoft employee August 26, 2022 6:47 am
collapse this comment
It's on the roadmap - check out https://github.com/dotnet/
sdk-container-builds/issues/91 for more details, but it
should be relatively straightforward to do. Once it's done,
supplying a Runtime Identifier (either via the --runtime/-r
CLI option or the RuntimeIdentifier MSBuild property) with an
architecture of arm64 would cause us to choose the
appropriate arm architecture if the chosen image supports it.
All of the Microsoft-provided .NET base images listed in the
article do support ARM so it should all line up.
Log in to Reply
* [png]
Howard van Rooijen August 26, 2022 12:55 am
collapse this comment
Great work. Really looking forward to integrating this into our
CI/CD pipelines.
Log in to Reply
+ [png]
Chet HuskMicrosoft employee August 26, 2022 6:49 am
collapse this comment
Thanks Howard - I'm looking forward to hearing from you and
your team about how it works for you.
Log in to Reply
* [png]
Shawn Stoddard August 26, 2022 8:24 am
collapse this comment
Any thoughts about support software other than Docker - say
PodMan for example?
Log in to Reply
+ [png]
Chet HuskMicrosoft employee August 26, 2022 9:00 am
collapse this comment
We definitely want to support alternative container engines
like podman. I just tested our support with podman-machine on
Windows and I was able to push my image and run it, though I
did have to use Docker CLI commands that transparently used
my podman machine. The podman-specific commands didn't run,
so I'll raise an issue on the repo about investigating that
specifically - as a goal podman run, podman list, and all
other podman commands should work just as well as docker
commands.
Log in to Reply
o [png]
Chet Husk August 27, 2022 7:09 am
collapse this comment
Following up here - podman actually works seamlessly,
it's just you have to be very aware of if you're running
podman machine on Windows in rootless mode or not, since
those modes change the storage location of the loaded
container images.
Log in to Reply
* [png]
nazar554 August 26, 2022 8:29 am
collapse this comment
Does this work with packages.lock.json and -locked-mode ?
Also it would be great if SDK could use it to generate a software
bills of materials (SBOM)
Log in to Reply
+ [png]
Chet HuskMicrosoft employee August 26, 2022 9:06 am
collapse this comment
There are some pain points with packages.lock.json and
publish, especially with runtime identifiers. This is because
publish uses restore to acquire runtime-specific assets that
aren't part of a normal restore. There's an issue over at the
NuGet/Home repository that goes into the details and some
workarounds, but we don't have a solid set of guidance yet on
how these features should be integrated.
Log in to Reply
* [png]
Mark Stega August 26, 2022 2:06 pm
collapse this comment
This looks to be a very useful addition to the SDK
About the article:
1) It would be nice to describe why the CI script uses
actions-hub/docker/login & cli rather than just using docker
commands
2) What does having the 'dotnet build' accomplish that isn't done
in the subsequent 'dotnet publish' step?
3) Why does the build have those 2 environment vars declared?
About using the feature:
I added this publish step to my github actions: 'dotnet publish
ICEBG.Web.DataServices/ICEBG.Web.DataServices.csproj -os linux
-arch x64 -configuration Azure -p:PublishProfile=DefaultContainer
-p:Version=2022-08-26-21-29-29-WIP'. I do not seem to have an
image with the tag I expected. After doing the publish I execute
a 'docker images -a' command. I don't see an image with the
expected tag. I see either 6 images as in:
REPOSITORY TAG IMAGE ID CREATED SIZE
229416 6e1367aa97844c89b4a25a987bf5a0ba 9aa1a65ab488 28 seconds ago 220MB
47cde3a84d9e 29 seconds ago 220MB
4f0b4b1fe90b 29 seconds ago 220MB
229416 575ed5c505ea4307943e45d0e6d6c104 f81699aabf05 31 seconds ago 220MB
e4b930a957ba 32 seconds ago 220MB
f8ccc4a1f9be 32 seconds ago 220MB
node 16 bfb7b2a05614 9 days ago 910MB
node 16-alpine 5dcd1f6157bd 9 days ago 115MB
node 14-alpine d12c0eadaee1 2 weeks ago 119MB
alpine 3.13 6b5c5e00213a 2 weeks ago 5.62MB
alpine 3.14 dd53f409bf0b 2 weeks ago 5.6MB
node 14 52e5cabe9b9c 3 weeks ago 914MB
buildpack-deps buster c75e17448eed 3 weeks ago 804MB
buildpack-deps bullseye 810420bc6608 3 weeks ago 835MB
ubuntu 20.04 3bc6e9f30f51 3 weeks ago 72.8MB
ubuntu 18.04 8d5df41c547b 3 weeks ago 63.1MB
debian 10 d4729731066b 3 weeks ago 114MB
debian 11 07d9246c53a6 3 weeks ago 124MB
buildpack-deps stretch 9d4f40bcbdd3 2 months ago 835MB
debian 9 662c05203bab 2 months ago 101MB
moby/buildkit latest a2c9241854f2 3 months ago 142MB
node 12 6c8de432fc7f 4 months ago 918MB
node 12-alpine bb6d28039b8c 4 months ago 91MB
alpine 3.12 24c8ece58a1a 4 months ago 5.58MB
ubuntu 16.04 b6f507652425 12 months ago 135MB
docker stable b0757c55a1fd 21 months ago 220MB
or 3 images as in
REPOSITORY TAG IMAGE ID CREATED SIZE
229416 c5540378845c43989cfd8b4dd78757c4 ed0a482e5e09 32 seconds ago 220MB
931a6389bed0 33 seconds ago 220MB
f2ec7d74725e 33 seconds ago 220MB
Log in to Reply
+ [png]
Chet HuskMicrosoft employee August 26, 2022 3:06 pm
collapse this comment
Hi Mark, thanks for your feedback.
I'll address your points here and then look at what edits I
should make to the blogpost.
1) Since authentication isn't solved by the new feature yet,
in order to actually push to Azure we need to login via the
Docker CLI. Then later, to actually take our image from the
local Docker daemon to Azure Container Registry we use docker
tag to rename the local image to match the destination
registry and docker push to push the image to the registry.
Both of these docker commands will not be necessary in a
future release, the publish command itself will handle
pushing to the registry.
2) In this case nothing, I can probably delete it entirely to
avoid confusion.
3) I'm assuming you mean the GITHUB_USERNAME and GITHUB_TOKEN
environment variables? Those are because this sample was
written before the package was pushed to NuGet.org, so I was
getting the package from a GitHub Packages feed, and those
variables were part of the authentication to that feed. Now
that the package is available on NuGet.org I can remove them
entirely from both the sample project and this post.
Finally, I'd love to help dig into why no container was built
in your case. There are two primary causes I can immediately
think of: the first is that you may not be on the correct
version of the .NET SDK. You'll need 7.0.100-preview.7 or
greater. The second is that your project (despite the name)
isn't a Web project (meaning a project with the
Microsoft.NET.Sdk.Web SDK in its project file). We currently
don't have PublishProfile support for non-web projects,
though we do plan to have it in a future release. See https:/
/github.com/dotnet/sdk-container-builds/issues/141 for
details there. In the meantime, if you do have a non-web
project, you can publish the container directly by adding /
p:PublishContainer to your dotnet publish command.
If neither of these is the case, I invite you to open an
issue at the parent repository and we can talk about getting
a binlog to help dig into the problem. Thanks!
Log in to Reply
o [png]
Mark Stega August 27, 2022 6:28 am
collapse this comment
Chet,
Nice cleanup, much easier to follow in the current form.
I definitely have a web project using
Microsoft.Net.Sdk.Web but I messed up my global.json
file. After fixing that, the issue becomes clear: You
have an argument on the dotnet publish line of '
-p:PublishProfile=DefaultContainer' and that profile is
not part of the repository. My dotnet publish results in
/home/runner/.dotnet/sdk/7.0.100-preview.7.22377.5/Sdks/Microsoft.NET.Sdk.Publish/targets/DotNetCLIToolTargets/Microsoft.NET.Sdk.DotNetCLITool.targets(104,11): error MSB4057: The target "PublishContainer" does not exist in the project. [/home/runner/work/ICEBG/ICEBG/ICEBG.Web.DataServices/ICEBG.Web.DataServices.csproj]
which is an interesting error since I don't reference
'PublishContainer'
My publish command is:
- name: Publish, tag, and push DS image
uses: actions-hub/docker/login@master
env:
DOCKER_REGISTRY_URL: ${{ secrets.REGISTRY_LOGIN_SERVER }}
DOCKER_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
- run: |
dotnet --info
sudo docker images -a
dotnet publish ICEBG.Web.DataServices/ICEBG.Web.DataServices.csproj --os linux --arch x64 --configuration Azure -p:PublishProfile=DefaultContainer -p:Version=${{ needs.version.outputs.suffix }}
sudo docker images -a
The expanded version of the publish command shows as:
dotnet publish ICEBG.Web.DataServices/ICEBG.Web.DataServices.csproj --os linux --arch x64 --configuration Azure -p:PublishProfile=DefaultContainer -p:Version=2022-08-27--13-11-46--WIP
Log in to Reply
# [png]
Chet Husk August 27, 2022 7:12 am
collapse this comment
One of the parts of this feature was providing that
default PublishProfile in the SDK itself, much in the
same way that the existing default publish profiles
are shipped. So if you're running on preview 7 or
greater you should have that profile as part of your
SDK. The specific error shown here is what I would
expect if you didn't have the
Microsoft.Net.Build.Containers package added to your
project - it provides the implementation of the
target listed in the error. Can you check your
package references and make sure that package is
available?
Log in to Reply
@ [png]
Mark Stega August 27, 2022 8:10 am
collapse this comment
Chet,
Thanks, you absolutely nailed the issue. I had
totally forgotten to add the package.
Is it expected to have multiple images created on
the publish step?
From 'docker images -a':
REPOSITORY TAG IMAGE ID CREATED SIZE
icebg.web.dataservices 2022-08-27--15-06-14--WIP e76e909e7988 9 seconds ago 230MB
229416 9682efcb28a740f3ae9c822d45451f9a 9256ae07657a 44 seconds ago 220MB
none none e9ce4e2a4360 45 seconds ago 220MB
none none 0609c5b67892 45 seconds ago 220MB
Relevant Links
.NET Download
.NET Hello World
.NET Meetup Events
.NET Documentation
.NET API Browser
.NET SDKs
.NET Application Architecture Guides
Web apps with ASP.NET Core
Mobile apps with Xamarin.Forms
Microservices with Docker Containers
Modernizing existing .NET apps to the cloud
Archive
August 2022
July 2022
June 2022
May 2022
April 2022
March 2022
February 2022
January 2022
December 2021
November 2021
October 2021
September 2021
August 2021
July 2021
June 2021
May 2021
April 2021
March 2021
February 2021
January 2021
December 2020
November 2020
October 2020
September 2020
August 2020
July 2020
June 2020
May 2020
April 2020
March 2020
February 2020
January 2020
December 2019
November 2019
October 2019
September 2019
August 2019
July 2019
June 2019
May 2019
April 2019
March 2019
February 2019
January 2019
December 2018
November 2018
October 2018
September 2018
August 2018
July 2018
June 2018
May 2018
April 2018
March 2018
February 2018
January 2018
December 2017
November 2017
October 2017
September 2017
August 2017
July 2017
June 2017
May 2017
April 2017
March 2017
February 2017
January 2017
December 2016
November 2016
October 2016
September 2016
August 2016
July 2016
June 2016
May 2016
April 2016
March 2016
February 2016
January 2016
December 2015
November 2015
October 2015
September 2015
August 2015
July 2015
June 2015
May 2015
April 2015
March 2015
February 2015
January 2015
December 2014
November 2014
October 2014
September 2014
August 2014
July 2014
June 2014
May 2014
April 2014
March 2014
February 2014
January 2014
December 2013
November 2013
October 2013
September 2013
August 2013
July 2013
June 2013
May 2013
April 2013
March 2013
February 2013
January 2013
December 2012
November 2012
October 2012
September 2012
August 2012
July 2012
June 2012
May 2012
April 2012
March 2012
February 2012
January 2012
October 2011
September 2011
August 2011
June 2011
April 2011
March 2011
February 2011
January 2011
December 2010
November 2010
October 2010
September 2010
August 2010
July 2010
June 2010
May 2010
April 2010
March 2010
February 2010
December 2009
November 2009
October 2009
September 2009
August 2009
July 2009
June 2009
May 2009
April 2009
March 2009
February 2009
January 2009
December 2008
November 2008
October 2008
September 2008
August 2008
July 2008
June 2008
May 2008
April 2008
March 2008
February 2008
January 2008
December 2007
November 2007
October 2007
September 2007
August 2007
July 2007
June 2007
May 2007
April 2007
March 2007
February 2007
January 2007
December 2006
November 2006
October 2006
September 2006
August 2006
July 2006
June 2006
May 2006
April 2006
March 2006
February 2006
January 2006
October 2005
July 2005
May 2005
December 2004
November 2004
September 2004
June 2004
Topics
.NET
ASP.NET
.NET Core
ASP.NET Core
.NET Framework
Blazor
Entity Framework
C#
Azure
Visual Studio
WPF
.NET MAUI
ML.NET
Performance
Machine Learning
F#
WinForms
Maintenance & Updates
AI Machine Learning
.NET Internals
Containers
Security
SignalR
Community Standup
Conversations
Developer Stories
Cloud
WCF
Game Development
Show dotnet
Debugging
Lifecycle
Networking
Docker
WebHooks
GitHub Actions
gRPC
XAML
Maoni
Async
Concurrency
GC
TPL
Visual Basic
Featured
Apache
Big Data
Spark for .NET
Static Analysis
Orchard Core
SQL Server
JSON
IoT
LOH
Stay informed
Login
Insert/edit link
Close
Enter the destination URL
URL [ ]
Link Text [ ]
[ ] Open link in a new tab
Or link to existing content
Search [ ]
No search term specified. Showing recent items. Search or use up and
down arrow keys to select an item.
Cancel
[Add Link]
Code Block
x
Paste your code snippet [ ]
Cancel Ok
Feedback usabilla icon
What's new
* Surface Laptop Go 2
* Surface Pro 8
* Surface Laptop Studio
* Surface Pro X
* Surface Go 3
* Surface Duo 2
* Surface Pro 7+
* Windows 11 apps
Microsoft Store
* Account profile
* Download Center
* Microsoft Store support
* Returns
* Order tracking
* Virtual workshops and training
* Microsoft Store Promise
* Flexible Payments
Education
* Microsoft in education
* Devices for education
* Microsoft Teams for Education
* Microsoft 365 Education
* Education consultation appointment
* Educator training and development
* Deals for students and parents
* Azure for students
Business
* Microsoft Cloud
* Microsoft Security
* Dynamics 365
* Microsoft 365
* Microsoft Power Platform
* Microsoft Teams
* Microsoft Industry
* Small Business
Developer & IT
* Azure
* Developer Center
* Documentation
* Microsoft Learn
* Microsoft Tech Community
* Azure Marketplace
* AppSource
* Visual Studio
Company
* Careers
* About Microsoft
* Company news
* Privacy at Microsoft
* Investors
* Diversity and inclusion
* Accessibility
* Sustainability
* Sitemap
* Contact Microsoft
* Privacy
* Manage cookies
* Terms of use
* Trademarks
* Safety & eco
* About our ads
* (c) Microsoft 2022
Theme
* light-theme-iconLight
* dark-theme-iconDark