【问题标题】:Asp.net core 2.2 intercept and change route data values - url localizationAsp.net core 2.2 拦截和更改路由数据值 - url本地化
【发布时间】:2019-11-06 13:37:45
【问题描述】:

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

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

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

我不想使用属性路由来装饰控制器和动作;相反,我想捕获路由数据并基于culturecontroller/action,获取目标控制器和操作,可能与字典关联。 我已经在 asp.net (not core) mvc 中做过这样的事情。

到目前为止,我可以使用此代码捕获路由:

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


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

            await next();
        });

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

【问题讨论】:

  • 你为什么要这样做?
  • 您的自定义中间件将不起作用,因为在进入 RouteMiddleware 之前没有 RouteData(例如UseMvc())。绕过它的一种方法是创建一个路由器来映射中间件并在匹配时使用 mvc。
  • @itminus,请提供任何工作示例?

标签: asp.net-core routing


【解决方案1】:

这是一个适合我的解决方法:

// 如果路由匹配这个模式,假设: app.UseMvc(routeBuilder => { routeBuilder.MapRoute("route1",template: "/{controller=Home}/{action=Index}"); }); // 否则如果路由匹配 `{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"] 作为字符串; varculture=routeData.Values["culture"] 作为字符串; // 根据当前路由数据获取真正的后备路径 context.Request.Path = getNormalizedPath(routeData); 等待下一个(); }); appBuilder.UseRequestLocalization(); appBuilder.UseMvc(rb=>{ rb.MapRoute(name:"cultureRoute",template:template); }); }); //如果你有其他的MVC路由,在下面添加: // routeBuilder.MapRoute(name:"mvcRoutes",template: "{area:exists}/{controller=Home}/{action=Index}"); }); // else if 不匹配上面的模式,比方说: 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());
});

@ʞᴉɯ 在 cmets 中发现,第一个 UseMvc() 不适用于 2.2。我们需要将 MVC Compatibility 更改为 CompatibilityVersion.Version_2_1:

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

【讨论】:

  • 太棒了! ___谢谢
  • 尝试将其他 MVC 路由与 routeBuilder.MapRoute 一起使用,我得到“必须在 IRouteBuilder 上设置默认处理程序。”错误。
  • 如果我把第一条规则放在上面 app.UseMvc(routeBuilder => { routeBuilder.MapRoute("Blog", template: "/Blog/{page:int=1}", new {controller ="主要", 行动="博客"}); });然后调用 UseRouter 指令但不再起作用.. 404
  • @ʞᴉɯ 很抱歉再次为您提供了不正确的代码 sn-p。我测试了您的代码,发现它是由ASP.NET Core 2.2 中引入的端点路由行为引起的:如果我保留services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2),我可以重现与您相同的问题。但是如果我把它改成SetCompatibilityVersion(CompatibilityVersion.Version_2_1),文化路由器中间件对我来说就很好了。
  • @ʞᴉɯ 我已经编辑了我的答案。非常抱歉代码不正确。
猜你喜欢
  • 1970-01-01
  • 2011-11-22
  • 1970-01-01
  • 2020-02-23
  • 2016-10-22
  • 1970-01-01
  • 2018-04-15
  • 1970-01-01
  • 2017-01-08
相关资源
最近更新 更多