.NET Core 5 中间件 InvokeAsync 未触发

.NET Core 5 middleware InvokeAsync not triggered

我有一个使用 .NET Core 2.2 中间件的后端解决方案,我将其更新为 .NET Core 5,但不再触发 InvokeAsync 方法。

这是我的代码:

启动(在配置服务中):

app.UseMiddleware<ValidRouteMiddleware>();
app.UseMiddleware<ValidNuisAlgoTokenAndAdminMiddleware>();
app.UseMiddleware<CheckIdChantierDefaultMiddleware>();
app.UseMiddleware<ValidationCatcherMiddleware>();

有效路由中间件:

public class ValidRouteMiddleware
{
    private readonly ILogger<ValidRouteMiddleware> _logger;
    private const string BadRouteErrorMessage = "Hello World d~.~b";
    private readonly RequestDelegate _next;
    private readonly List<string> _allRoutes;

    public ValidRouteMiddleware(RequestDelegate next, ILogger<ValidRouteMiddleware> logger,
       IActionDescriptorCollectionProvider actionDescriptorCollectionProvider)
    {
        _next = next;
        _logger = logger;
        ....
    }

    public async Task InvokeAsync(HttpContext context)
    {
        if (!MiddlewareTools.CheckRoute(context,_allRoutes))
        {
            _...
            return;
        }
        else
        {
            await _next.Invoke(context);
        }
    }
}

CheckIdChantierDefaultMiddleware:

    public class CheckIdChantierDefaultMiddleware
    {
        private readonly ILogger<CheckIdChantierDefaultMiddleware> _logger;
        private const string UnauthorizedErrorMessage = "Non autorisé";
        private readonly RequestDelegate _next;
        private readonly List<string> _excludedRoutes;

        public CheckIdChantierDefaultMiddleware(RequestDelegate next, ILogger<CheckIdChantierDefaultMiddleware> logger,
            IActionDescriptorCollectionProvider actionDescriptorCollectionProvider)
        {
            _next = next;
            ...
        }

        public async Task InvokeAsync(HttpContext context, ComInDbContext dbContext)
        {
        }
    }

等...

缺少什么?

此致

注:整个Startup/ConfigureServices

public void Configure(IApplicationBuilder app, IHostApplicationLifetime appLifetime, IWebHostEnvironment env, ILogger<Startup> logger)
{
    Logger = logger;
    Logger.LogInformation($"Environnement d'exécution : {Environment.EnvironmentName}");

    appLifetime.ApplicationStarted.Register(OnApplicationStarted);
    appLifetime.ApplicationStopping.Register(OnApplicationStopping);
    appLifetime.ApplicationStopped.Register(OnApplicationStopped);

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
    }

    // Pour la génération des PDFs, on doit injecter la lib en 32 ou 64
    var wkHtmlToPdfContext = new CustomAssemblyLoadContext();
    var architectureFolder = (IntPtr.Size == 8) ? "64 bits" : "32 bits";
    // Folder dans Infrastructure.PDF
    var wkHtmlToPdfPath = Path.Combine(AppContext.BaseDirectory, $"libwkhtmltox\{architectureFolder}\libwkhtmltox");
    wkHtmlToPdfContext.LoadUnmanagedLibrary(wkHtmlToPdfPath);

    app.UseRouting();

    // Utilisation de la règle du CORS
    Logger.LogInformation($"Application de la règle `{filteredOrigin}` pour le CORS");
    app.UseCors(filteredOrigin);

    // Swagger uniquement en DEV
    if (Environment.EnvironmentName == "Development" || Environment.EnvironmentName == "PreProduction")
    {
        // Active Swagger
        Logger.LogInformation($"Activation de Swagger (sur l'URL \"/swagger\") ...");
        app.UseSwagger();
        app.UseSwaggerUI(c =>
        {
            c.SwaggerEndpoint("/swagger/v1/swagger.json", "Swagger - Administration API");
            c.RoutePrefix = String.Empty;
        });
    }

    // Active les signaux de HealthCheck sur l'url de routage "/health"
    Logger.LogInformation($"Activation des HealthCheck (sur l'URL \"/health\") ...");
    // Active le pipeline d'Endpoints
    Logger.LogInformation($"Activation du pipeline d'Endpoints ...");
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
        endpoints.MapHealthChecks("/health",
            new HealthCheckOptions
            {
                ResponseWriter = async (context, report) =>
                {
                    var result = JsonSerializer.Serialize(
                        new
                        {
                            status = report.Status.ToString(),
                            errors = report.Entries.Select(e => new { key = e.Key, value = Enum.GetName(typeof(HealthStatus), e.Value.Status) })
                        });
                    context.Response.ContentType = MediaTypeNames.Application.Json;
                    await context.Response.WriteAsync(result, context.RequestAborted);
                }
            });
    });

    app.UseHttpsRedirection();

    #region Middleware

    // Active le middleware pour la vérification des headers
    app.UseMiddleware<ValidRouteMiddleware>();
    app.UseMiddleware<ValidNuisAlgoTokenAndAdminMiddleware>();
    app.UseMiddleware<CheckIdChantierDefaultMiddleware>();
    app.UseMiddleware<ValidationCatcherMiddleware>();

    #endregion Middleware
}

我在这里写了一个简单的demo。首先我在startup中的Configure方法中创建了一个自定义中间件并在endpoint之前注册了它,然后你可以看到InvokeAsync触发成功

当我在 endpoint 之后注册中间件时,InvokeAsync 不会被触发。

Panagiotis Kanavos 已经解释了 Endpoint 或者您可以阅读 this 关于路由 Asp .net core 5

我怀疑这段代码是否在 .NET Core 2 中有效。中间件按照请求的注册顺序阻止处理请求。 ASP.NET Core 中的所有内容都是一个中间件块,包括 HTTPS、身份验证、CORS、控制器支持、路由、端点,端点充当中间件链中的 last 步骤。

永远不会调用端点之后注册的任何内容。这包括自定义中间件 HTTPS 重定向步骤。

ASP.NET Core middleware page in the docs explains how middleware works and the correct middleware order

至少你需要在 if (env.IsDevelopment()) 块之后放置 UseHttpsRedirection,并在 UseEndpoints.

之前注册你的自定义中间件

我建议创建一个新的 ASP.NET 核心 MVC 应用程序并检查代码。中间件的顺序已经正确。

.NET Core LTS 版本

您还应该考虑跳过 .NET 5 并直接进入 .NET 6。.NET 5 是一个短期版本,达到 End-Of-Life in May 2022。 Long-Term-Support 版本为 .NET 6,将支持到 2024 年 11 月。

从 .NET 5 迁移到 .NET 6 可能就像将目标从 net6.0 更改为 net5.0 并升级 NuGet 包一样简单。另一方面,从新的最小 MVC 模板开始可以显着减少启动代码,从而减少出现此类错误的机会。

再次尝试创建一个新的空 MVC 网络应用程序并检查生成的代码。

middleware doc page 显示了一个 .NET 6 示例,其中所有程序和 Startup.cs 代码都合并到 Program.cs 中。在问题的情况下,自定义中间件将添加在控制器和 Razor 页面中间件之前。

...
app.UseHttpsRedirection();
app.UseStaticFiles();
// app.UseCookiePolicy();

app.UseRouting();
// app.UseRequestLocalization();
// app.UseCors();

app.UseAuthentication();
app.UseAuthorization();
// app.UseSession();
// app.UseResponseCompression();
// app.UseResponseCaching();

    app.UseMiddleware<ValidRouteMiddleware>();
    app.UseMiddleware<ValidNuisAlgoTokenAndAdminMiddleware>();
    app.UseMiddleware<CheckIdChantierDefaultMiddleware>();
    app.UseMiddleware<ValidationCatcherMiddleware>();


app.MapRazorPages();
app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

Write Custom ASP.NET Core Middleware讲解如何编写中间件和调用中间件

Panagiotis 让我找到解决方案, 我必须在端点之前调用中间件,并且调用被触发。

谢谢大家