Asp.net 核心 2.2 拦截和更改路由数据值 - url 本地化
Asp.net core 2.2 intercept and change route data values - url localization
在 asp.net 核心 2.2 中是否有可能为每个请求拦截路由数据并(可能)更改值,例如目标 controller
/ action
值?
我需要使用本地化的 url 方案,包含两个字母的文化规范和本地化的控制器/操作名称,例如:
/en/contact-us
/it/contatti
/de/kontakte
我不想使用属性路由来装饰控制器和动作;相反,我想捕获路由数据并基于 culture
和 controller/action
,获取目标控制器和操作,可能与字典关联。
我已经在 asp.net(非核心)mvc 中做过这样的事情。
到目前为止,我可以使用以下代码捕获路由:
app.Use(async (context, next) =>
{
var routeData = context.GetRouteData();
routeData.Values["controller"] = ....;
routeData.Values["action"] = .....;
await next();
});
但仅针对精确映射到现有 controller/action 的 url 填充路由数据,否则为空;这似乎是由于 asp.net 核心的 AttributeRouting.CreateAttributeMegaRoute
方法,它只映射现有的 controllers/actions.
这是适合我的解决方法:
// 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)
以获得将路由到支持 controller/action 的真实路径。
同时根据当前路由路径自动设置请求本地化功能,需要插入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);
在 asp.net 核心 2.2 中是否有可能为每个请求拦截路由数据并(可能)更改值,例如目标 controller
/ action
值?
我需要使用本地化的 url 方案,包含两个字母的文化规范和本地化的控制器/操作名称,例如:
/en/contact-us
/it/contatti
/de/kontakte
我不想使用属性路由来装饰控制器和动作;相反,我想捕获路由数据并基于 culture
和 controller/action
,获取目标控制器和操作,可能与字典关联。
我已经在 asp.net(非核心)mvc 中做过这样的事情。
到目前为止,我可以使用以下代码捕获路由:
app.Use(async (context, next) =>
{
var routeData = context.GetRouteData();
routeData.Values["controller"] = ....;
routeData.Values["action"] = .....;
await next();
});
但仅针对精确映射到现有 controller/action 的 url 填充路由数据,否则为空;这似乎是由于 asp.net 核心的 AttributeRouting.CreateAttributeMegaRoute
方法,它只映射现有的 controllers/actions.
这是适合我的解决方法:
// 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)
以获得将路由到支持 controller/action 的真实路径。
同时根据当前路由路径自动设置请求本地化功能,需要插入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);