Deploying .NET apps to containers on AWS

By Julie Lerman

As a .NET developer, you may not be aware of the commitment that AWS has made to .NET, including developer advocates, specialized APIs for your .NET apps to easily work with AWS services, and even some great tooling for our IDEs. The AWS Toolkit for Visual Studio provides interaction with a slew of AWS services, while the AWS toolkits for Visual Studio Code and JetBrains Rider focus their tooling on serverless features. With this toolkit, you can easily deploy .NET apps to fully managed containers on AWS without leaving Visual Studio.

AWS has a number of ways to run and manage containers, including Elastic Container Repository (or ECR, a service for storing Docker images) and containers orchestrators Elastic Kubernetes Service (EKS) and the proprietary Elastic Container Service (ECS), both of which integrate with ECR.

But if you don’t want to have to think about how those orchestrators work, then AWS Fargate is the service for you. You provide some configuration info and it takes care of pushing images, spinning up containers, creating load balancers and managing container instances for your apps. It’s a really simple way to get your workload up and running.

In this article, you’ll learn how to use the AWS Toolkit for Visual Studio to publish a simple ASP.NET Core application to Fargate. I’ll start with an ASP.NET Core Web application from a template and add a little bit of text output to the default page. Then we’ll deploy it to Fargate using the toolkit and take a look at the application running in a pair of containers on AWS.


Although .NET 5, ASP.NET Core 5 and EF Core 5 are around the corner (or possibly here, by the time you read this article), I’ll use Visual Studio 2019 and the 3.1 versions of these frameworks. 

You will also need Docker Desktop installed and running on your computer, and it should be set to use Linux containers, which is the default. 

Your Visual Studio installation should have the Container Development Tools component installed as part of the .NET Core cross-platform development workload.

You also need to install the AWS Toolkit for Visual Studio. You can find that in the extensions manager in Visual Studio or download it here. With the toolkit installed, if you do not yet have an account on AWS, you can create a free account here, then the toolkit will guide you to set up a user role and associate the toolkit with that role. This will give the toolkit permission to perform your developer tasks on AWS. You can find a detailed walkthrough of this in writing in my Code Magazine article, or if you prefer video, in my Pluralsight course “Fundamentals of Building .NET Applications on AWS.

Step 1: Creating the ASP.NET Core application

First, we’ll start by creating a new  ASP.NET Core Web Application project in Visual Studio. Mine is named ChocolateEatersAnon.

Next, you need to choose what type of web app you want. Be sure that the top dropdowns have .NET Core and ASP.NET Core 3.1 selected, then choose Web Application. Leave the default “Configure for HTTPS” and “Enable Docker Support” checked, and click Create to complete the project creation.

The template will create a simple web application with two pages: index and privacy.  Because we enabled Docker support, there is a dockerfile which provides instructions to Docker about how to build a Docker image from your code and the ASP.NET Core runtime.

Step 2: Adding a bit of intelligence to the web site

Let’s make a tweak to the Welcome page. A Razor page is composed from a cshtml file and a cs file. The Welcome page is driven by index.cshtml and index.cs. The class name in the index.cs file is IndexModel.

We’ll add a message property to IndexModel and display it on the page, then add a public string property called Message, then modify the OnGet method to set the value of the Message property.

Here is the class after I’ve added this code:

namespace ChocolateEaters.Pages
  public class IndexModel : PageModel
    private readonly ILogger<IndexModel> _logger; 
    public string Message { get; set; }  

    public IndexModel(ILogger<IndexModel> logger)
      _logger = logger;

    public void OnGet()
      Message= $"It's {DateTime.Now}! Time for some chocolate!";

In index.cshtml, I’ve added some simple code to display the message in red text which I placed right above the “Learn about building” paragraph.

<span style="color:red">@Html.DisplayFor(model => model.Message)

Now when you run the app, you can see the message on the welcome page, and it will update every time you refresh the page. In addition to the usual options of debugging in IIS or Kestrel, you can also debug locally in Docker. The VS Container tools manage everything for this and the only difference you’ll notice is the local port to which the container sends its output.


Step 3: Deploying as Docker containers in the cloud

Now that the application has this brilliant logic, it’s time to deploy it to AWS Fargate as Docker containers—and yes, that’s plural; even with a tiny application, it’s always good to have at least one extra instance of the container running in case something causes a problem with a container. Fargate will automatically switch over to a working container, and nobody will know the difference.

The AWS Toolkit lets you publish apps from either the project’s context menu or from the Project menu in the toolbar. Either way, you need to choose the option “Publish Container to AWS…”, which is available when there is a dockerfile in the project.

This will open a wizard with five pages of configuration. Some of the details are pre-populated and will suffice for our demo, while others need a little tweaking. Overall, however, even on my first time through, I did not find it complicated nor requiring any DevOps expertise to tweak. Once you are familiar with what’s on each page, setting up the configuration on a subsequent deployment should be a breeze.

I’ll walk you through the pages quickly to get you up and running. (For a detailed explanation of what all the options are for, see my Pluralsight course mentioned in the Requirements section of this article.)

Step 4: Define where to publish the application

The defaults on the first page are correct. Permission to publish comes from your AWS toolkit profile and everything will be created in the selected region. Docker Image Build specifies which type of build you want and the name for the image that will get stored in the AWS repository (ECR).  Deployment Target is set to run as a service on an ECS cluster, the correct option for long-running applications like this website.

publish container to was

Step 5: Setting up the Launch Configuration page

Choose “Create a New Cluster” and provide a name for the ECS cluster where your service will run. Because we are creating a new ECS cluster, the launch type is already set to Fargate. Everything else should be correct, but I’ll explain them anyway:

  • The defaults for Allocated Compute Capacity (.25 vCPU and 512MB memory) are sufficient for the demo and supported by the free tier.

  • Network Configuration lets you specify the subnets and security group of the VPC that will host your Fargate service. A VPC (Virtual Private Cloud) is an isolated virtual network on AWS. The default setting is to use your account’s default VPC. 

  • A subnet is a subset of that VPC network, and any access to a VPC must go through two or more of its subnets. By default, the wizard selected all three subnets from the default VPC.

A security group is the firewall that protects your VPC. The default security group of the VPC was selected by the wizard. You can read more about VPC security groups here.

launch configuration

Step 6: Setting up the Service Configuration page

The settings on this next page default to creating a new service and giving it the name of the project.

A task is responsible for running a single Docker container within the service. I like to have a minimum of two containers, even for a small demo; if one fails, Fargate will automatically flip to the other. This is the only change you need to make.

Fargate uses the Minimum and Maximum Percent threshold to determine how many of its containers should be running at any given time. Leave those at their defaults.

service configuration

Step 7: Setting up the Application Load Balancer Configuration page

The two key tasks of the application load balancer are to act as a single point of contact gateway to the running containers and to make sure the appropriate number of containers are always running and available. It’s a good idea to have a load balancer for your web application so you don’t have to worry about availability.

Check the first checkbox to configure a load balancer. With that checked, the other options become active. Select Create New on the Load Balancer dropdown. This will auto-populate all the rest of the options creating the additional resources that your new load balancer requires, and using the project name where a name is required.

application load balancer configuration

Step 8: Defining the application tasks

The last configuration page is to create a task definition. A task definition describes the parameters for each container that Fargate will run for your application. 

Start by selecting Create New from the Task Definition dropdown. This will also auto-populate the name of the task definition and specify that that the task should create new containers.

The task uses an IAM role to access other services. Open the drop down and choose PowerUserAccess from the “New Role Based on AWS Managed User Policy.” This is an acceptable option for our demo, but keep in mind that it is overkill for this use case. For your real applications, you’ll need to be more selective about the permissions granted to the role you create.

Task execution role will let Fargate pull Docker images from ECR to create the containers. Choose Create New and the appropriate role will be created for you.

The port mapping (80) and ASP.NET Core Environment variable defaults are correct.

task definition

Hooray: It’s time to click the Publish button!

This will trigger Docker to build the images locally. Once the images are created, the toolkit will push these images up to AWS ECR, and then Fargate will create all of the needed resources based on your configurations. When everything is set up, then Fargate will use the task definition to run two containers from the image that was pushed to ECR.

The wizard will leave a window open to share the status of the deployment with you. When everything is ready, the status should show two running Fargate tasks, and the URL of the app will be available as a link.


The app is up and running, and more importantly,  I can see that it is once again time to eat some more chocolate.

time to eat chocolate

Next steps

This article provided a quick walk through to get an ASP.NET Core web app running in containers on AWS Fargate using a free AWS account.

For a more detailed experience of publishing ASP.NET Core apps on AWS, check out Julie’s course, “Fundamentals of Building .NET Applications on Amazon Web Services.

About the author

Julie Lerman is a software coach with 30 years of experience as a developer. She is a long-time Pluralsight author, Microsoft MVP, Microsoft Regional Director and Docker Captain who lives in the hills of Vermont and continues to be known as the world’s top expert in Entity Framework. You can find Julie giving keynotes and hard-core coding sessions on Domain-Driven Design, Azure, Entity Framework and other topics at software conferences around the world. Julie has authored the highly acclaimed “Programming Entity Framework” books from O'Reilly, the MSDN Magazine Data Points column and numerous articles in your favorite programming resources.