web-dev-qa-db-fra.com

L'ajout de middleware personnalisé ne fonctionne pas lors de l'utilisation d'IMiddleware

J'essaie d'ajouter un middleware personnalisé au pipeline (pour être plus facile, je choisirai l'exemple de documentation .NET Core). Disons que nous voulons que la culture espagnole soit définie chaque fois qu'un appel à l'API est déclenché. Voici le code qui fonctionne parfaitement:

public class RequestCultureMiddleware
{
    private readonly RequestDelegate _next;

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

    public async Task InvokeAsync(HttpContext context)
    {
        CultureInfo.CurrentCulture = new CultureInfo("es-ES");
        CultureInfo.CurrentUICulture = new CultureInfo("es-ES");

        // Call the next delegate/middleware in the pipeline
        await _next(context);
    }
}

public static class RequestCultureMiddlewareExtensions
{
    public static IApplicationBuilder UseRequestCulture(
        this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<RequestCultureMiddleware>();
    }
}

et la classe Startup:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        //here is our custom middleware!
        app.UseRequestCulture();

        app.UseHttpsRedirection();

        app.UseRouting();

        app.UseAuthorization();

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

C'est bien, mais comme vous pouvez le voir, RequestCultureMiddleware n'implémente pas d'interface ou de classe de base/classe abstraite. Vous devez juste vous souvenir lors de la définition d'un middleware pour créer un constructeur qui reçoit le middleware suivant et vous devez également créer une méthode appelée spécifiquement "InvokeAsync" avec "HttpContext" comme paramètre.

J'ai essayé de trouver un contrat ... une classe de base ou une interface et devinez quoi, nous avons "IMiddleware" qui fait partie de "Microsoft.AspNetCore.Http" Assembly. Wow, c'est parfait. Mettons-le en œuvre.

L'interface ressemble à ceci:

namespace Microsoft.AspNetCore.Http
{
    //
    // Summary:
    //     Defines middleware that can be added to the application's request pipeline.
    public interface IMiddleware
    {
        //
        // Summary:
        //     Request handling method.
        //
        // Parameters:
        //   context:
        //     The Microsoft.AspNetCore.Http.HttpContext for the current request.
        //
        //   next:
        //     The delegate representing the remaining middleware in the request pipeline.
        //
        // Returns:
        //     A System.Threading.Tasks.Task that represents the execution of this middleware.
        Task InvokeAsync(HttpContext context, RequestDelegate next);
    }
}

Et voici la mise en œuvre:

    public class RequestCultureMiddleware : IMiddleware
    {

        public Task InvokeAsync(HttpContext context, RequestDelegate next)
        {
            CultureInfo.CurrentCulture = new CultureInfo("es-ES");
            CultureInfo.CurrentUICulture = new CultureInfo("es-ES");

            // Call the next delegate/middleware in the pipeline
            return next(context);
        }
    }


    public static class RequestCultureMiddlewareExtensions
    {
        public static IApplicationBuilder UseRequestCulture(
            this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<RequestCultureMiddleware>();
        }
    }
}

Mais, lors de l'exécution de l'API, j'obtiens l'erreur suivante au moment de l'exécution:

System.InvalidOperationException: No service for type 'WebApplication1.RequestCultureMiddleware' has been registered.
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.AspNetCore.Http.MiddlewareFactory.Create(Type middlewareType)
   at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass5_1.<<UseMiddlewareInterface>b__1>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

Comment exactement je suis censé enregistrer ce middleware si ce n'est en utilisant l'extension "UseMiddleware"? Merci.

7
Dragos Stoica

Je suis sûr que ce problème a été résolu il y a longtemps après 5 mois, mais j'écris ce conseil au cas où.

Le problème est que la méthode "InvokeAsync" de votre programme middleware personnalisé n'est pas exécutée même si vous l'avez intégrée dans la méthode "Configure" de Startup.

J'ai eu le même problème l'autre jour et je l'ai résolu, mais j'ai mis du code intégré juste avant la méthode app.UseEndpoints.

dans ton cas

app.UseAuthorization();
app.UseRequestCulture();  // <- this way.
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
});

À propos, si vous le placez après la méthode app.UseEndpoints, le constructeur sera appelé, mais la méthode InvokeAsync ne sera pas exécutée.

0
Masatoshi Furuya