我应该在哪里编写代码来覆盖MVC请求的路由数据值?

时间:2018-01-28 11:22:20

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

我想根据RouteData中的用户lang来覆盖claim中名为User.Identity的项目的值。

例如,如果路由数据中的lang值为en example.com/en/login ),我想阅读lang {用户{1}}并覆盖路由数据中的claim。因此,登录页面中的其他链接应遵循lang 值(不是lang)。

我在哪里设置语言:

在我的项目中,我在 en 中设置了UiThread的语言。所以我在那里更改了Application_AuthenticateRequest路线值,但似乎没有预期的结果(为什么?):

lang

哪里我应该编写代码来覆盖请求的路由值? 你的建议是什么

2 个答案:

答案 0 :(得分:2)

Application_AuthenticateRequestMVC life cycle中为时已晚,无法对路线值产生任何影响。

在动作过滤器运行之前,MVC使用value providers在请求的早期解析ModelBinder中的值,因此动作过滤器不是解决此问题的方法。

你基本上有几个选择。

  1. 创建自己的RouteRouteBase subclass。路由负责将请求转换为路由值,因此您可以在此处放置条件逻辑来构建请求。
  2. 使用全球注册的IAuthorizationFilter。授权过滤器在ModelBinder之前运行,因此可以影响传递给模型和操作方法的值。
  3.   

    然而,作为其他网站的不满意的用户,他们控制语言选择过程,而不是让用户根据URL /选择决定,我必须抗议。您认为这样做可以帮助用户,但实际上您使网站的使用更加令人沮丧

         
        
    1. 大多数用户将通过搜索引擎或您网站的某个营销渠道进入您的网站。在每种情况下,他们都会自动以自己的语言进入您的网站,因为他们使用自己的语言进行搜索。如果您have the culture in the URL并且不使用任何Cookie或会话状态来阻止搜索引擎索引您的本地化网页,那么至少会发生这种情况。
    2.   
    3. 通过浏览器历史记录或书签返回的用户也将始终使用自己的语言返回。
    4.   
    5. 一般(很少)用户可以通过键入www.somesite.com进入您的网站,在这种情况下,他们不会以自己的语言进入。他们没有问题,认识到他们看到了错误的语言,并会立即寻找某种语言下拉或标志图标来切换到他们的语言。除非您使用某种记住我的功能,否则此步骤将始终在他们登录之前发生。
    6.         

      所以,"覆盖"没有什么意义。用户登录时的文化。他们已经在99.999%的达到这个阶段的案例中选择了正确的文化。

    如果你仍然坚持"帮助"通过这样做,您的用户不要覆盖URL中的文化。在登录操作的帖子部分放置一个RedirectToAction,将其重新定向到具有新文化的网址,仅在登录时。这将允许您(现在受挫)的用户覆盖您的覆盖并更改回他们打算查看该网站的语言。

    如果您没有选择在网址或某种语言选择器中选择所需语言来查看网站,那么当他们不回来时,请不要感到惊讶。

    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
    {
        if (!ModelState.IsValid)
        {
            return View(model);
        }
    
        // This doesn't count login failures towards account lockout
        // To enable password failures to trigger account lockout, change to shouldLockout: true
        var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
        switch (result)
        {
            case SignInStatus.Success:
                // Change to the culture of the signed in user by replacing the
                // first segment of the URL.
                returnUrl = ChangeCultureInUrl(returnUrl);
                return RedirectToLocal(returnUrl);
            case SignInStatus.LockedOut:
                return View("Lockout");
            case SignInStatus.RequiresVerification:
                return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
            case SignInStatus.Failure:
            default:
                ModelState.AddModelError("", "Invalid login attempt.");
                return View(model);
        }
    }
    

    同样,我的建议是让用户选择他们的文化,但如果你仍然认为这是必要的,那么上述解决方案远胜于劫持文化并从中控制用户。

答案 1 :(得分:0)

创建一个实现IActionFilter的类,覆盖其中的“lang”值,并配置MVC以使用IActionFilter

using System.Web.Mvc;

namespace WebApplication1.Filters
{
    public class LangOverrideFilter : IActionFilter
    {
        public void OnActionExecuted(ActionExecutedContext filterContext)
        {
        }

        public void OnActionExecuting(ActionExecutingContext filterContext)
        {
            filterContext.RouteData.Values["lang"] = "en";
            //Access userclaims through filterContext.HttpContext.User.
        }
    }
}

在App_Start / FilterConfig.cs中:

using System.Web;
using System.Web.Mvc;
using WebApplication1.Filters;

namespace WebApplication1
{
    public class FilterConfig
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new LangOverrideFilter());
            filters.Add(new HandleErrorAttribute());
        }
    }
}

我的App_Start / RouteConfig.cs用于测试:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

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

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