从操作过滤器属性重定向时,路由表中的无路由与提供的值匹配

时间:2018-01-18 10:07:54

标签: c# asp.net-mvc asp.net-mvc-5 asp.net-mvc-routing

我在我的网络应用程序上有3种语言的本地化,方案是:当用户打开页面时,URL example.com但我想将它设为example.com/en。

我正在尝试使用RedirectToRouteResult来实现它,但在第一次尝试打开页面时,我收到错误。我从这个article

中采用了这种机制

我尝试实现此目的的主要原因是用户级别定义的文化信息,因此当来自一个国家/地区的用户设置他/她的语言时,他/她不必每次都重新执行此操作他们进入页面的时间,因为我将数据存储在缓存和数据库中; 并且OutputCache因此当有人进入页面时,他们不会面对其他用户呈现的页面,这可能不是新用户的默认语言。

public class InternationalizationAttribute : ActionFilterAttribute {
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
    // This is a dummy constraint, if the culture is zz, it means that URL does not contain correct culture
    bool redirectToLanguagedVersion = filterContext.RouteData.Values["culture"].ToString() == "zz"; 
    string language = "en", culture = "GB";

    if (redirectToLanguagedVersion)
    {
        if (filterContext.HttpContext.User.Identity.IsAuthenticated)
        {
            var user = IdentityManager.GetUser(filterContext.HttpContext.User.Identity.GetUserId());
            language = user.CultureInfoLanguage ?? language;
            culture = user.CultureInfoCulture ?? culture;
        }
        else
        {
            language = filterContext.RequestContext.HttpContext.Cache["UserCultureInfoLanguage"]?.ToString() ?? language;
            culture = filterContext.RequestContext.HttpContext.Cache["UserCultureInfoCulture"]?.ToString() ?? culture;
        }

        RouteValueDictionary values = filterContext.RouteData.Values;
        values.Remove("culture");
        values.Add("culture", culture);
        filterContext.Result = new RedirectToRouteResult("DefaultWithCulture", values); // Issue hits here
    }
    else
    {
        // ... Define the culture user should use and update cache/db if needed

        Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo(string.Format("{0}-{1}", language, culture));
        Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(string.Format("{0}-{1}", language, culture));
    }
}}

这是RouteConfig

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        // Call to register your localized and default attribute routes
        routes.MapLocalizedMvcAttributeRoutes(
            urlPrefix: "{culture}/",
            constraints: new { culture = new CultureConstraint(defaultCulture: "zz", pattern: "[a-z]{2}") }
        );

        routes.MapRoute(
            name: "DefaultWithCulture",
            url: "{culture}/{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
            constraints: new { culture = new CultureConstraint(defaultCulture: "zz", pattern: "[a-z]{2}") }
        );

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { culture = "zz", controller = "Home", action = "Index", id = UrlParameter.Optional }
        );

        routes.MapRoute(
            name: "TourWithCulture",
            url: "{culture}/{controller}/{action}/{id}/{title}",
            defaults: new { controller = "Tours", action = "Explore", id = UrlParameter.Optional, title = UrlParameter.Optional },
            constraints: new { culture = new CultureConstraint(defaultCulture: "zz", pattern: "[a-z]{2}") }
        );

        routes.MapRoute(
            name: "Tour",
            url: "{controller}/{action}/{id}/{title}",
            defaults: new { controller = "Tours", action = "Explore", id = UrlParameter.Optional, title = UrlParameter.Optional },
            constraints: new { culture = new CultureConstraint(defaultCulture: "zz", pattern: "[a-z]{2}") }
        );
    }
}

1 个答案:

答案 0 :(得分:0)

您获得异常的原因是您没有提供构建URL所需的匹配值。要构建URL,您需要提供所有必需的值(如果需要,还可以提供可选的值)。但是额外的值会导致它不匹配。

RouteValueDictionary values = filterContext.RouteData.Values;
values.Remove("culture");
values.Add("culture", culture);
filterContext.Result = new RedirectToRouteResult("DefaultWithCulture", values);

始终需要控制器和操作。所以,对于这条路线你需要通过:

  1. 文化
  2. 控制器
  3. 动作
  4. id(可选)
  5. 这意味着如果您的路线值集合超过此值(例如title),则与DefaultWithCulture不匹配。请注意,DefaultWithCulture是路径的额外条件,但您仍必须传递所有必需的路线值才能与之匹配。

    也就是说,在使用基于this answer的路由时,您不应该将路由名称传递给RedirectToRouteResult,因为事实上有2条路由代表可能的匹配 - DefaultWithCulture和{{ 1}}在这种情况下。您必须删除匹配的额外名称条件,否则将无法匹配Default

    Default