Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/337.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 我应该在哪里编写代码来覆盖MVC请求的路由数据值?_C#_Asp.net Mvc_Asp.net Mvc 5_Asp.net Mvc Routing - Fatal编程技术网

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

C# 我应该在哪里编写代码来覆盖MVC请求的路由数据值?,c#,asp.net-mvc,asp.net-mvc-5,asp.net-mvc-routing,C#,Asp.net Mvc,Asp.net Mvc 5,Asp.net Mvc Routing,我想根据user.Identity中的用户claim覆盖RouteData中名为lang的项的值 例如,如果路由数据中的lang值为en(example.com/en/login),我希望读取用户的lang声明,并通过它覆盖roue数据中的lang。因此,登录页面中的其他链接应遵循新的lang值(而不是en) 设置语言的位置: 在我的项目中,我在应用程序中设置了UiThread的语言\u AuthenticateRequest。因此,我在那里更改了lang路由值,但似乎没有达到预期的结果(为什么

我想根据
user.Identity
中的用户
claim
覆盖
RouteData
中名为
lang
的项的值

例如,如果路由数据中的
lang
值为
en
(example.com/en/login),我希望读取用户的
lang
声明
,并通过它覆盖roue数据中的
lang
。因此,登录页面中的其他链接应遵循新的
lang
值(而不是
en

设置语言的位置:

在我的项目中,我在
应用程序中设置了
UiThread
的语言\u AuthenticateRequest
。因此,我在那里更改了
lang
路由值,但似乎没有达到预期的结果(为什么?):


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

创建一个实现
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());
        }
    }
}
用于测试的My 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 }
            );
        }
    }
}

应用程序\u AuthenticateRequest
在中太晚,无法对路由值产生任何影响

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

你基本上有两个选择

  • 创建自己的
    路线
    或。路由负责将请求转换为路由值,因此您可以在此处放置条件逻辑来构建请求
  • 使用全局注册的
    IAuthorizationFilter
    。授权筛选器在ModelBinder之前运行,因此会影响传递到模型和操作方法中的值
  • 然而,作为一个不满意的用户,其他网站控制了语言选择过程,而不是仅仅让用户根据URL/选择来决定,我不得不抗议。您认为这样做是在帮助用户,但事实上,您使您的网站使用起来更加令人沮丧

  • 大多数用户会通过搜索引擎或网站的营销渠道进入你的网站。在每种情况下,他们都会自动以自己的语言进入您的网站,因为他们正在以自己的语言进行搜索。如果您不使用任何cookie或会话状态来阻止搜索引擎为本地化页面编制索引,至少会发生这种情况
  • 通过浏览器历史记录或书签返回的用户也将始终以自己的语言返回
  • (通常)很小一部分用户可能会通过键入
    www.somesite.com
    进入您的网站,在这种情况下,他们不会使用自己的语言。他们将毫无问题地认识到他们看到的是错误的语言,并将立即寻找某种语言下拉列表或标志图标以切换到他们的语言。除非您正在使用某种“记住我”功能,否则此步骤将始终在他们登录之前进行
  • 因此,当用户登录时,“覆盖”区域性没有什么意义。在达到这一阶段的所有病例中,99.999%的患者已经选择了正确的培养基

    如果你仍然坚持这样做来“帮助”你的用户,不要从URL中覆盖文化。在登录操作的post部分放置一个
    RedirectToAction
    ,以便在登录时将它们重定向到具有新区域性的URL。这将允许您(现在感到沮丧)的用户能够覆盖您的覆盖,并更改回他们想要查看站点的语言

    如果您在URL或某种语言选择器中选择网站,而不给他们以所需语言查看网站的选项,那么当他们没有返回时,不要感到惊讶

    [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);
        }
    }
    
    [HttpPost]
    [异名]
    [ValidateAntiForgeryToken]
    公共异步任务登录(LoginView模型,字符串返回URL)
    {
    如果(!ModelState.IsValid)
    {
    返回视图(模型);
    }
    //这不会将登录失败计入帐户锁定
    //要使密码失败触发帐户锁定,请更改为shouldLockout:true
    var result=wait SignInManager.PasswordSignInAsync(model.Email、model.Password、model.RememberMe、shouldllockout:false);
    开关(结果)
    {
    案例标志状态成功:
    //通过替换
    //URL的第一段。
    returnUrl=ChangeCultureInUrl(returnUrl);
    返回重定向到本地(returnUrl);
    案例标志状态锁定输出:
    返回视图(“锁定”);
    案例标志状态。要求验证:
    return RedirectToAction(“SendCode”,new{ReturnUrl=ReturnUrl,RememberMe=model.RememberMe});
    案例信号状态故障:
    违约:
    AddModelError(“,”登录尝试无效“);
    返回视图(模型);
    }
    }
    

    同样,我的建议是让用户选择他们的区域性,但是如果您仍然认为出于某种原因这是必要的,那么上述解决方案要比劫持区域性并从用户手中取得控制权要好得多。

    您应该能够在
    ActionFilter
    中做到这一点。从请求语言的用户手中夺走对所请求语言的控制权似乎是一个非常糟糕的主意。这只会让那些想用一种语言查看网站的用户感到沮丧,但这不允许他们使用,因为该语言与他们在URL中请求的语言不同。请参阅和。@NightOwl888,我的站点中有一个场景,我认为用户希望进行此更改:有时用户在站点中使用一种语言(例如,不是他最喜欢的语言)
    [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);
        }
    }