ASP.NET Core 2.2拦截和更改路由数据值-网址本地化

时间:2019-06-24 18:02:51

标签: asp.net-core routing

在asp.net core 2.2中是否可以针对每个请求截取路由数据并(可能)更改值,例如目标controller / action的值?

我需要使用具有两个字母区域性规范和本地化控制器/动作名称的本地化url方案,例如:

/en/contact-us
/it/contatti
/de/kontakte

我不想使用属性路由来装饰控制器和动作;相反,我想捕获路线数据并以culturecontroller/action为基础,也许与词典关联一起获得目标控制器和动作。 我已经在asp.net(不是核心)mvc中完成了此类操作。

直到现在,我都可以使用以下代码捕获路由:

        app.Use(async (context, next) =>
        {
            var routeData = context.GetRouteData();


            routeData.Values["controller"] = ....;
            routeData.Values["action"] = .....;

            await next();
        });

,但仅对精确映射到现有控制器/动作的url填充路由数据,否则为null;看来这是由于asp.net核心的AttributeRouting.CreateAttributeMegaRoute方法所致,它仅映射现有的控制器/动作。

1 个答案:

答案 0 :(得分:1)

以下是对我有用的解决方案:

// if the route matches this pattern, let's say:
app.UseMvc(routeBuilder => {
    routeBuilder.MapRoute("route1",template: "/{controller=Home}/{action=Index}");
});

// else if the route matches `{culture=en-US}/{controller=Home}/{action=Index}`
app.UseRouter(routeBuilder =>{
    var template = "{culture=en-US}/{controller=Home}/{action=Index}";
    routeBuilder.MapMiddlewareRoute(template, appBuilder =>{
        appBuilder.Use(async(context, next)=>{
            var routeData = context.GetRouteData();
            var controller = routeData.Values["controller"] as string;
            var action= routeData.Values["action"] as string;
            var culture= routeData.Values["culture"] as string;
            // get the real backing path according to current route data
            context.Request.Path = getNormalizedPath(routeData);  
            await next();
        });
        appBuilder.UseRequestLocalization();
        appBuilder.UseMvc(rb=>{
            rb.MapRoute(name:"cultureRoute",template:template);
        });
    });
    // if you have other MVC routes, add them below:
    // routeBuilder.MapRoute(name:"mvcRoutes",template: "{area:exists}/{controller=Home}/{action=Index}");
});

// else if doesn't match the above pattern, let's say:
app.UseMvc(routeBuilder => {
    routeBuilder.MapRoute("route3",template: "/test/mvc/{controller=Home}/{action=Index}");
});
private string getNormalizedPath(RouteData routeData)
{
    var culture= routeData.Values["culture"] as string;
    var controller = routeData.Values["controller"] as string;
    var action= routeData.Values["action"] as string;

    controller = ... real controller according to current culture & controller string
    action = ... real action according to current culture & controller string
    return $"/{culture}/{controller}/{action}";
}

您需要自定义getNormalizedPath(routeData)才能获取将被路由到后备控制器/操作的真实路径。

要同时根据当前路径自动设置“请求本地化功能”,您需要插入RouteDataRequestCultureProvider

services.Configure<RequestLocalizationOptions>(options =>
{
    var supportedCultures = new[]{
        new CultureInfo("en"),
        new CultureInfo("fr"),
        new CultureInfo("de"),
        new CultureInfo("it"),
    };
    options.SupportedCultures = supportedCultures;
    options.SupportedUICultures = supportedCultures;
    options.RequestCultureProviders.Insert(0, new RouteDataRequestCultureProvider());
});

@ʞᴉɯ在评论中发现,第一个UseMvc()在2.2版本中效果不佳。我们需要将MVC兼容性更改为CompatibilityVersion.Version_2_1

services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);