繁体   English   中英

ASP.NET Core MVC路由问题

[英]ASP.NET Core MVC Route issue

我正在尝试设置一个ASP.NET Core MVC网站,以支持多个国家/地区的多语种,例如:

  • www.test.com/au/en(澳大利亚,英语)
  • www.test.com/au/de(澳大利亚,德国)

为了为当前用户设置区域性,我找到了以下代码

public static class GetRoutesMiddlewareExtensions
{
    public static IApplicationBuilder UseGetRoutesMiddleware(this IApplicationBuilder app, Action<IRouteBuilder> configureRoutes)
    {
        if (app == null)
        {
            throw new ArgumentNullException(nameof(app));
        }

        var routes = new RouteBuilder(app)
        {
            DefaultHandler = app.ApplicationServices.GetRequiredService<MvcRouteHandler>(),
        };
        configureRoutes(routes);
        routes.Routes.Insert(0, AttributeRouting.CreateAttributeMegaRoute(app.ApplicationServices));
        var router = routes.Build();

        return app.UseMiddleware<GetRoutesMiddleware>(router);
    }
}

public class GetRoutesMiddleware
{
    private readonly RequestDelegate next;
    private readonly IRouter _router;

    public GetRoutesMiddleware(RequestDelegate next, IRouter router)
    {
        this.next = next;
        _router = router;
    }

    public async Task Invoke(HttpContext httpContext)
    {
        var context = new RouteContext(httpContext);
        context.RouteData.Routers.Add(_router);

        await _router.RouteAsync(context);

        if (context.Handler != null)
        {
            httpContext.Features[typeof(IRoutingFeature)] = new RoutingFeature()
            {
                RouteData = context.RouteData,
            };
        }

        // proceed to next...
        await next(httpContext);
    }
}

我创建了一个如下所示的RequestCultureProvider:

public class RequestCultureProvider : IRequestCultureProvider
{
    public Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext httpContext)
    {
        if (httpContext.GetRouteValue("language") == null)
        {
            return Task.FromResult(new ProviderCultureResult("en", "en"));
        }
        var langauge = httpContext.GetRouteValue("language").ToString().ToLower();
        return Task.FromResult(new ProviderCultureResult(langauge, langauge));
    }
}

要设置路由,我可以使用以下方法:

private readonly Action<IRouteBuilder> GetRoutes =
    routes =>
    {
        routes.MapRoute(name: "Default",
                        template: "{area}/{language}/{controller}/{action}",
                        defaults: new { area = "au", language = "en", controller = "home", action = "Index" },
                        constraints: new { area = new RequiredRouteConstraint(), language = new RegexRouteConstraint("^(en|de)$")  });
    };

然后在Startup.cs的Configure中,我有

// setup routes
app.UseGetRoutesMiddleware(GetRoutes);
// add localization
var supportedCultures = new List<CultureInfo>() {
                new CultureInfo("en"),
                new CultureInfo("de"),
            };

var requestLocalizationOptions = new RequestLocalizationOptions
{
    DefaultRequestCulture = new RequestCulture(supportedCultures.First()),
    SupportedCultures = supportedCultures,
    SupportedUICultures = supportedCultures,
};
requestLocalizationOptions.RequestCultureProviders.Clear();
requestLocalizationOptions.RequestCultureProviders.Add(
    new RequestCultureProvider()
);
app.UseRequestLocalization(requestLocalizationOptions);

我不确定它是否相关,但是为了以一种更有条理的方式布局视图,我设置了一个CultureViewExpander,如下所示:

public class CultureViewExpander : IViewLocationExpander
{
    public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
    {
        return viewLocations.Select(s => s.Replace("%1", CultureInfo.CurrentUICulture.TwoLetterISOLanguageName));
    }

    public void PopulateValues(ViewLocationExpanderContext context)
    {
        context.Values.Add("Language", CultureInfo.CurrentUICulture.TwoLetterISOLanguageName);
    }
}

它在Startup.cs中的ConfigureServices中实现为

services.Configure<RazorViewEngineOptions>(o =>
{
    o.ViewLocationExpanders.Add(new CultureViewExpander());

    // {0} for the action
    // {1} for the controller
    // {2} for the area
    // %1 for language
    o.ViewLocationFormats.Clear();
    o.ViewLocationFormats.Add("/Views/Shared/{0}" + RazorViewEngine.ViewExtension);

    o.AreaViewLocationFormats.Clear();
    o.AreaViewLocationFormats.Insert(0, "/Areas/{2}/Views/{1}/%1/{0}" + RazorViewEngine.ViewExtension);
});

支持的语言可以正常工作,但是当我导航到www.test.com/au/fr时,我只是得到一个空白屏幕,但是我需要它返回404。如何获取它以针对无效路线返回404值?

对于不匹配的URL(如www.test.com/fr Core正确返回404错误。 取决于浏览器如何处理这种响应。 Firefox仅显示您所描述的空白页。 IE,Chrome和Opera显示页面带有错误描述,例如:

在此处输入图片说明

当应返回错误代码时,可以自定义ASP.NET Core行为。 您可以通过将UseStatusCodePages添加到应用程序配置中来使用简单的文本消息:

app.UseStatusCodePages("text/plain", "Status code page, status code: {0}");

如果请求失败,您也可以将用户重定向到自定义错误页面:

app.UseStatusCodePagesWithRedirects("/error/{0}");

确保正确解析了路径/error/404 ,否则您将无限重定向至此页面。

检查本文以获取更多详细信息: ASP.NET Core中的错误处理

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM