Osk*_*lin 11 c# asp.net-mvc routing localization
我正在使用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
);
}
Run Code Online (Sandbox Code Playgroud)
注意:控制器和/或动作不需要是第一个和第二个.事实上,它们根本不需要存在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 ..
}
Run Code Online (Sandbox Code Playgroud)
您还可以为路径添加路径约束,因此它只接受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);
}
}
Run Code Online (Sandbox Code Playgroud)
意味着你可以这样做......
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) }
);
Run Code Online (Sandbox Code Playgroud)
你有它:)
我为MVC Api 版本化做了类似的事情.
GL :)希望这会有所帮助.
好的..另一个建议.
为了确保我明白,你想......
如果是这样..这个答案有三个部分: -
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
);
}
Run Code Online (Sandbox Code Playgroud)
因此,如果您想拥有该路线,http://www.example.com/sv/account/logon那么上述路线将起作用.
LanguageCode == sv(或en或fr或您支持的任何语言)
account ==控制器:AccountController
login ==行动.
事实上,我已经说过,controller = "home"并且action="index"只表示这两个参数默认为那些值,如果没有提供.所以,如果你转到http://www.example.com/sv/account/logon那么MVC框架足够聪明,可以知道(基于那条路线)languageCode paramters == sv,controller == action and action(method)== index.
注意:您的路线顺序是重要的.非常重要.当您注册路线时,此路线必须是第一条路线(如果不是)的一条路线(在IgonoreRoute之后).
.
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
在这里我们去...(再次伪代码....)
public abstract class BaseController : Controller
{
protected string LanguageCode
{
get { return (string) ControllerContext.RouteData.Values["LanguageCode"]; }
}
}
Run Code Online (Sandbox Code Playgroud)
那么我们就像这样装饰我们的控制器:)
[LanguageCodeActionFilter]
public class ApiController : BaseController
{
public ActionResult Index()
{
if (this.LanguageCode == "sv") ... // whatever.. etc..
}
}
Run Code Online (Sandbox Code Playgroud)
请注意我是如何装饰课程的 ......而不仅仅是每个动作.这意味着类中的所有操作都会受到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
);
Run Code Online (Sandbox Code Playgroud)
这有帮助吗?
我知道这是一个非常古老的问题,但是刚刚解决了完整的相关问题集,我想我会分享我的解决方案。
下面是一个完整的解决方案,包括一些额外的技巧,可以轻松更改语言。它允许特定的文化,而不仅仅是特定的语言(但在此示例中仅保留了语言部分)。
这个新的路由包括一个约束(正如其他人所建议的那样)以确保语言路由不会占用某些标准路径。不需要默认语言值,因为这一切都由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 = @"[a-z]{2}|[a-z]{2}-[a-zA-Z]{2}" }
);
// Default routing
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Run Code Online (Sandbox Code Playgroud)
这将在处理控制器请求之前查看控制器请求,并根据 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);
}
}
Run Code Online (Sandbox Code Playgroud)
例如
[Localisation] <<< ADD THIS TO ALL CONTROLLERS (OR A BASE CONTROLLER)
public class AccountController : Controller
{
Run Code Online (Sandbox Code Playgroud)
这就是它有点棘手的地方,需要一些解决方法。
将 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(@"/[a-z]{2}/|/[a-z]{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(@"/");
}
Run Code Online (Sandbox Code Playgroud)
菜单选项包含一个链接,该链接具有指定为路由参数的新语言。
例如(剃刀示例)
<li>@Html.ActionLink("English", "ChangeLanguage", "Account", new { lang = "en", id = HttpUtility.UrlEncode(Request.RawUrl) }, null)</li>
<li>@Html.ActionLink("Spanish", "ChangeLanguage", "Account", new { lang = "es", id = HttpUtility.UrlEncode(Request.RawUrl) }, null)</li>
Run Code Online (Sandbox Code Playgroud)
返回的 URl 是当前页面,经过编码后可以成为 URL 的 id 参数。这意味着您需要启用某些转义序列,否则 Razor 将拒绝这些转义序列作为潜在的安全违规。
注意:对于非剃刀设置,您基本上需要一个具有新语言和当前页面相对 URL 的锚点,路径如下:
http://website.com/{language}/account/changelanguage/{existingURL}
其中 {language} 是新的文化代码,{existingURL} 是当前相关页面地址的 URLencoded 版本(这样我们将返回到同一页面,并选择新的语言)。
返回 URL 的必需编码意味着您需要在 中启用某些转义字符web.config,否则现有 URL 参数将导致错误。
在您的 web.config 中,找到httpRuntime标记(或添加它)<system.web>并将以下内容添加到其中(基本上删除此属性的标准版本中的 %):
requestPathInvalidCharacters="<,>,&,:,\,?"
Run Code Online (Sandbox Code Playgroud)
在您的 web.config 中,找到该<system.webserver>部分并在其中添加以下内容:
<security>
<requestFiltering allowDoubleEscaping="true"/>
</security>
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
15349 次 |
| 最近记录: |