Activación de middleware con un contenedor de terceros en ASP.NET Core

En este artículo se explica cómo usar IMiddlewareFactory y IMiddleware como un punto de extensibilidad para la activación de middleware con un contenedor de terceros. Para información general sobre IMiddlewareFactory e IMiddleware, consulte Activación de middleware basada en fábrica en ASP.NET Core.

Vea o descargue el código de ejemplo (cómo descargarlo)

En la aplicación de ejemplo se muestra una activación de middleware por medio de una implementación de IMiddlewareFactory, SimpleInjectorMiddlewareFactory. En el ejemplo se usa el contenedor de inserción de dependencias Simple Injector.

La implementación de middleware del ejemplo registra el valor proporcionado por un parámetro de cadena de consulta (key). El middleware usa un contexto de base de datos insertado (un servicio con ámbito) para registrar el valor de cadena de consulta en una base de datos en memoria.

Nota:

En la aplicación de ejemplo se usa Simple Injector única y exclusivamente con fines de demostración. El uso de Simple Injector no está avalado. Los métodos de activación de middleware descritos en la documentación de Simple Injector y los problemas de GitHub está recomendado por los responsables de Simple Injector. Para más información, vea la documentación de Simple Injector y el repositorio de GitHub de Simple Injector.

IMiddlewareFactory

IMiddlewareFactory proporciona métodos para crear middleware.

En la aplicación de ejemplo, se implementa un Middleware Factory para crear una instancia de SimpleInjectorActivatedMiddleware. Ese Middleware Factory usa el contenedor de Simple Injector para resolver el 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 define el middleware para la canalización de solicitudes de la aplicación.

Middleware activado por una implementación de 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);
    }
}

Se crea una extensión para el middleware (Middleware/MiddlewareExtensions.cs):

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

Startup.ConfigureServices debe realizar varias tareas:

  • Configurar el contenedor de Simple Injector.
  • Registrar tanto el Factory como el Middleware.
  • Poner disponible el contexto de base de datos de la aplicación en el contenedor de 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();
}

El middleware se registra en la canalización de procesamiento de solicitudes en 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();
    });
}

En este artículo se explica cómo usar IMiddlewareFactory y IMiddleware como un punto de extensibilidad para la activación de middleware con un contenedor de terceros. Para información general sobre IMiddlewareFactory e IMiddleware, consulte Activación de middleware basada en fábrica en ASP.NET Core.

Vea o descargue el código de ejemplo (cómo descargarlo)

En la aplicación de ejemplo se muestra una activación de middleware por medio de una implementación de IMiddlewareFactory, SimpleInjectorMiddlewareFactory. En el ejemplo se usa el contenedor de inserción de dependencias Simple Injector.

La implementación de middleware del ejemplo registra el valor proporcionado por un parámetro de cadena de consulta (key). El middleware usa un contexto de base de datos insertado (un servicio con ámbito) para registrar el valor de cadena de consulta en una base de datos en memoria.

Nota:

En la aplicación de ejemplo se usa Simple Injector única y exclusivamente con fines de demostración. El uso de Simple Injector no está avalado. Los métodos de activación de middleware descritos en la documentación de Simple Injector y los problemas de GitHub está recomendado por los responsables de Simple Injector. Para más información, vea la documentación de Simple Injector y el repositorio de GitHub de Simple Injector.

IMiddlewareFactory

IMiddlewareFactory proporciona métodos para crear middleware.

En la aplicación de ejemplo, se implementa un Middleware Factory para crear una instancia de SimpleInjectorActivatedMiddleware. Ese Middleware Factory usa el contenedor de Simple Injector para resolver el 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 define el middleware para la canalización de solicitudes de la aplicación.

Middleware activado por una implementación de 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);
    }
}

Se crea una extensión para el middleware (Middleware/MiddlewareExtensions.cs):

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

Startup.ConfigureServices debe realizar varias tareas:

  • Configurar el contenedor de Simple Injector.
  • Registrar tanto el Factory como el Middleware.
  • Poner disponible el contexto de base de datos de la aplicación en el contenedor de 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();
}

El middleware se registra en la canalización de procesamiento de solicitudes en Startup.Configure:

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

    app.UseSimpleInjectorActivatedMiddleware();

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

Recursos adicionales