Previous month:
November 2016
Next month:
March 2017

February 2017

ASP.NET Core with IIS: Setup Issues

If you are planing to run an ASP.NET Core application with IIS then this blog post might be worth a glance.

These are a few issues I run into ...

1. Targets in .xproj-file

If the project started with RC1 or earlier version of .NET Core then check for correct targets. Open the .xproj file and search for the following line

<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" 
        Condition="'$(VSToolsPath)' != ''" />

and replace it with

<Import Project="$(VSToolsPath)\DotNet.Web\Microsoft.DotNet.Web.targets" 
        Condition="'$(VSToolsPath)' != ''" />

2. The process path in web.config

If you get 502 after starting the web then take a look into windows event viewer. One of the errors you will probably see is

Application 'MACHINE/WEBROOT/APPHOST/YOUR-APP with physical root 'C:\webapp\publish\' created process with commandline '"dotnet" WebApp.Selfhost.dll' but either crashed or did not reponse or did not listen on the given port '28236', ErrorCode = '0x800705b4'

This error means that IIS is unable to start your app using the command dotnet. To remedy this issue open web.config and change the processPath from dotnet to C:\Program Files\dotnet\dotnet.exe.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <system.webServer>
        <handlers>
            <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
        </handlers>
        <aspNetCore processPath="C:\Program Files\dotnet\dotnet.exe"
            arguments=".\WebApp.Selfhost.dll"
            stdoutLogEnabled="false"
            stdoutLogFile=".\logs\stdout"
            forwardWindowsAuthToken="false" />
    </system.webServer>
</configuration>

3. When to call UseIISIntegration

If you still getting 502 then the possible cause of this error may be that the your application is listening on a different port as expected. This can happen if one of your configuration keys is Port. In this case your web is listening on this port instead of dynamically generated port.

The configuration of the WebHostBuilder causing the error can look as following:

var hostBuilder = new WebHostBuilder()
    .UseConfiguration(myConfig) // inserts config with key "Port"
    .UseIISIntegration()    // uses previously inserted port "by mistake"
    .UseKestrel()
    .UseStartup<Startup>();

To cure that just change the order of the calls because with .NET Core 1.1 the listening url when running with IIS will not been overwritten anymore.

var hostBuilder = new WebHostBuilder()
    .UseIISIntegration()
    .UseConfiguration(myConfig)
    .UseKestrel()
    .UseStartup<Startup>();

 


(ASP).NET Core Dependecy Injection: Disposing

After several years of using the same Dependency Injection (DI) framework like Autofac you may have a good understanding how your components, implementing the interface IDisposable, are going to be disposed.

With the nuget package Microsoft.Extensions.DependencyInjection the new .NET Core framework brings its own DI framework. It is not that powerful as the others but it is sufficient for simple constructor injection. Nonetheless, even if you don't need some advanced features you have to be aware of how the components are destroyed by this framework.

Let's look at a concrete example. Given are 2 classes, a ParentClass and a ChildClass:

public class ParentClass : IDisposable
{
	public ParentClass(ChildClass child)
	{
		Console.WriteLine("Parent created.");
	}

	public void Dispose()
	{
		Console.WriteLine("Parent disposed.");
	}
}

public class ChildClass : IDisposable
{
	public ChildClass()
	{
		Console.WriteLine("Child created");
	}

	public void Dispose()
	{
		Console.WriteLine("Child disposed.");
	}
}

At first we are using Autofac to resolve ParentClass:

var builder = new ContainerBuilder();
builder.RegisterType<ParentClass>().AsSelf();
builder.RegisterType<ChildClass>().AsSelf();
var container = builder.Build();

Console.WriteLine("== Autofac ==");
var parent = container.Resolve<ParentClass>();

container.Dispose();

With Autofac we are getting the following output:

== Autofac ==
Child created
Parent created.
Parent disposed.
Child disposed.

And now we are using .NET Core DI:

var services = new ServiceCollection();
services.AddTransient<ParentClass>();
services.AddTransient<ChildClass>();
var provider = services.BuildServiceProvider();

Console.WriteLine("== .NET Core ==");
var parent = provider.GetRequiredService<ParentClass>();

((IDisposable) provider).Dispose();

The output we get is:

== .NET Core ==
Child created
Parent created.
Child disposed.
Parent disposed.

Comparing the outputs we see that Autofac destroys the outer compontent (i.e. ParentClass) first and then the inner component (i.e. ChildClass). The .NET Core DI does not honor the dependency hierarchy and destroys the components in the same order they are created.

Most of the time the behavior of .NET Core DI is not a problem because the components just free internal resources and are done. But in some cases the outer component has to do something like to unregister from the inner component that may live on. If the inner component is/will not be disposed then all works fine; if not then we get ObjectDisposedException.

If you start a new project with .NET Core I suggest to stay with DI framework you are familiar with unless it is a sample application.

PS: Further information of how to switch from .NET Core DI to other frameworks in an ASP.NET Core application: Replacing the default services container  and ASP.NET Core with Autofac