建站学 - 轻松建站从此开始!

建站学-个人建站指南,网页制作,网站设计,网站制作教程

当前位置: 建站学 > 网站开发 > asp.net教程 >

ASP.NET MVC的全球化方案

时间:2010-10-20 22:20来源: 作者: 点击:
由于项目需要最近在学习ASP.NET MVC。在实践中,网站要支持多语言,需要全球化。在MVC下我实现了一个全球化框架,在这里与各位分享一下,不足之处也请各位看官指教。

由于项目需要最近在学习ASP.NET MVC。在实践中,网站要支持多语言,需要全球化。在MVC下我实现了一个全球化框架,在这里与各位分享一下,不足之处也请各位看官指教。

 

让URL支持全球化

经常上微软网站的朋友可能很熟悉类似包含..\zh-cn\..、..\en-us\..的url形式,这就是本文要使用的全球化方案。当然还有使用QueryString传递参数的方案,基本思路我想是类似的。

由于MVC天生的URL路由原理,使得这个方案很容易被接受。

 

基本思路

这个方案的基本思路是:

1.当用户访问的url含有合法的culture参数时,能够直接路由到对应的controller,在controller初始化时设置线程的Culture;

2.当用户访问的url不包含culture参数时,同样被路由到对应的controller,但controller在执行action前,重定向到包含Culture的url。这里的Culture按照先检测cookie,再检测语言浏览器设置,最后使用默认值的优先级顺序实施。

先看下效果演示,注意url,点击下载例子

image

image

 

Resource.resx

在接下去之前先回顾一下资源文件。在asp.net web应用程序(winform同样)中定义的资源文件.resx实际上是一个xml配置文件,通常我们只关心其中的key\value配置;我们可以建立一个或多个.resx,这些.resx会对应生成一个cs文件,这个cs文件会定义一个类(可能是Resource类,取决于你的资源文件的命名),通过访问这个类的静态属性即可访问这些key,而选择哪个.resx读取的关键就是CultureInfo,只要我们设置当前线程的CultureInfo,Resource便会自动识别对应的.resx配置文件。而在.resx的命名上,需要按照这样的规则:

Resource.zh-cn.resx(对应简体中文资源文件)

Resource.en-us.resx(对应美国英语资源文件)

中间的Culture名字很重要。

通常在开发时,只要一个默认的Resource.resx,当开发完成之后,拷贝一个相同的Resource.resx,并改名字成上面的样子,然后手动或自动将其中的所有value都翻译成对应的语言。

 

解决路由问题

在这个方案中,首先要考虑的是url路由配置。首先,理想情况下,我们所有的url都是domain/culture/controller/action/param1/..这种形式,那么只要一份以culture开头的路由就可以了。但是事实上并非这么简单,如果用户不知道这个规则,他手动输入了domain/controller/action/param1..那么这种url将不能被正确路由。这种情况在初次访问网站的时候最为常见(通常我们都会键入www.microsoft.com而不会在后面加上任何的culture参数)。那么难道我们要为了这种场景写两份路由吗?显然不是,或者说不用手动做这件事。这里要解决的第一个问题出现了。我的方案是:只为domain/controller/action/param1..这种路由手动写代码配置,这也比较符合习惯;然后通过一个方法,遍历route表中的所有路由,并在每个url规则前面加上一个参数ci表示culture,生成一份新的路由加到路由表中即可。这样做尽管没有减少路由规则,但是至少不用手动一个个写了,要不然没人会同意这个方案的。下面是代码和解释:

 

1 protected void Application_Start()
2 {
3     AreaRegistration.RegisterAllAreas();
4     RegisterRoutes(RouteTable.Routes);
5     RegisterGlobalizationRoutes();
6     ...
7 }

 

01 private void RegisterGlobalizationRoutes()
02 {
03     //RouteTable.Routes即路由表
04     if (RouteTable.Routes == null)
05         return;
06     //创建一个新的路由集合,存放将要添加到路由
07     RouteCollection rc = new RouteCollection();
08   
09     //这里需要跳过routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
10     //由于IgnoreRouteInternal是个私有类,所以这里只能反射
11     //skip IgnoreRouteInternal
12     var routes = RouteTable.Routes.SkipWhile(p => (p.GetType().Name == "IgnoreRouteInternal"));
13   
14     int insertpoint = RouteTable.Routes.Count() - routes.Count();
15   
16     //遍历所有需要处理的路由
17     foreach (var r in routes)
18     {
19         Route item = (r as Route);
20         //下面的代码创建一个新的路由对象,在url规则前面加上ci参数,并拷贝其他设置
21         Route newitem = new Route(
22             //string.Format(@"{ci}/{0}",item.Url),
23             @"{ci}/" + item.Url,
24             new MvcRouteHandler());
25         newitem.Defaults = new RouteValueDictionary(item.Defaults);
26         newitem.Constraints = new RouteValueDictionary(item.Constraints);
27         //ci参数需要验证,因为只有合法的culture才能被接受
28         newitem.Constraints.Add("ci", new CulturePrefixRule());
29         newitem.DataTokens = new RouteValueDictionary();
30         newitem.DataTokens["Namespaces"] = item.DataTokens["Namespaces"];
31         rc.Add(newitem);
32     }
33     //带ci参数的路由应当靠前放,所以这里插入到前面
34     foreach (var c in rc)
35     {
36         RouteTable.Routes.Insert(insertpoint++, c);
37     }
38 }
01 //实现IRouteConstraint的一个类
02 private class CulturePrefixRule : IRouteConstraint
03 {
04     IEnumerable<string> cultureConllection = CultureInfo.GetCultures(CultureTypes.SpecificCultures).Select(p => p.Name.ToLower());
05     public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
06     {
07         if (values[parameterName] != null)
08             return cultureConllection.Contains(values[parameterName].ToString().ToLower());
09         else
10             return false;
11     }
12 }

 

(责任编辑:admin)

织梦二维码生成器
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片