Previous month:
March 2017
Next month:
September 2017

August 2017

ASP.NET Core: Update to Autofac 4.6.1 recommended - more than a bugfix release

If you are using Autofac in your ASP.NET Core application then I recommend to update Autofac to version 4.6.1. This bugfix release brought a change how child scope handle additional registrations so that some errors like Cannot resolve parameter 'IOptionsFactory<KestrelServerOptions>' just disappear.

With additional registrations I mean the following:

var builder = new ContainerBuilder();

using (var container = builder.Build())
{
    using (var childScope = container.BeginLifetimeScope(innerBuilder =>
        {
            // additional registration that are known by childScope only
            innerBuilder.RegisterType<Foo>().AsSelf();
        }))
    {
        ...
    }
}

When using a child scope during the setup of an ASP.NET Core application having Autofac 4.6.0 or lower then you had to use the IContainer (= root scope) itself or use a workaround to register MVC components. The first option is not recommended because a DI container should be considered as immutable. The second option could be confusing if you don't know the internals of Autofac.

The second options looks like this:

public class Startup
{
    public Startup(ILifetimeScope childScope)
    {
        _childScope = childScope;
    }

    public IServiceProvider ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();

        // All singleton are "rebased" to "aspNetScopeTag"
        const string aspNetScopeTag = "AspNetScope";

        _aspNetScope = _childScope.BeginLifetimeScope(aspNetScopeTag,
            builder => builder.Populate(services, aspNetScopeTag));

         return new AutofacServiceProvider(_aspNetScope);
    }
    ...
}

 With Autofac 4.6.1 you just call Populate without any confusing parameters like aspNetScopeTag.

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    _aspNetScope = _childScope.BeginLifetimeScope(builder => builder.Populate(services));

    return new AutofacServiceProvider(_aspNetScope);
}

 

Want to try it out? I have prepared 2 projects: AspNetCore2_Autofac460 and AspNetCore2_Autofac461 in my github repo. Download the sources and start the applications with dotnet run in the corresponding folder. The first one will raise an error the latter will start the web server successfully.

 

P.S.: Missing context? Why someone would want to provide its own DI container instead of using IServiceCollection and be done with it? Then read my blog post ASP.NET Core in production: Take back control of your web app or the follow-up post ASP.NET Core in production: Graceful shutdown and reacting to aborted requests.


ASP.NET Core in production: Graceful shutdown and reacting to aborted requests

In the previous post "ASP.NET Core in production: Take back control of your web app" I mentioned that getting hold if the dependency injection (DI) is just one step of many to improve the architecture of your web applications. Today well will look into 2 other aspects that are best explained together: graceful shutdown and reacting to aborted requests.

Image you are in the middle of handling of a web request. How do you know that the WebHost is about to shut down or that the client is not interested in the response anymore? Especially the latter will occur more often and without proper handling you end up wasting resources for nothing.

1) If your component is interested in server shutdown only then you can inject IApplicationLifetime and use the property ApplicationStopping that is of type CancellationToken. Most of asynchronous operations support cancellation tokens so you just have to pass the token to them but be prepare for handling the OperationCanceledException and TaskCanceledException.

public DemoController(IApplicationLifetime appLifetime)
{
    _appLifetime = appLifetime;
}     
[HttpGet("MyAction")]
public async Task<IActionResult> MyAction()
{
    CancellationToken token = _appLifetime.ApplicationStopping;
    return await DoSomethingAsync(token);
}

Having a side-free operation like selecting data from database can be cancelled without much effort just pass the CancellationToken to asynchronous methods (like ToListAsync(token)) or check the property CancellationToken.IsCancellationRequested in case you are iterating over some collection or does other synchronous stuff. However, if the operation is critical, the server is shutting down and the component needs a few seconds more to finish then you can delay the shutdown by registering a callback with the CancellationToken.

Use this feature with care, don't hold up the shutdown indefinitely!

_appLifetime.ApplicationStopping.Register(() =>
{
    // server is not going to shutdown     // until the callback is done
});

Note: you can delay the shutdown by overriding the method Dispose of the controller. Using IDisposable-components to finish some stuff works best if you decouple the DI from ASP.NET life cycle like suggested in my previous post because in most cases you want(!) to shut down the WebHost first so that the endpoints are closed and no new requests can come in. Afterwards you can stop your internal processes and dispose of components.

public class DemoController: Controller
{
    protected override void Dispose(bool disposing)
    {
        base.Dispose(disposing);
        //finish your stuff synchronously
    }
}

2) Being interested in server shutdown only is more of an edge case. Most of the time it doesn't matter whether the operation has to stop because of the shutdown or because the client has aborted the HTTP request (e.g. by navigating to another page). In both cases you can use HttpContext.RequestAborted which is another CancellationToken. Although it is called "request-aborted" it is cancelled on shutdown as well because in this case the request is aborted by the server itself not the client.

[HttpGet("MyAction")]
public async Task<IActionResult> MyAction()
{
    CancellationToken token = HttpContext.RequestAborted;
    return await DoSomethingAsync(token);
}

If the method happens to be an action of an MVC/Web API controller (like in my examples) then you can just specify a new method argument of type CancellationToken to get HttpContext.RequestAborted provided to you.

[HttpGet("MyAction")]
public async Task<IActionResult> MyAction(CancellationToken token)
{
    return await DoSomethingAsync(token);
}

 

Want to try it out? I've updated the example from my previous post so that you are able to start and abort HTTP requests or restart the WebHost. The sources are available on Github.

ASP.NET Core - Graceful shutdown


ASP.NET Core in production: Take back control of your web app

With ASP.NET Core the setup of a new MVC or a Web API project is essentially a 2-liner. The standard setup you can find in most tutorials is ideal for demos, workshops or simple web apps but is insufficient for complex applications.

The standard setup looks as follows:

WebHost
.CreateDefaultBuilder()
.UseStartup<Startup>()
.Build()
.Run();

The rest of the configuration of the web app is usually made in Startup.

The problem with the standard approach is that the WebHost controls your entire web application, i.e. it dictates the app life cycle, sets up dependency injection framework, starts and stops your processes and if the WebHost is shutting down (or crashes) then your web application is down as well. Especially the stopping of the app is more of a crash than a graceful shutdown.

A web application is usually more than just a bunch of endpoints. Depending on your requirements you may need a more complex startup, perhaps consisting of multiple steps like

  • setting up logging first
  • pulling configuration
  • filling caches
  • processing of (temp) data from previous run
  • starting some tasks like listening on the file system or for pulling the requests from a message queue because HTTP is not the only gateway to the world
  • etc.

Only after all preparation steps are made the app is ready to open the HTTP endpoints to accept new requests, i.e. to start the WebHost. The web app may run for weeks or month so you may want to restart it (automatically) multiple times to reconfigure the ASP.NET Core pipeline without killing the whole process. And, if the app has to be stopped then you probably want to close the endpoints first, give running requests some time to finish, process the data in buffers or temp files, log some statistics and only then to stop the application.

The first step to get these features is to get control over dependency injection (DI) managing your components. Giving full control of the DI to the ASP.NET Core runtime means that you can't bootstrap your processes before starting the WebHost and if it is stopped then the DI container incl. all your components is disposed of as well. This makes a graceful shutdown very hard. 

In the following examples I'm using Autofac because it is one of the feature-richest and most mature dependency injection frameworks available for .NET. Especially, with Autofac v4.6.1 and Autofac.Extensions.DependencyInjection is it very easy to achieve the desired setup.

Example of a more complex startup so it is easier to get the idea what I 'm talking about: (pseudo code)

var builder = new ContainerBuilder();
// register all dependencies specific to your app
// not necessarilly specific to ASP.NET ...
using (var container = builder.Build())
{
    // assume, depending on some configurations
    // you need to add further dependencies
    var myConfig = container.Resolve<MyConfiguratio>();

    // Adding further dependencies on a child scope
    // can be repeated multiple times if required
    using (var appScope =
        container.BeginLifetimeScope(appScopeBuilder => RegisterFurtherDeps(myConfig)))
    {
        // All methods should do their work in child scopes of "appScope"
        // which should be disposed eventually to free the resources.

        // For example, check file system permissions, databases etc.
        CheckPreconditions(appScope);
        CleanupTheMessFromPreviousRun(appScope);
        StartSomeKindOfTasks(appScope);

        await StartWebHostAsync(appScope);

        // when we are here then that means the endpoints are closed
        WaitForPendingRequests(maxWaitTime: Timespan.FromSeconds(5));
        Cleanup();
        LogStatistics();
    }
}

....

public async Task StartWebHostAsync(ILifetimeScope appScope)
{
    // The WebHost gets its own scope and can do with it what ever it wants,
    // like "polluting" it with some ASP.NET stuff :)
    using (var webHostScope =
        appScope.BeginLifetimeScope(builder => RegisterAspNetSpecificStuff(builder)))
    {
        await WebHost
        .CreateDefaultBuilder()
        .UseStartup<Startup>()
         // This method does not exist but you get the point
        .UseThisDependencyInjectionScope(webHostScope) 
         .Build()
        .RunAsync();
    }
}

 

After a lengthly motivational part let's get to the real code.

In this demo we will setup an MVC web and restart the WebHost on button-click just to proof that the application stays alive even if the web server goes down. 

 At first we set up a DI container and register a class MySingleton as a singleton. This class will be the proof that it is not going to be recreated every time the WebHost restarts.

private static async Task StartWebAppAsync()
{
    var builder = new ContainerBuilder();
    builder.RegisterType<MySingleton>().AsSelf().SingleInstance();
    
    using (var container = builder.Build())
    {
        while (true)
       {
           await StartWebServerAsync(container);
       }
   }
}

The configuration of the WebHost differs just in one point: the instantiation of the class Startup is delegated to Autofac. Because of that our Startup is getting ILifetimeScope via constructor injection.

private static async Task StartWebServerAsync(ILifetimeScope scope)
{
    using (var webHostScope = scope.BeginLifetimeScope(
        builder => builder.RegisterType<Startup>().AsSelf()))
   {
       await WebHost
        .CreateDefaultBuilder()
        .UseStartup<Startup>()
        .ConfigureServices(services =>
            services.AddTransient(provider => webHostScope.Resolve<Startup>()))
        .Build()
        .RunAsync();
   }
}

Note: If your Startup has some ASP.NET specific dependencies, say IHostingEnvironment and IConfiguration then you have to pull them out of IServiceProvider and pass them to a factory created by Autofac.

public Startup(ILifetimeScope webHostScope, 
    IHostingEnvironment hostingEnvironment,
    IConfiguration configuration)
{
    ...
}

...
await WebHost
    ...
    .ConfigureServices(services => services.AddTransient(provider =>
    {
        var hostingEnv = provider.GetRequiredService<IHostingEnvironment>();
        var config = provider.GetRequiredService<IConfiguration>();
        var factory = webHostScope.Resolve<Func<IHostingEnvironment, IConfiguration, Startup>>();          return factory(hostingEnv, config);
    }))
    ...

Ok, back on track.  

In the Startup we copy the DI registrations from IServiceCollection to our DI container by using the method Populate and save the newly created DI scope in a variable so it can be disposed when the ASP.NET part is shutting down.

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    // register ASP.NET Core stuff
    services.AddMvc();
    _aspNetScope = _webHostScope.BeginLifetimeScope(builder => builder.Populate(services));     return new AutofacServiceProvider(_aspNetScope);
}
public void Configure(IApplicationBuilder app, IApplicationLifetime appLifetime)
{
    app.UseMvc();
    appLifetime.ApplicationStopped.Register(() => _aspNetScope.Dispose());
}

 

Your MVC application is now set up properly.

Want to try it out? Download the sources from Github, launch the mini MVC app with dotnet run, go to the url printed in the console window and start restarting the WebHost :)

ASP.NET Core - Take back the control of your web app

 

P.S.: Getting hold of the DI is just one but not the only one aspect of keeping your app under control. But that's a topic for another day...


ASP.NET Core: Beware - Singleton may not be singleton

If you register a type as a singleton then you expect just 1 instance of this type in your whole application. What you may not know is that ASP.NET Core is creating 2 instances of IServiceProvider during building of the IWebHost that may lead to 2 instance of your "singleton".

This is the case if you register a type, say MySingleton, when configuring the web host ...

WebHost
.CreateDefaultBuilder()
.UseStartup<Startup>()
.ConfigureServices(services => services.AddSingleton<MySingleton>())
.Build()
.Run();

 ..., e.g. so that is available in the constructor of your Startup

public class Startup
{
private readonly MySingleton _mySingletonFromHostingServiceProvider;
public Startup(MySingleton mySingletonFromHostingServiceProvider)
{
_mySingletonFromHostingServiceProvider = mySingletonFromHostingServiceProvider;
}
...
}

Now, if we resolve MySingleton during normal web request we get a whole new instance instead the same instance as in constructor of the Startup class. 

public void Configure(IApplicationBuilder app)
{
app.Use((ctx, next) =>
{
var mySingleton = ctx.RequestServices.GetRequiredService<MySingleton>();

// the comparison of 2 instances yields "false"
var areEqual = _mySingletonFromHostingServiceProvider == mySingleton;

Console.WriteLine($"==> {nameof(_mySingletonFromHostingServiceProvider)} == {nameof(mySingleton)}: {areEqual}");          return next();
    });
}

 There are at least two ways to fix this problem.

Either pass an instance of MySingleton to method AddSingleton instead of passing just the type

var mySingleton = new MySingleton();
WebHost
.CreateDefaultBuilder()
.UseStartup<Startup>()
.ConfigureServices(services => services.AddSingleton(mySingleton))
.Build()
.Run();

 or by replacing the previous registration with a new one in ConfigureServices 

public class Startup
{
private readonly MySingleton _mySingletonFromHostingServiceProvider;
public Startup(MySingleton mySingletonFromHostingServiceProvider)
{
_mySingletonFromHostingServiceProvider = mySingletonFromHostingServiceProvider;
}
public void ConfigureServices(IServiceCollection services)
{
services.Replace(new ServiceDescriptor(typeof(MySingleton), _mySingletonFromHostingServiceProvider));
  // alternative way
//services.AddSingleton(_mySingletonFromHostingServiceProvider);
}
...
}

 

According to @davidfowl the ASP.NET team will address this problem in the future. 

PS: There is at least another one solution to fix this problem and gaining back the control over your web app but that's for another time ... :)