This is part II of the blog post series in which I share some of ways to build and deploy an ASP.NET core application to IIS running on a Windows VM. In the previous post, I cover how to build and published an ASP.NET core application. The end result is an artifact (a published directory). In this post, I go over how to deploy the artifact to IIS. Along the way, we’ll discuss:
Following are the steps for deploying a typical ASP.NET core application on IIS for the first time.
Follow the steps below to check and enable IIS as necessary:
When publishing the application, if you choose Framework dependent deployment (FDD), the server on which your app runs need to have the appropriate .NET core runtime installed. To check the runtime available on a server, run the following command:
dotnet --info
Note: To use the dotnet command tools, you need to install the SDK.
Below shows a sample of the .net core runtimes installed on a Windows VM.
.NET Core runtimes installed:
Microsoft.AspNetCore.All 2.1.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore
Microsoft.AspNetCore.All 2.2.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore
Microsoft.AspNetCore.App 2.1.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore
Microsoft.AspNetCore.App 2.2.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore
Microsoft.NETCore.App 2.1.3 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.2.2 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
The above runtimes mean the server can support any FDD of an application which targets .NET core between 2.0.0 and 2.2.2, thanks to the roll forward feature, which is available starting with .net core 2.0.0.
Download and install the latest runtime and hosting bundle. As of this writing, the latest stable .net core runtime is 2.2. You can find it here.
Caution: You need to enable IIS first before installing the runtime and hosting bundle. If you install the bundle without enabling IIS, then you need to run the installation again and choose “Repair”, after enabling IIS.
Restart the server after the installation.
An application pool essentially allows you to control the resources for a web application. For example, you can have multiple applications share the same resources by assigning them to the same pool, or you can allocate dedicated resources for an application by assigning the application to an application pool, separating from the other pools.
An application pool also acts as a sandbox to effectively isolate applications within the pool from applications within another pool. If an application runs under an application pool crashes or causes trouble, it does not affect applications running in another pool. You can have multiple applications share a same pool, and you can also have multiple pools for different applications. Each application pool represents a worker process. As such, the more application pools you have, the more memory you need.
When you stop an application pool, you essentially stop the application(s) associated with the pool.
A site is a container for web applications. Each site has a default root application, and you can create more applications under the site. All applications under a same site share the same root URL (binding).
Although applications under a same site share the same bindings, each application can have its own application pool. As such, you can still achieve application isolation when hosting multiple applications under a same site. Ofcourse, you can also host multiple applications under multiple sites.
You may want to host multiple applications under a same site to reuse DNS, or if the applications are closely related. For example, suppose you have two related applications; perhaps two different API versions of a same app. You can host both applications under the same site. They both share the same root URL, but different ending path (e.g myapi.com/v1 and myapi.com/v2).
A site binding basically suggests to IIS that a site can handle a request if the request’s header matches one or more parts of the binding. The primary parts of a binding are type, IP address, port and hostname. When an incoming request hits the server, based on the sites’ bindings, IIS can determine which site is the best match to handle the request.
A binding consists primarily of the following:
Type: Either http or https. In the case of https, you can associate a SSL certificate with the binding.
Host name: A server can have one or more host names assigned to it. The default value is blank, or localhost. The hostname in the request address must match the hostname in the binding for the site to process the request.
Port: The TCP port number. This is a required configuration. Specify the port number on which you want to bind the site. The port number specified in the request address must match the port number in the binding for the site to process the request.
IP Address: A server can have more than 1 IP address assigned to it. When configuring a binding for a site, you can select a specific IP assigned to a server. You can also select the value “All Unassigned”, meaning all the ip addresses that have not been assigned to other IIS sites. If the request address has the form of an IP address, the request’s IP address must match the IP address of the binding for the site to process the request.
An SSL certificate is for establishing a secured communication between a server and a client to prevent a Man-in-the-middle attack.
Below I give a recap of how SSL works. For more details, checkout the article.
To obtain an SSL certificate:
Communication between browser and server using SSL:
For testing purpose, you can also use a self signed certificate. See this post.
For demonstration purpose, I have built and published a simple ASP.NET core application. The app targets .NET core 2.2.
On the remote server, I have the published folder under “C:\inetpub\MyAspNetCoreApp”.
To create an application pool,
.NET CLR version:
The .NET CLR version refers to the version of the Common Language Runtime which the .NET framework includes. For this example, since we deploying an ASP.NET core application that targets .NET core, not .NET, so we choose “No Managed Code”.
Displays the version of the .NET Framework that an application pool uses. If the application pool was configured to not use the .NET Framework, the value is No Managed Code.
Application Pools
Managed pipeline mode: Integrated vs Classic
This stackoverflow post talks about the differences between integrated vs classic mode. The main points come from the documentation. Below is just my summary.
Integrated mode is the newer mode available since IIS 7.0. Integrated mode unifies the processing models of IIS and ASP.NET. In integrated mode, an order list of events process a request and then generate a response.
Classic mode separates the processing models of IIS and ASP.NET. In classic mode, a request goes through native processing in IIS. Then, it goes through Aspnet_isapi.dll for processing of managed code.
Some of the processing steps, such as authentication and authorization are the same in IIS and ASP.NET processing models. As such, it is less performant than integrated mode because of the duplicate processings a request has to go through. If you are deploying a new application, definitely choose integrated mode.
You should see the site loads. If so, congratulations.
Next steps: Once you are able to load the site locally, you can configure the binding to allow the world to reach your site.
In the next post, I’ll share how to automate the build and deployment process using azure pipelines.
If you get HTTP 500.19 – Internal Server Error. It can be the server does not have the correct .Net core runtime installed. See this cd .
One way to troubleshoot is running the application directly using the dotnet command.
Open the command line, CD to the directory containing the application files: C:\inetpub\MyAspNetCoreApp. Then type the command
dotnet AspNetCoreApp.dll
You should be able to browse to the application on port 5000.
Read my next post in this series to learn how to automate the build and deployment process so you can save time, reduce human errors and focus more on building your application.
Build and publish an ASP.NET core application using Visual Studio 2017.
Quick Reference: IIS Application Pool
Understanding IIS Bindings, Websites, Virtual Directories, and lastly Application Pools
Differences between Integrated vs Classic mode in App Pool
How to set up site bindings in Internet Information Services (IIS)
Enhancing ASP.NET Core/Blazor App Security and Reusability with HttpMessageHandler and Named HttpClient
Building multitenant application – Part 2: Storing value into database session context from ASP.NET core web API
Building multitenant application – Part 1: Multitenant database using Row Level Security
Azure AD authentication in angular using MSAL angular v2 library
Build and deploy a WebJob alongside web app using azure pipelines
Authenticate against azure ad using certificate in a client credentials flow
Notes on The Clean Architecture
Migrating from Microsoft.AspNetCore.Authentication.AzureAD to Microsoft Identity Web authentication library to integrate with Azure AD.