Konzultant a lektor pro [ASP].NET Core & REST API

Registrace AutoFac v [ASP].NET Core 3.0

Od verze: ASP.NET Core 3.0
Miroslav Holec

Miroslav Holec

12. září. 2019

Nový .NET Core 3.0 přináší obecný host, který v sobě zapouzdřuje podporu DI, logování a konfigurace aplikace. Vývojáře by měl zajímat, protože brzy zmizí zpětná kompatibilita s web hostem a přechod na generic host verzi bude nezbytný. Tento host navíc nabízí možnost velmi pohodlného zapojení vlastního DI kontejneru.

👨‍🏫️ Firemní školení
Vývoj aplikací v ASP.NET Core 3.0

Seznámíte se s klíčovými aspekty ASP.NET Core, které v praxi použijete pro vývoj různých druhů webových aplikací a webových služeb. Celodenní školení přímo u Vás ve firmě. Celá ČR / Slovensko

ServiceProviderFactory

Když jste chtěli zapojit doposud vlastní kontejner do ASP.NET Core aplikace, museli jste vytvořit jeho instanci v metodě ConfigureServices() a dle návodu nějakým způsobem slít dohromady registrované služby MS DI kontejneru a vašeho custom kontejneru. Nově se tato logika odsouvá do tzv. ServiceProviderFactory, která se pouze registruje do generic hostu. Na příkladu níže je vidět registrace v případě AutoFacu.

Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureWebHostDefaults(webBuilder =>
{
    webBuilder.UseStartup<Startup>();
})
.Build().Run();

Samotnou ServiceProviderFactory bude většina DI kontejnerů vydávat jako součást NuGet balíčku. Pokud ne, budete si ji muset napsat svépomocí. V takovém případě stačí implementovat generický interface IServiceProviderFactory.

V případě AutoFacu najdete tuto factory v NuGet balíčku Autofac.Extensions.DependencyInjection.

Registrace services do kontejneru

A teď přichází největší pecka! Použitím ServiceProviderFactory můžete dle konvencí připravit ve třídě Startup.cs metodu ConfigureContainer, která má na vstupu samotný DI kontejner (ten generický typ ze ServiceProviderFactory).

public class Startup
{
    // Microsoft DI
    public void ConfigureServices(IServiceCollection services)
    {
    }

    // Custom DI (AutoFac)
    public void ConfigureContainer(ContainerBuilder builder)
    {
        builder.RegisterType<ForecastService>()
           .As<IForecastService>().InstancePerLifetimeScope();
    }

    // HTTP Context Pipeline
    public void Configure(IApplicationBuilder app, Handlers.Handlers handlers)
    {
    }
}

Metody se odbavují v pořadí ConfigureServices(), poté ConfigureContainer() a nakonec Configure(). Do metody Configure() lze již přes method injection předat vlastní registrované služby.

Pozor na konstruktor třídy Startup

Poslední zmínku bych chtěl věnovat konstruktoru třídy Startup. Do něj mohou s použitím generic hosta nově vstoupit jen dva povolené typy IConfiguration a IWebHostEnvironment.

public class Startup
{
    public Startup(IConfiguration configuration, IWebHostEnvironment env)
    {
        this.configuration = configuration;
        this.env = env;
    }

    private readonly IConfiguration configuration;
    private readonly IWebHostEnvironment env;

    ...

Behind the scene

Pakliže vás zajímá, jak funguje IServiceProviderFactory na pozadí, čtěte dále. Faktorka vyžaduje implementaci dvou metod:

CreateBuilder(IServiceCollection services)

Jedná se o metodu, která na vstupu dostane MS DI kolekci registrovaných služeb. Jsou to ty služby, které registrujete v metodě Startup.ConfigureServices(). V této metodě je nutné tyto služby vzít a nalít je do nově registrovaného kontejneru (nebo nějakou mechanikou kolem něj). V případě AutoFacu:

public ContainerBuilder CreateBuilder(IServiceCollection services)
{
    var builder = new ContainerBuilder();

    builder.Populate(services);

    _configurationAction(builder);

    return builder;
}

CreateServiceProvider(ContainerBuilder builder)

Druhá metoda dostane na vstupu již custom container builder (mohl by to být i přímo kontejner). V této metodě je následně nutné vyrobit instanci pro interface IServiceProvider. Ten by měl podporovat všechny známé metody, jako například GetService() nebo GetRequiredService(). V případě AutoFacu:

public IServiceProvider CreateServiceProvider(ContainerBuilder containerBuilder)
{
    var container = containerBuilder.Build();
    return new AutofacServiceProvider(container);
}