Attivazione del middleware basata su factory in ASP.NET Core

IMiddlewareFactory/IMiddleware è un punto di estendibilità per l'attivazione middleware che offre i vantaggi seguenti:

  • Attivazione per ogni richiesta client (inserimento di servizi con ambito)
  • Tipizzazione forte del middleware

I metodi di estensione UseMiddleware verificano se il tipo registrato del middleware implementa IMiddleware. In caso affermativo, viene usata l'istanza di IMiddlewareFactory registrata nel contenitore per risolvere l'implementazione IMiddleware, invece di usare la logica di attivazione del middleware basata sulle convenzioni. Il middleware è registrato come un servizio con ambito o temporaneo nel contenitore dei servizi dell'app.

IMiddleware viene attivato per ogni richiesta client (connessione), in modo che i servizi con ambito possano essere inseriti nel costruttore del middleware.

IMiddleware

IMiddleware definisce il middleware per la pipeline di richieste dell'app. Il metodo InvokeAsync(HttpContext, RequestDelegate) gestisce le richieste e restituisce un oggetto Task che rappresenta l'esecuzione del middleware.

Middleware attivato da convenzione:

public class ConventionalMiddleware
{
    private readonly RequestDelegate _next;

    public ConventionalMiddleware(RequestDelegate next)
        => _next = next;

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

        if (!string.IsNullOrWhiteSpace(keyValue))
        {
            dbContext.Requests.Add(new Request("Conventional", keyValue));

            await dbContext.SaveChangesAsync();
        }

        await _next(context);
    }
}

Middleware attivato da MiddlewareFactory:

public class FactoryActivatedMiddleware : IMiddleware
{
    private readonly SampleDbContext _dbContext;

    public FactoryActivatedMiddleware(SampleDbContext dbContext)
        => _dbContext = dbContext;

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

        if (!string.IsNullOrWhiteSpace(keyValue))
        {
            _dbContext.Requests.Add(new Request("Factory", keyValue));

            await _dbContext.SaveChangesAsync();
        }

        await next(context);
    }
}

Le estensioni vengono create per il middleware:

public static class MiddlewareExtensions
{
    public static IApplicationBuilder UseConventionalMiddleware(
        this IApplicationBuilder app)
        => app.UseMiddleware<ConventionalMiddleware>();

    public static IApplicationBuilder UseFactoryActivatedMiddleware(
        this IApplicationBuilder app)
        => app.UseMiddleware<FactoryActivatedMiddleware>();
}

Non è possibile passare gli oggetti al middleware attivato da factory con UseMiddleware:

public static IApplicationBuilder UseFactoryActivatedMiddleware(
    this IApplicationBuilder app, bool option)
{
    // Passing 'option' as an argument throws a NotSupportedException at runtime.
    return app.UseMiddleware<FactoryActivatedMiddleware>(option);
}

Il middleware attivato da factory viene aggiunto al contenitore predefinito in Program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<SampleDbContext>
    (options => options.UseInMemoryDatabase("SampleDb"));

builder.Services.AddTransient<FactoryActivatedMiddleware>();

Entrambi i middleware vengono registrati nella pipeline di elaborazione delle richieste, anche in Program.cs:

var app = builder.Build();

app.UseConventionalMiddleware();
app.UseFactoryActivatedMiddleware();

IMiddlewareFactory

IMiddlewareFactory specifica i metodi per creare il middleware. L'implementazione del middleware basata su factory viene registrata nel contenitore come un servizio con ambito.

L'implementazione predefinita di IMiddlewareFactory, MiddlewareFactory, è presente nel pacchetto Microsoft.AspNetCore.Http.

Risorse aggiuntive

IMiddlewareFactory/IMiddleware è un punto di estendibilità per l'attivazione del middleware.

I metodi di estensione UseMiddleware verificano se il tipo registrato del middleware implementa IMiddleware. In caso affermativo, viene usata l'istanza di IMiddlewareFactory registrata nel contenitore per risolvere l'implementazione IMiddleware, invece di usare la logica di attivazione del middleware basata sulle convenzioni. Il middleware è registrato come un servizio con ambito o temporaneo nel contenitore dei servizi dell'app.

Vantaggi:

  • Attivazione per ogni richiesta client (inserimento di servizi con ambito)
  • Tipizzazione forte del middleware

IMiddleware viene attivato per ogni richiesta client (connessione), in modo che i servizi con ambito possano essere inseriti nel costruttore del middleware.

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

IMiddleware

IMiddleware definisce il middleware per la pipeline di richieste dell'app. Il metodo InvokeAsync(HttpContext, RequestDelegate) gestisce le richieste e restituisce un oggetto Task che rappresenta l'esecuzione del middleware.

Middleware attivato da convenzione:

public class ConventionalMiddleware
{
    private readonly RequestDelegate _next;

    public ConventionalMiddleware(RequestDelegate next)
    {
        _next = next;
    }

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

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

            await db.SaveChangesAsync();
        }

        await _next(context);
    }
}

Middleware attivato da MiddlewareFactory:

public class FactoryActivatedMiddleware : IMiddleware
{
    private readonly AppDbContext _db;

    public FactoryActivatedMiddleware(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 = "FactoryActivatedMiddleware", 
                    Value = keyValue
                });

            await _db.SaveChangesAsync();
        }

        await next(context);
    }
}

Le estensioni vengono create per il middleware:

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

    public static IApplicationBuilder UseFactoryActivatedMiddleware(
        this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<FactoryActivatedMiddleware>();
    }
}

Non è possibile passare gli oggetti al middleware attivato da factory con UseMiddleware:

public static IApplicationBuilder UseFactoryActivatedMiddleware(
    this IApplicationBuilder builder, bool option)
{
    // Passing 'option' as an argument throws a NotSupportedException at runtime.
    return builder.UseMiddleware<FactoryActivatedMiddleware>(option);
}

Il middleware attivato da factory viene aggiunto al contenitore predefinito in Startup.ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<AppDbContext>(options =>
        options.UseInMemoryDatabase("InMemoryDb"));

    services.AddTransient<FactoryActivatedMiddleware>();

    services.AddRazorPages();
}

Entrambi i middleware vengono registrati nella pipeline di elaborazione delle richieste in Startup.Configure:

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

    app.UseConventionalMiddleware();
    app.UseFactoryActivatedMiddleware();

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

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

IMiddlewareFactory

IMiddlewareFactory specifica i metodi per creare il middleware. L'implementazione del middleware basata su factory viene registrata nel contenitore come un servizio con ambito.

L'implementazione predefinita di IMiddlewareFactory, MiddlewareFactory, è presente nel pacchetto Microsoft.AspNetCore.Http.

Risorse aggiuntive

IMiddlewareFactory/IMiddleware è un punto di estendibilità per l'attivazione del middleware.

I metodi di estensione UseMiddleware verificano se il tipo registrato del middleware implementa IMiddleware. In caso affermativo, viene usata l'istanza di IMiddlewareFactory registrata nel contenitore per risolvere l'implementazione IMiddleware, invece di usare la logica di attivazione del middleware basata sulle convenzioni. Il middleware è registrato come un servizio con ambito o temporaneo nel contenitore dei servizi dell'app.

Vantaggi:

  • Attivazione per ogni richiesta client (inserimento di servizi con ambito)
  • Tipizzazione forte del middleware

IMiddleware viene attivato per ogni richiesta client (connessione), in modo che i servizi con ambito possano essere inseriti nel costruttore del middleware.

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

IMiddleware

IMiddleware definisce il middleware per la pipeline di richieste dell'app. Il metodo InvokeAsync(HttpContext, RequestDelegate) gestisce le richieste e restituisce un oggetto Task che rappresenta l'esecuzione del middleware.

Middleware attivato da convenzione:

public class ConventionalMiddleware
{
    private readonly RequestDelegate _next;

    public ConventionalMiddleware(RequestDelegate next)
    {
        _next = next;
    }

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

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

            await db.SaveChangesAsync();
        }

        await _next(context);
    }
}

Middleware attivato da MiddlewareFactory:

public class FactoryActivatedMiddleware : IMiddleware
{
    private readonly AppDbContext _db;

    public FactoryActivatedMiddleware(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 = "FactoryActivatedMiddleware", 
                    Value = keyValue
                });

            await _db.SaveChangesAsync();
        }

        await next(context);
    }
}

Le estensioni vengono create per il middleware:

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

    public static IApplicationBuilder UseFactoryActivatedMiddleware(
        this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<FactoryActivatedMiddleware>();
    }
}

Non è possibile passare gli oggetti al middleware attivato da factory con UseMiddleware:

public static IApplicationBuilder UseFactoryActivatedMiddleware(
    this IApplicationBuilder builder, bool option)
{
    // Passing 'option' as an argument throws a NotSupportedException at runtime.
    return builder.UseMiddleware<FactoryActivatedMiddleware>(option);
}

Il middleware attivato da factory viene aggiunto al contenitore predefinito in Startup.ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<AppDbContext>(options =>
        options.UseInMemoryDatabase("InMemoryDb"));

    services.AddTransient<FactoryActivatedMiddleware>();

    services.AddMvc()
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

Entrambi i middleware vengono registrati nella pipeline di elaborazione delle richieste in Startup.Configure:

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

    app.UseConventionalMiddleware();
    app.UseFactoryActivatedMiddleware();

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

IMiddlewareFactory

IMiddlewareFactory specifica i metodi per creare il middleware. L'implementazione del middleware basata su factory viene registrata nel contenitore come un servizio con ambito.

L'implementazione predefinita di IMiddlewareFactory, MiddlewareFactory, è presente nel pacchetto Microsoft.AspNetCore.Http.

Risorse aggiuntive