C#学习教程:ASP.NET MVC,本地化路由和用户的默认语言分享


ASP.NET MVC,本地化路由和用户的默认语言

我正在使用ASP.NET MVC本地化路由。 因此,当用户访问英文站点时,它是example.com/en/Controller/Action ,瑞典站点是example.com/sv/Controller/Action

如何确保当用户进入网站时他/她直接使用正确的语言? 我知道如何获得我想要的语言,这不是问题。 我过去经常做的是将文化放入RegisterRoutes方法中。 但由于我的页面处于集成模式,因此无法从Application_Start获取请求。

那么我应该如何从一开始就确保路线正确?

我就是这样做的。

~~免责声明:伪代码~~

global.asax

 public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.IgnoreRoute("{*favicon}", new { favicon = @"(.*/)?favicon.ico(/.*)?" }); routes.MapRoute( "Question-Answer", // Route name "{languageCode}/{controller}/{action}", // URL with parameters new {controller = "home", action = "index"} // Parameter defaults ); } 

注意:控制器和/或动作不需要是第一个和第二个。 实际上,它们根本不需要存在于url with parameters部分的url with parameters

然后 …

HomeController.cs

 public ActionResult Index(string languageCode) { if (string.IsNullOrEmpty(languageCode) || languageCode != a valid language code) { // No code was provided OR we didn't receive a valid code // which you can't handle... so send them to a 404 page. // return ResourceNotFound View ... } // .. do whatever in here .. } 

奖金建议

您还可以为路由添加路由约束 ,因此它只接受languageCode参数的某些字符串。 所以偷了这个家伙的代码 ….

(更多pseduo代码)…

 public class FromValuesListConstraint : IRouteConstraint { public FromValuesListConstraint(params string[] values) { this._values = values; } private string[] _values; public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) { // Get the value called "parameterName" from the // RouteValueDictionary called "value" string value = values[parameterName].ToString(); // Return true is the list of allowed values contains // this value. return _values.Contains(value); } } 

意味着你可以这样做……

 routes.MapRoute( "Question-Answer", // Route name "{languageCode}/{controller}/{action}", // URL with parameters new {controller = "home", action = "index"} // Parameter defaults new { languageCode = new FromValuesListConstraint("en", "sv", .. etc) } ); 

你有它:)

我为MVC Api 版本化做了类似的事情。

GL :)希望这会有所帮助。

好的..另一个建议。

为了确保我明白,你想……

如果是这样..这个答案有三个部分: –

  1. 添加路线。 (这是我之前的答案中的剪贴)。

global.asax

 public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.IgnoreRoute("{*favicon}", new { favicon = @"(.*/)?favicon.ico(/.*)?" }); routes.MapRoute( "Question-Answer", // Route name "{languageCode}/{controller}/{action}", // URL with parameters new {controller = "home", action = "index"} // Parameter defaults ); } 

更新(根据评论)

因此,如果您想要路线http://www.example.com/sv/account/logon那么上述路线将起作用。

LanguageCode == sv(或en或fr或您支持的任何语言)

account ==控制器:AccountController

login == action。

我所说的controller = "home"action="index"的事实只意味着这两个参数默认为那些没有提供的值。 所以,如果你转到http://www.example.com/sv/account/logon那么MVC框架足够聪明,可以知道(基于那条路线)languageCode paramters == sv,controller == action and action(方法)==索引。

注意 :您的路线顺序是重要的。 非常重要。 当您注册路线时,此路线必须是(如果不是)第一条路线(在IgonoreRoute之后)。


  1. 您需要创建一个自定义的ActionFilter ,它将在执行操作之前被调用。 这是我的快速尝试……

 using System.Linq; using System.Web.Mvc; namespace YourNamespace.Web.Application.Models { public class LanguageCodeActionFilter : ActionFilterAttribute { // This checks the current langauge code. if there's one missing, it defaults it. public override void OnActionExecuting(ActionExecutingContext filterContext) { const string routeDataKey = "languageCode"; const string defaultLanguageCode = "sv"; var validLanguageCodes = new[] {"en", "sv"}; // Determine the language. if (filterContext.RouteData.Values[routeDataKey] == null || !validLanguageCodes.Contains(filterContext.RouteData.Values[routeDataKey])) { // Add or overwrite the langauge code value. if (filterContext.RouteData.Values.ContainsKey(routeDataKey)) { filterContext.RouteData.Values[routeDataKey] = defaultLanguageCode; } else { filterContext.RouteData.Values.Add(routeDataKey, defaultLanguageCode); } } base.OnActionExecuting(filterContext); } } } 
  1. 现在你需要创建一个BaseController,你的所有控制器都inheritance了它。 然后,这将创建一个易于访问的属性 ,您的所有操作都可以访问它…然后根据该值显示他们想要的任何内容。

在这里我们去…(再次伪代码….)

 public abstract class BaseController : Controller { protected string LanguageCode { get { return (string) ControllerContext.RouteData.Values["LanguageCode"]; } } } 

那么我们就像这样装饰我们的控制器:)

 [LanguageCodeActionFilter] public class ApiController : BaseController { public ActionResult Index() { if (this.LanguageCode == "sv") ... // whatever.. etc.. } } 

请注意我是如何装饰课程的 …而不仅仅是每个动作。 这意味着类中的所有操作都会受到ActionFilter的影响:)

此外,您可能希望在global.asax中添加一个处理NO languageCode的新路由..而硬编码默认该值…

喜欢(也未经考验)……

 routes.MapRoute( "Question-Answer", // Route name "{controller}/{action}", // URL with parameters new {controller = "home", action = "index", languageCode = "sv"} // Parameter defaults ); 

这有帮助吗?

我知道这是一个非常古老的问题,但只需要解决一整套相关问题,我想我会分享我的解决方案。

以下是一个完整的解决方案,包括一些额外的技巧,可以轻松更改语言。 它允许特定的文化,而不仅仅是特定的语言(但在这个例子中只保留语言部分)。

function包括:

第1步:修改RouteConfig中的RegisterRoutes

这个新路由包括一个约束(正如其他人也建议的那样),以确保语言路由不会获取某些标准路径。 不需要默认语言值,因为它全部由LocalisationAttribute处理(参见步骤2)。

  public static void RegisterRoutes(RouteCollection routes) { ... // Special localisation route mapping - expects specific language/culture code as first param routes.MapRoute( name: "Localisation", url: "{lang}/{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }, constraints: new { lang = @"[az]{2}|[az]{2}-[a-zA-Z]{2}" } ); // Default routing routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } 

第2步:创建本地化属性

这将在处理控制器请求之前查看它们,并根据URL,cookie或默认浏览器文化更改当前区域性。

 // Based on: http://geekswithblogs.net/shaunxu/archive/2010/05/06/localization-in-asp.net-mvc-ndash-3-days-investigation-1-day.aspx public class LocalisationAttribute : ActionFilterAttribute { public const string LangParam = "lang"; public const string CookieName = "mydomain.CurrentUICulture"; // List of allowed languages in this app (to speed up check) private const string Cultures = "en-GB en-US de-DE fr-FR es-ES ro-RO "; public override void OnActionExecuting(ActionExecutingContext filterContext) { // Try getting culture from URL first var culture = (string)filterContext.RouteData.Values[LangParam]; // If not provided, or the culture does not match the list of known cultures, try cookie or browser setting if (string.IsNullOrEmpty(culture) || !Cultures.Contains(culture)) { // load the culture info from the cookie var cookie = filterContext.HttpContext.Request.Cookies[CookieName]; if (cookie != null) { // set the culture by the cookie content culture = cookie.Value; } else { // set the culture by the location if not specified culture = filterContext.HttpContext.Request.UserLanguages[0]; } // set the lang value into route data filterContext.RouteData.Values[LangParam] = culture; } // Keep the part up to the "-" as the primary language var language = culture.Split(new char[] { '-' }, StringSplitOptions.RemoveEmptyEntries)[0]; filterContext.RouteData.Values[LangParam] = language; // Set the language - ignore specific culture for now Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(language); // save the locale into cookie (full locale) HttpCookie _cookie = new HttpCookie(CookieName, culture); _cookie.Expires = DateTime.Now.AddYears(1); filterContext.HttpContext.Response.SetCookie(_cookie); // Pass on to normal controller processing base.OnActionExecuting(filterContext); } } 

第3步:将本地化应用于所有控制器

例如

 [Localisation] <<< ADD THIS TO ALL CONTROLLERS (OR A BASE CONTROLLER) public class AccountController : Controller { 

第4步:更改语言(例如从菜单中)

这是一个有点棘手的地方,需要一些解决方法。

将ChangeLanguage方法添加到您的帐户控制器。 这将从“上一个路径”中删除任何现有语言代码,以允许新语言生效。

  // Regex to find only the language code part of the URL - language (aa) or locale (aa-AA) syntax static readonly Regex removeLanguage = new Regex(@"/[az]{2}/|/[az]{2}-[a-zA-Z]{2}/", RegexOptions.Compiled); [AllowAnonymous] public ActionResult ChangeLanguage(string id) { if (!string.IsNullOrEmpty(id)) { // Decode the return URL and remove any language selector from it id = Server.UrlDecode(id); id = removeLanguage.Replace(id, @"/"); return Redirect(id); } return Redirect(@"/"); } 

第5步:添加语言菜单链接

菜单选项包含指定为路径参数的新语言的链接。

例如(Razor例子)

 
  • @Html.ActionLink("English", "ChangeLanguage", "Account", new { lang = "en", id = HttpUtility.UrlEncode(Request.RawUrl) }, null)
  • @Html.ActionLink("Spanish", "ChangeLanguage", "Account", new { lang = "es", id = HttpUtility.UrlEncode(Request.RawUrl) }, null)
  • 返回URl是当前页面,经过编码,以便它可以成为URL的id参数。 这意味着您需要启用某些转义序列,否则Razor会拒绝这些转义序列作为潜在的安全违规。

    注意:对于非剃刀设置,您基本上需要一个具有新语言的锚点和当前页面相对URL,如下所示: http://website.com/{language}/account/changelanguage/{existingURL}http://website.com/{language}/account/changelanguage/{existingURL} language http://website.com/{language}/account/changelanguage/{existingURL} account/ http://website.com/{language}/account/changelanguage/{existingURL}

    其中{language}是新的文化代码,{existingURL}是当前相对页面地址的URLencoded版本(这样我们将返回同一页面,选择新的语言)。

    第6步:在url中启用某些“不安全”字符

    返回URL所需的编码意味着您需要在web.config启用某些转义字符,否则现有的URL参数将导致错误。

    在您的web.config中,在找到httpRuntime标记(或添加它)并向其中添加以下内容(基本上删除此属性的标准版本中的%):

      requestPathInvalidCharacters="<,>,&,:,,?" 

    在web.config中,找到部分并在其中添加以下内容:

        

    如果url格式正确,您可以在global.asax BeginRequest中询问。 您也可以尝试使用路线,但根据我的经验,如果您不确定第一个参数是lang,您的路线会非常不稳定。

     Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs) Dim lang As String = "es" If not Request.Path.ToLower.StartsWith("sv/") and _ not Request.Path.ToLower.StartsWith("en/") ''//ask the browser for the preferred lang Select Case Mid(Request.UserLanguages(0).ToString(), 1, 2).ToLower Case "en" Response.Redirect("en/") Case "sv" Response.Redirect("sv/") Case Else Response.Redirect("sv/") ''//the default End Select end if end sub 

    未经测试的代码。 原谅我的VB

    上述就是C#学习教程:ASP.NET MVC,本地化路由和用户的默认语言分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注---猴子技术宅(www.ssfiction.com)

    本文来自网络收集,不代表猴子技术宅立场,如涉及侵权请点击右边联系管理员删除。

    如若转载,请注明出处:https://www.ssfiction.com/ckf/1031612.html

    发表评论

    邮箱地址不会被公开。 必填项已用*标注