而不会在后面加上任何的culture参数)。那么难道我们要为了这种场景写两份路由吗?显然不是,或者说不用手动做这件事。这里要解决的第一个问题出现了。我的方案是:只为domain/controller/action/param1.。这种路由手动写代码配置,这也比较符合习惯;然后通过一个方法,遍历route表中的所有路由,并在每个url规则前面加上一个参数ci表示culture,生成一份新的路由加到路由表中即可。这样做尽管没有减少路由规则,但是至少不用手动一个个写了,要不然没人会同意这个方案的。下面是代码和解释:
以下为引用的内容:
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RegisterRoutes(RouteTable.Routes); RegisterGlobalizationRoutes(); ... }
|
以下为引用的内容:
private void RegisterGlobalizationRoutes() { //RouteTable.Routes即路由表 if (RouteTable.Routes == null) return; //创建一个新的路由集合,存放将要添加到路由 RouteCollection rc = new RouteCollection();
//这里需要跳过routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); //由于IgnoreRouteInternal是个私有类,所以这里只能反射 //skip IgnoreRouteInternal var routes = RouteTable.Routes.SkipWhile(p => (p.GetType().Name == "IgnoreRouteInternal"));
int insertpoint = RouteTable.Routes.Count() - routes.Count();
//遍历所有需要处理的路由 foreach (var r in routes) { Route item = (r as Route); //下面的代码创建一个新的路由对象,在url规则前面加上ci参数,并拷贝其他设置 Route newitem = new Route( //string.Format(@"{ci}/{0}",item.Url), @"{ci}/" + item.Url, new MvcRouteHandler()); newitem.Defaults = new RouteValueDictionary(item.Defaults); newitem.Constraints = new RouteValueDictionary(item.Constraints); //ci参数需要验证,因为只有合法的culture才能被接受 newitem.Constraints.Add("ci", new CulturePrefixRule()); newitem.DataTokens = new RouteValueDictionary(); newitem.DataTokens["Namespaces"] = item.DataTokens["Namespaces"]; rc.Add(newitem); } //带ci参数的路由应当靠前放,所以这里插入到前面 foreach (var c in rc) { RouteTable.Routes.Insert(insertpoint++, c); } }
|
以下为引用的内容:
//实现IRouteConstraint的一个类 private class CulturePrefixRule : IRouteConstraint { IEnumerable<string> cultureConllection = CultureInfo.GetCultures(CultureTypes.SpecificCultures).Select(p => p.Name.ToLower()); public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) { if (values[parameterName] != null) return cultureConllection.Contains(values[parameterName].ToString().ToLower()); else return false; } }
|
这里要注意几点:
1.routes.IgnoreRoute("{resource}.axd/{*pathInfo}");会在路由表中添加一条IgnoreRouteInternal类型的路由,只不过这条是需要被跳过的而已。三个类的关系是:
RouteBase->Route->IgnoreRouteInternal
而不巧的是IgnoreRouteInternal是个私有类,因此,只能借助反射了。
2.为路由设置Constraints属性时,实际上是为其指定一个IRouteConstraint。MVC内部有一个实现了IRouteConstraint的接受正则表达式的类,我们在MapRoute方法中用一个string初始化Constraints,实际上就是实例化了这个类。而这里我们的需求显然要复杂点:需要判断ci参数是否是支持的,所以也就有了CulturePrefixRule实现IRouteConstraint。
3.带有ci参数的路由更“特殊”,所以最好还是放在路由表前面。原因我就不再累述了。