Attivazione del middleware con un contenitore di terze parti in ASP.NET Core

In questo articolo viene illustrato come usare IMiddlewareFactory e IMiddleware come punto di estendibilità per l'attivazione del middleware con un contenitore di terze parti. Per informazioni introduttive su IMiddlewareFactory e IMiddleware, vedere Attivazione del middleware basata su factory in ASP.NET Core.

Visualizzare o scaricare il codice di esempio (procedura per il download)

L'app di esempio illustra l'attivazione del middleware da parte di un'implementazione IMiddlewareFactory, SimpleInjectorMiddlewareFactory. Nell'esempio viene utilizzato il contenitore di inserimento delle dipendenze Simple Injector.

L'implementazione del middleware nell'esempio registra il valore fornito da un parametro stringa di query (key). Il middleware usa un contesto di database inserito, ovvero un servizio con ambito, per registrare il valore della stringa di query in un database in memoria.

Nota

Nell'app di esempio viene utilizzato Simple Injector esclusivamente a scopi dimostrativi. L'utilizzo di Simple Injector non ne implica la sponsorizzazione. Le modalità di attivazione del middleware descritte nella documentazione di Simple Injector e i problemi in GitHub sono consigliati dai gestori di Simple Injector. Per ulteriori informazioni, vedere la documentazione di Simple Injector e il repository GitHub su Simple Injector.

IMiddlewareFactory

IMiddlewareFactory specifica i metodi per creare il middleware.

Nell'app di esempio viene implementata una factory middleware per creare un'istanza SimpleInjectorActivatedMiddleware di . Il middleware basato su factory usa il contenitore Simple Injector per risolvere il middleware:

public class SimpleInjectorMiddlewareFactory : IMiddlewareFactory
{
    private readonly Container _container;

    public SimpleInjectorMiddlewareFactory(Container container)
    {
        _container = container;
    }

    public IMiddleware Create(Type middlewareType)
    {
        return _container.GetInstance(middlewareType) as IMiddleware;
    }

    public void Release(IMiddleware middleware)
    {
        // The container is responsible for releasing resources.
    }
}

IMiddleware

IMiddleware definisce il middleware per la pipeline di richieste dell'app.

Middleware attivato da un'implementazione IMiddlewareFactory (Middleware/SimpleInjectorActivatedMiddleware.cs):

public class SimpleInjectorActivatedMiddleware : IMiddleware
{
    private readonly AppDbContext _db;

    public SimpleInjectorActivatedMiddleware(AppDbContext db)
    {
        _db = db;
    }

    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        var keyValue = context.Request.Query["key"];

        if (!string.IsNullOrWhiteSpace(keyValue))
        {
            _db.Add(new Request()
                {
                    DT = DateTime.UtcNow, 
                    MiddlewareActivation = "SimpleInjectorActivatedMiddleware", 
                    Value = keyValue
                });

            await _db.SaveChangesAsync();
        }

        await next(context);
    }
}

Viene creata un'estensione per il middleware (Middleware/MiddlewareExtensions.cs):

public static class MiddlewareExtensions
{
    public static IApplicationBuilder UseSimpleInjectorActivatedMiddleware(
        this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<SimpleInjectorActivatedMiddleware>();
    }
}

Startup.ConfigureServices deve eseguire diverse attività:

  • Impostare il contenitore Simple Injector.
  • Registrare la factory e il middleware.
  • Rendere disponibile il contesto di database dell'app dal contenitore Simple Injector.
public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages();

    // Replace the default middleware factory with the 
    // SimpleInjectorMiddlewareFactory.
    services.AddTransient<IMiddlewareFactory>(_ =>
    {
        return new SimpleInjectorMiddlewareFactory(_container);
    });

    // Wrap ASP.NET Core requests in a Simple Injector execution 
    // context.
    services.UseSimpleInjectorAspNetRequestScoping(_container);

    // Provide the database context from the Simple 
    // Injector container whenever it's requested from 
    // the default service container.
    services.AddScoped<AppDbContext>(provider => 
        _container.GetInstance<AppDbContext>());

    _container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();

    _container.Register<AppDbContext>(() => 
    {
        var optionsBuilder = new DbContextOptionsBuilder<DbContext>();
        optionsBuilder.UseInMemoryDatabase("InMemoryDb");
        return new AppDbContext(optionsBuilder.Options);
    }, Lifestyle.Scoped);

    _container.Register<SimpleInjectorActivatedMiddleware>();

    _container.Verify();
}

Il middleware è registrato nella pipeline di elaborazione della richiesta in Startup.Configure:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
    }

    app.UseSimpleInjectorActivatedMiddleware();

    app.UseStaticFiles();
    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

In questo articolo viene illustrato come usare IMiddlewareFactory e IMiddleware come punto di estendibilità per l'attivazione del middleware con un contenitore di terze parti. Per informazioni introduttive su IMiddlewareFactory e IMiddleware, vedere Attivazione del middleware basata su factory in ASP.NET Core.

Visualizzare o scaricare il codice di esempio (procedura per il download)

L'app di esempio illustra l'attivazione del middleware da parte di un'implementazione IMiddlewareFactory, SimpleInjectorMiddlewareFactory. Nell'esempio viene utilizzato il contenitore di inserimento delle dipendenze Simple Injector.

L'implementazione del middleware nell'esempio registra il valore fornito da un parametro stringa di query (key). Il middleware usa un contesto di database inserito, ovvero un servizio con ambito, per registrare il valore della stringa di query in un database in memoria.

Nota

Nell'app di esempio viene utilizzato Simple Injector esclusivamente a scopi dimostrativi. L'utilizzo di Simple Injector non ne implica la sponsorizzazione. Le modalità di attivazione del middleware descritte nella documentazione di Simple Injector e i problemi in GitHub sono consigliati dai gestori di Simple Injector. Per ulteriori informazioni, vedere la documentazione di Simple Injector e il repository GitHub su Simple Injector.

IMiddlewareFactory

IMiddlewareFactory specifica i metodi per creare il middleware.

Nell'app di esempio viene implementata una factory middleware per creare un'istanza SimpleInjectorActivatedMiddleware di . Il middleware basato su factory usa il contenitore Simple Injector per risolvere il middleware:

public class SimpleInjectorMiddlewareFactory : IMiddlewareFactory
{
    private readonly Container _container;

    public SimpleInjectorMiddlewareFactory(Container container)
    {
        _container = container;
    }

    public IMiddleware Create(Type middlewareType)
    {
        return _container.GetInstance(middlewareType) as IMiddleware;
    }

    public void Release(IMiddleware middleware)
    {
        // The container is responsible for releasing resources.
    }
}

IMiddleware

IMiddleware definisce il middleware per la pipeline di richieste dell'app.

Middleware attivato da un'implementazione IMiddlewareFactory (Middleware/SimpleInjectorActivatedMiddleware.cs):

public class SimpleInjectorActivatedMiddleware : IMiddleware
{
    private readonly AppDbContext _db;

    public SimpleInjectorActivatedMiddleware(AppDbContext db)
    {
        _db = db;
    }

    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        var keyValue = context.Request.Query["key"];

        if (!string.IsNullOrWhiteSpace(keyValue))
        {
            _db.Add(new Request()
                {
                    DT = DateTime.UtcNow, 
                    MiddlewareActivation = "SimpleInjectorActivatedMiddleware", 
                    Value = keyValue
                });

            await _db.SaveChangesAsync();
        }

        await next(context);
    }
}

Viene creata un'estensione per il middleware (Middleware/MiddlewareExtensions.cs):

public static class MiddlewareExtensions
{
    public static IApplicationBuilder UseSimpleInjectorActivatedMiddleware(
        this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<SimpleInjectorActivatedMiddleware>();
    }
}

Startup.ConfigureServices deve eseguire diverse attività:

  • Impostare il contenitore Simple Injector.
  • Registrare la factory e il middleware.
  • Rendere disponibile il contesto di database dell'app dal contenitore Simple Injector.
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

    // Replace the default middleware factory with the 
    // SimpleInjectorMiddlewareFactory.
    services.AddTransient<IMiddlewareFactory>(_ =>
    {
        return new SimpleInjectorMiddlewareFactory(_container);
    });

    // Wrap ASP.NET Core requests in a Simple Injector execution 
    // context.
    services.UseSimpleInjectorAspNetRequestScoping(_container);

    // Provide the database context from the Simple 
    // Injector container whenever it's requested from 
    // the default service container.
    services.AddScoped<AppDbContext>(provider => 
        _container.GetInstance<AppDbContext>());

    _container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();

    _container.Register<AppDbContext>(() => 
    {
        var optionsBuilder = new DbContextOptionsBuilder<DbContext>();
        optionsBuilder.UseInMemoryDatabase("InMemoryDb");
        return new AppDbContext(optionsBuilder.Options);
    }, Lifestyle.Scoped);

    _container.Register<SimpleInjectorActivatedMiddleware>();

    _container.Verify();
}

Il middleware è registrato nella pipeline di elaborazione della richiesta in Startup.Configure:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
    }

    app.UseSimpleInjectorActivatedMiddleware();

    app.UseStaticFiles();
    app.UseMvc();
}

Risorse aggiuntive