Activation d’un intergiciel (middleware) avec un conteneur tiers dans ASP.NET Core

Cet article montre comment utiliser IMiddlewareFactory et IMiddleware comme point d’extensibilité pour l’activation d’un middleware avec un conteneur tiers. Pour une présentation de IMiddlewareFactory et de IMiddleware, consultez Activation d’un intergiciel basée sur une fabrique dans ASP.NET Core.

Affichez ou téléchargez l’exemple de code (procédure de téléchargement)

L’exemple d’application montre l’activation d’un middleware par une implémentation de IMiddlewareFactory, SimpleInjectorMiddlewareFactory. L’exemple utilise le conteneur d’injection de dépendances Simple Injector.

L’implémentation du middleware de l’exemple enregistre la valeur fournie par un paramètre de la chaîne de requête (key). Le middleware utilise un contexte de base de données injecté (un service délimité) pour enregistrer la valeur de la chaîne de requête dans une base de données en mémoire.

Notes

L’exemple d’application utilise Simple Injector seulement à des fins de démonstration. Sa simple utilisation ne constitue pas une publicité pour ce produit. Les approches de l’activation des middlewares décrites dans la documentation de Simple Injector et les problèmes GitHub sont recommandées par les développeurs de Simple Injector. Pour plus d’informations, consultez la documentation de Simple Injector et le dépôt GitHub de Simple Injector.

IMiddlewareFactory

IMiddlewareFactory fournit des méthodes pour créer un middleware.

Dans l’exemple d’application, une fabrique d’intergiciels est implémentée pour créer une instance de SimpleInjectorActivatedMiddleware. La fabrique de middleware utilise le conteneur Simple Injector pour résoudre le 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 définit le middleware pour le pipeline des requêtes de l’application.

Intergiciel activé par une implémentation 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);
    }
}

Une extension est créée pour l’intergiciel (Middleware/MiddlewareExtensions.cs) :

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

Startup.ConfigureServices doit effectuer plusieurs tâches :

  • Configurer le conteneur Simple Injector.
  • Inscrire la fabrique et le middleware.
  • Rendez le contexte de base de données de l’application disponible depuis le conteneur 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();
}

Le middleware est inscrit dans le pipeline de traitement des requêtes, dans 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();
    });
}

Cet article montre comment utiliser IMiddlewareFactory et IMiddleware comme point d’extensibilité pour l’activation d’un middleware avec un conteneur tiers. Pour une présentation de IMiddlewareFactory et de IMiddleware, consultez Activation d’un intergiciel basée sur une fabrique dans ASP.NET Core.

Affichez ou téléchargez l’exemple de code (procédure de téléchargement)

L’exemple d’application montre l’activation d’un middleware par une implémentation de IMiddlewareFactory, SimpleInjectorMiddlewareFactory. L’exemple utilise le conteneur d’injection de dépendances Simple Injector.

L’implémentation du middleware de l’exemple enregistre la valeur fournie par un paramètre de la chaîne de requête (key). Le middleware utilise un contexte de base de données injecté (un service délimité) pour enregistrer la valeur de la chaîne de requête dans une base de données en mémoire.

Notes

L’exemple d’application utilise Simple Injector seulement à des fins de démonstration. Sa simple utilisation ne constitue pas une publicité pour ce produit. Les approches de l’activation des middlewares décrites dans la documentation de Simple Injector et les problèmes GitHub sont recommandées par les développeurs de Simple Injector. Pour plus d’informations, consultez la documentation de Simple Injector et le dépôt GitHub de Simple Injector.

IMiddlewareFactory

IMiddlewareFactory fournit des méthodes pour créer un middleware.

Dans l’exemple d’application, une fabrique d’intergiciels est implémentée pour créer une instance de SimpleInjectorActivatedMiddleware. La fabrique de middleware utilise le conteneur Simple Injector pour résoudre le 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 définit le middleware pour le pipeline des requêtes de l’application.

Intergiciel activé par une implémentation 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);
    }
}

Une extension est créée pour l’intergiciel (Middleware/MiddlewareExtensions.cs) :

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

Startup.ConfigureServices doit effectuer plusieurs tâches :

  • Configurer le conteneur Simple Injector.
  • Inscrire la fabrique et le middleware.
  • Rendez le contexte de base de données de l’application disponible depuis le conteneur 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();
}

Le middleware est inscrit dans le pipeline de traitement des requêtes, dans Startup.Configure :

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

    app.UseSimpleInjectorActivatedMiddleware();

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

Ressources supplémentaires