Deploy ASP.NET Core to IIS & How ASP.NET Core Hosting Works

Deploy ASP.NET Core to IIS & How ASP.NET Core Hosting Works | Best and cheap ASP.NET Core 1.0 hosting. In this article, we will review how to deploy an ASP.NET Core application to IIS. Deploying an ASP.NET Core app to IIS isn’t complicated, but ASP.NET Core hosting is a little different than ASP.NET.

How to Configure Your ASP.NET Core App For IIS

The first thing you will notice when creating a new ASP.NET Core project is they are actually console applications. Your project now contains a Program.cs file just like a console app would have and it contains the following code:

What is the WebHostBuilder?

All ASP.NET Core applications require a WebHost object that essentially serves as the application and web server. WebHostBuilder is used to configure and create the WebHost. You will normally see UseKestrel() and UseIISIntegration() in the WebHostBuilder setup code.

What do these do?

  • UseKestrel() – This registers the IServer interface for Kestrel as the server that will be used to host your application. In the future, there could be other options, including WebListener which will be Windows only.
  • UseIISIntegration() – This tells ASP.NET that IIS will be working as a reverse proxy in front of Kestrel. This then specifies some settings around which port Kestrel should listen on, forwarding headers, and other details.

If you are planning to deploy your application to IIS, UseIISIntegration() is required

What is AspNetCoreModule?

You may have noticed that ASP.NET Core projects create a web.config file. This is only used when deploying your application to IIS. It registers the AspNetCoreModule as an HTTP handler.

Default web.config for ASP.NET Core:

If you are planning to deploy your application to IIS, UseIISIntegration() is required

Default web.config for ASP.NET Core:

AspNetCoreModule handles all incoming traffic to IIS and acts as the reverse proxy that knows how to hand the traffic off to your ASP.NET Core application. You can view the source code of it on GitHub. It also ensures that your web application is running. It is responsible for starting your process up.

Install .NET Core Windows Server Hosting Bundle

Before you deploy your application, you need to install the .NET Core hosting bundle for IIS. This will install the .NET Core runtime, libraries, and the ASP.NET Core module for IIS.

After installing it, you may need to do a “net stop was /y” and “net start w3svc” to ensure all the changes are picked up for IIS.

Steps to Deploy ASP.NET Core to IIS

Before you deploy, you need to make sure that WebHostBuilder is configured properly to use Kestrel and IIS. Your web.config should also exist and look similar to our example above.

Step 1: Publish to a File Folder


Step 2: Copy Files to Preferred IIS Location

Now you need to copy your publish output to where you want the files to live. If you are deploying to a remote server, you may want to zip up the files and move to the server. If you are deploying to a local dev box, you can copy them locally.

For my example, I am copying the files to C:\inetpub\wwwroot\AspNetCore46

You will notice that with ASP.NET core there is no bin folder and it potentially copies over a ton of different .NET dlls. Your application may also be an EXE file if you are targeting the full .NET Framework. My little sample project had over 100 dlls in the output.


Step 3: Create Application in IIS

First, create a new IIS Application Pool. You will want to create one under the .NET CLR version of “No Managed Code“. Since IIS only works as a reverse proxy, it isn’t actually executing any .NET code.

Second, create your new application under your existing IIS Site, or create a new IIS site. Either way, you will want to pick your new IIS Application Pool and point it at the folder you copied your ASP.NET publish output files to.


Step 4: Load Your App!

At this point, your application should load just fine. If it does not, check the output logging from it. Within your web.config file you define how IIS starts up your ASP.NET Core process. Enable output logging by setting stdoutLogEnabled=true and you may also want to change the log output location as configured in stdoutLogFile. Check out the example web.config before to see where they are set.

Advantages of Using IIS with ASP.NET Core Hosting

Microsoft recommends using IIS with any public facing site for ASP.NET core hosting. IIS provides additional levels of configurability, management, security, logging, and many other things. Check out my blog post about Kestrel vs IIS to see a whole matrix of feature differences. It goes more in depth about what Kestrel is and why you need both Kestrel & IIS.

One of the big advantages to using IIS is the process management. IIS will automatically start your app and potentially restart it if a crash were to occur. If you were running your ASP.NET Core app as a Windows Service or console app, you would not have that safety net there to start and monitor the process for you.

Tips for Building an API in ASP.NET Core

Tips for Building an API in ASP.NET Core | Best and cheap ASP.NET Core 1.0 hosting. These days users expect a fluid, app-like experience on the internet. Thus, the new web is being built with APIs and single-page frontends. This means it’s more important that ever to build APIs that are easy to use, reliable, and scalable. ASP.NET Core makes it easy to build great APIs, but there are a few tips we’ve picked up that can help make your APIs even stronger and more scalable.

1. Set the Default Route for ASP.NET Core MVC

A lot of programmers who start using ASP.NET Core just use the default app.UseMvc(); line in the Configure method of Startup.cs. There are options that you can pass to the UseMvc function, like setting the default routes, which is one of the most overlooked:

This will set the root route of your API to: to call the DefaultController’s Get method.

What this does for you (aside from the obvious) is it sets the tone for a decent RESTful API. It also makes changes to URL strategy easier, including versioning the API in the URL easy to do if you set the URL strategy in one place.

2. Return IActionResult from .NET Core Controller Methods

Returning IActionResult from your controller methods affords the ability to take advantage of some of the helper methods and classes to ease returning proper HTTP results. The Ok method on the ControllerBase class will return an OkObjectResult that implements IActionResult and returns a 200 OK HTTP message to the caller. The NotFound method returns an object that sends a 404 NOT FOUND HTTP message.

There are quite a few others, but another extremely helpful one is the CreatedAtAction class that returns not only a 201 CREATED HTTP result but adds a header Location with the URL to access the newly created resource.

3. Use the .NET Async Pattern

Network calls by their very nature are asynchronous. It makes the most sense to create async controller methods that extend that asynchronicity when the controllers need to make database and external API calls.

The fact is, asynchronous support in .NET Core and the supporting libraries is very good these days. Using and creating asynchronous code is easy using async/await and libraries that support the Task pattern. The benefit is more simultaneous requests handled with the same hardware requirements.

Asynchronous code just performs better, and since it is so easy to create, why not do it?

4. Use .NET Attributes

Using attributes to decorate routes helps you to take advantage of some of the power of MVC. This may seem counterintuitive since I just told you to use the default routes. Decorating your methods and controller classes with just enough decoration for that class or method can help you take advantage of things like the CreatedAtAction.

You can also use attributes to help the JSON serializer do its job. You can use the NullValueHandling attribute to tell the serializer that when the value of a property is null, not to even serialize the property. You can change the property name that gets serialized so that you can stick with an internal coding standard and still return standard JSON names (like changing ‘MaxTitleLength’ to ‘maxLength’ when serialized). You can even set the order that properties are serialized so that more important properties are serialized first in the JSON documents.

5. Use Async Result Filters

Using Async Result Filters, you can shape the data in the last moments before it goes back to the caller. Usually, you’d add the properties you want (the way you want them) via an anonymous object. There are two problems with that approach, the first is that you need to do a lot of copying of properties and it violates the single responsibility principle. You could use AutoMapper to combat this property copying, but it doesn’t solve the second problem, which is adding new properties (like hypermedia).

Solution: An Async Result Filter will solve both problems and give you a cleaner, more maintainable code base.

BONUS: Try This Workaround to Improve Serialization of Self-Referencing Object Graphs

One of the problems with traditional .NET Web API serialization, is that it doesn’t handle self-referencing object graphs very well. The fact is, in good object-oriented objects there may actually be some reference loops, so it’s important to handle them gracefully.

In your ConfigureServices method of Startup.cs, change your MVC line from:

to :

In .NET 4.x a reference loop would cause an error. Once the serializer realized that serializing the object graph would cause a reference loop, it would fail and just send a 500 error. However, in .NET Core without the above JSON options added, the serializer serializes the object until it hits a reference loop and simply sends what has been serialized so far, ignoring the rest of the object, even if it could serialize the rest of the object graph easily.

What this line adds is, it tells the JSON serializer to ignore reference loops and continue serializing the rest of the graph. So far, this is just a workaround for the issue. It’s not perfect, but it’s better than just a failure.

The best way to handle this problem is to simply not have the problem. Normally, we would put these objects into DTOs that are not self-referencing and remove the problem altogether.

Structured Logging in ASP.NET Core

Structured Logging in ASP.NET Core | Best and cheap ASP.NET Core 1.0 hosting. ASP.NET Core is a complete rewrite of ASP.NET, targeting .NET Core on Linux and OS X as well as Windows.

Among the many upgrades in the new version is a completely rewritten diagnostic logging pipeline that not only emits interesting events from the framework, but uses structured logging to do so.

Structured Logging in ASP.NET Core

Like Serilog, ASP.NET Core uses message templates (named placeholders in format strings) to capture structured properties along with textual log data:

If this event is written out to the console, it will be formatted as plain text:

This is ideal during development, when a readable text format is preferred.

But, when the logging provider supports structured data, the properties associated with the event can be preserved in a machine-readable form:

Armed with structured log data, it’s easy to slice and dice logs with queries like:

This is a game-changing capability for complex distributed apps, or when log data runs more than a few hundred events in a day.

Setting Up

These instructions assume that you’ve created a new ASP.NET web application using the template in Visual Studio (File > New… > Project > ASP.NET Web Application).

Out of the box it should look something like this:


The packages we’ll install are:

  • Serilog – a logging framework for structured data
  • Serilog.Extensions.Logging – an ASP.NET logging provider that implements ASP.NET’s ILogger on top of Serilog
  • Serilog.Sinks.Seq – a Serilog sink that ships events to Seq over HTTP

To really take advantage of ASP.NET Core’s logging today, you’ll need a complete logging provider like Serilog to handle the task of shipping log events to most back-end storage targets, as only a few basic providers such as a console logger are there today. Over time it’s likely ASP.NET Core will gain more capabilities of its own in this area.

Crucially, all of the packages supporting ASP.NET Core are currently pre-release, so make sure to include the -Pre switch when installing from the Package Manager Console:

Then, the following lines added to Startup.cs will configure the Serilog back-end:

This assumes you have Seq running locally on your development machine, listening on the default port. Replace http://localhost:5341 with the address of you Seq server if it lives somewhere else.

(Adding Enrich.FromLogContext() here ensures that any events written directly through Serilog will seamlessly pick up correlation ids like RequestId from ASP.NET.)

Finally, also in Startup.cs, add Serilog to the ILoggerFactory that’s passed into the Configure() method:

When you refresh the application, all kinds of interesting data from the framework’s inner workings will appear in Seq:


In this screenshot you can see a few familiar MVC processes going on – requests started and finished, actions invoked and views selected.

Writing custom events

It would be interesting, but fairly underwhelming, if the story ended here. The real value in the new logging pipeline is that your own application events get the same treatment.

The simplest way to start logging from your own controllers is to take a dependency on type ILogger<T>:

The T generic parameter is passed so that log events can be tagged with the class that raised them.

ILogger<T> has methods like LogInformation(), LogWarning() and LogError() to write events to the logging pipeline:

Look carefully at the properties attached to the resulting event:


The first thing to notice is that the MachineName argument we supplied in the format string is there as a first-class property that can be used when searching for events.

The second thing to observe is RequestId – this little gem is added automatically by the ASP.NET framework to all events raised during a web request. Filtering down to a single RequestId will find all events related to just that HTTP request – your own, and the ones raised by the framework. If you don’t use this technique already, it’s something you absolutely must try.

Alternatives for ASP.NET 4.6

Not using ASP.NET Core just yet? Check out the Serilog support for ASP.NET 4.6, which adds a lot of structured logging goodness through a NuGet package.

Happy logging!