首页 > 解决方案 > 基于端点的路由.net core 3.1中缺少端点

问题描述

我正在使用由 WebApi 和 MVC 路由组成的多租户 .net 核心 Web 应用程序。对于正常行为的应用程序应该转到后备控制器,使用外部帮助将决定哪个主/租户控制器将被执行重定向。但有时应用程序拒绝找到适当的后备动作。经过一番调查,我发现在这些时刻,并非所有端点都在注册。经过两天的搜索,我发现这些问题大部分都影响了Razor,但没有一个适用于MVC/WebApi。我开始认为这是由 .MapWhen() 的第二个分支引起的,但未得到证实。

因此,对于解决此问题的任何帮助,我将不胜感激。还将我当前的路由配置附在下面:

配置服务方法:

services.AddControllersWithViews(options =>
    {
        options.Filters.Add(typeof(ReverseProxyFilter));
        options.Conventions.Add(new ApiExplorerGroupPerVersionConvention());
    })
    .AddRazorRuntimeCompilation()
    .AddApplicationPart(typeof(EmailNamespace).Assembly)
    .AddViewLocalization()
    .SetCompatibilityVersion(CompatibilityVersion.Latest)
    .AddNewtonsoftJson(options =>
        {
        options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
        options.SerializerSettings.DateParseHandling = DateParseHandling.DateTimeOffset;
        options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
        })
    .AddControllersAsServices();

services.AddRazorPages();

services.Configure<ForwardedHeadersOptions>(options =>
    {
        options.ForwardedHeaders = ForwardedHeaders.XForwardedProto;
    });

services.Configure<RouteOptions>(routeOptions =>
    {
        routeOptions.ConstraintMap.Add("master", typeof(MasterRouteConstraint));
        routeOptions.ConstraintMap.Add("tenant", typeof(TenantRouteConstraint));
    });

配置方法:

app.UseMiddleware<TenantFilterMiddleware>();

app.UseHttpStatusCodeExceptionMiddleware();

app.UseResponseCaching();

app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
    endpoints.MapHub<WebsocketsHub>("/hubs");
    endpoints.MapControllers();
    endpoints.MapRazorPages();
});

app.MapWhen(
    context => !context.Request.Path.Value.StartsWith("/api"),
    builder =>
        {
            builder.UseRouting();
            builder.UseEndpoints(endpoints =>
            {
                endpoints.MapFallbackToController("Index", "Fallback");
            });
    });

异常示例:

An unhandled exception occurred while processing the request.
InvalidOperationException: Cannot find the fallback endpoint specified by route values: 
{ 
    action: Index,
    controller: Fallback,
    area: 
}.
Microsoft.AspNetCore.Mvc.Routing.DynamicControllerEndpointMatcherPolicy.ApplyAsync(HttpContext HttpContext, CandidateSet candidates)

标签: c#asp.net.net-coreasp.net-core-3.1

解决方案


经过两天的尝试和研究,解决方案像往常一样简单。解决这个问题的方法是稍微重写路由管道。据我所知,微软路由系统非常喜欢将分支放在默认分支之前而不是之后,在这种情况下,所有系统行为在 100% 的情况下都按预期开始工作。

所以不要这样:

app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
    endpoints.MapHub<WebsocketsHub>("/hubs");
    endpoints.MapControllers();
    endpoints.MapRazorPages();
});

app.MapWhen(
    context => !context.Request.Path.Value.StartsWith("/api"),
    builder =>
        {
            builder.UseRouting();
            builder.UseEndpoints(endpoints =>
            {
                endpoints.MapFallbackToController("Index", "Fallback");
            });
    });

现在我有这个:

app.MapWhen(context => !context.Request.Path.Value.StartsWith("/api"), ConfigureApiPipeline);

app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();

app.UseEndpoints(MapBasicEndpoints);

函数ConfigureApiPipeline()如下所示:

app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.UseEndpoints(endpoints =>
    {
        MapBasicEndpoints(endpoints);
        endpoints.MapHealthChecks(SystemLivenessCheck.Path, new HealthCheckOptions()
                {
                    AllowCachingResponses = false,
                    ResultStatusCodes = new Dictionary<HealthStatus, int>
                    {
                        [HealthStatus.Healthy] = StatusCodes.Status200OK,
                        [HealthStatus.Degraded] = StatusCodes.Status503ServiceUnavailable,
                        [HealthStatus.Unhealthy] = StatusCodes.Status503ServiceUnavailable,
                    },
                });
        endpoints.MapFallbackToController("Index", "Fallback");
    });

并且MapBasicEndpoints是:

private static void MapBasicEndpoints(IEndpointRouteBuilder endpoints)
{
    endpoints.MapHub<WebsocketsHub>("/hubs");
    endpoints.MapControllers();
}


推荐阅读