ASP.NET核心MVC路由问题

问题描述 投票:0回答:1

我正在尝试设置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 as中实现

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以获取无效路由值?

asp.net-mvc asp.net-core asp.net-core-mvc asp.net-core-2.0
1个回答
0
投票

ASP.NET Core正确地为www.test.com/fr等不匹配的URL返回404错误。这取决于浏览器如何处理这样的响应。 Firefox只显示您描述的空白页面。 IE,Chrome和Opera显示页面,其中包含错误说明,如:

enter image description here

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

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

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

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

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

查看这篇文章了解更多详情:Error Handling in ASP.NET Core

© www.soinside.com 2019 - 2024. All rights reserved.