一.nop中的路由注册
在Global.asax,Application_Start()方法中会进行路由注册,代码如下。
1 public static void RegisterRoutes(RouteCollection routes) 2 { 3 routes.IgnoreRoute("favicon.ico"); 4 routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 5 6 //register custom routes (plugins, etc) 7 var routePublisher = EngineContext.Current.Resolve<IRoutePublisher>(); 8 routePublisher.RegisterRoutes(routes); 9 10 routes.MapRoute( 11 "Default", // Route name 12 "{controller}/{action}/{id}", // URL with parameters 13 new { controller = "Home", action = "Index", id = UrlParameter.Optional }, 14 new[] { "Nop.Web.Controllers" } 15 ); 16 }
我们会发现调用了IRutePublisher接口,该接口由Nop.Web.Framework.Mvc.Routes.RoutePublisher类实现。
并通过RegisterRoutes(RouteCollection routes)方法进行路由注册。代码如下:
1 /// <summary> 2 /// Register routes 3 /// </summary> 4 /// <param name="routes">Routes</param> 5 public virtual void RegisterRoutes(RouteCollection routes) 6 { 7 //ITypeFinder接口获取所有IRouteProvider接口实现类的Type对象 8 var routeProviderTypes = typeFinder.FindClassesOfType<IRouteProvider>(); 9 var routeProviders = new List<IRouteProvider>(); 10 foreach (var providerType in routeProviderTypes) 11 { 12 //Ignore not installed plugins 13 var plugin = FindPlugin(providerType);//PluginManager.ReferencedPlugins中查找该Type对象 14 if (plugin != null && !plugin.Installed)//插件不为空未安装则跳出本次循环 15 continue; 16 17 var provider = Activator.CreateInstance(providerType) as IRouteProvider;//实例化IRouteProvider接口对象 18 routeProviders.Add(provider); 19 } 20 routeProviders = routeProviders.OrderByDescending(rp => rp.Priority).ToList();//排序 21 routeProviders.ForEach(rp => rp.RegisterRoutes(routes));//遍历并调用RegisterRoutes(routes)进行路由注册 22 }
该方法做了如下工作:
第一步:通过ITyperFinder接口找到所有实现了IRouteProvider接口的类类型。保存在routeProviderTypes集合中
第二步:遍历routeProviderTypes集合,通过PluginManager类找到未安装IRouteProvider类类型。并从routeProviderTypes集合中排除掉。
第三步:实例化IRouteProvider实现类。
第四步:调用IRouteProvider实现类RegisterRoutes(routes)方法进行路由注册。
下图为主要接口之间的调用关系
通过上述分析nop路由注册主要是通过IRouteProvider接口实现的,现在我们看看项目中实现该接口的类都有哪些。
下图红色是在Nop.Web项目中,其他都是在nop插件中。
接下来我们看下路由的注册顺序如下图,我们看到最先匹配的Nop.Web.Infrastructure.RouteProvider中的路由注册。
二.启用支持多语言的SEO友好链接
nop支持SEO友好链接,管理后台->设置管理->综合设置->启用支持多语言的SEO友好链接 选中就可以支持了。
启用后URL格式为: http://www.yourStore.com/en/ 或 http://www.yourStore.com/zh/ (SEO比较友好)
那该功能怎么实现的呢?接下来我们看看nop是如何通过路由扩展实现的。
(Nop.Web.Framework.WebWorkContext在多语言中也会用到,这里先不讲它,我们只说路由)
我们先看下Nop.Web.Infrastructure.RouteProvider中的路由注册代码
Nop.Web.Infrastructure.RouteProvider
Nop.Web.Framework.Localization.LocalizedRouteExtensions类中对RouteCollection routes添加了MapLocalizedRoute的扩展方法
1 routes.MapLocalizedRoute("HomePage", 2 "", 3 new { controller = "Home", action = "Index" }, 4 new[] { "Nop.Web.Controllers" });
Nop.Web.Framework.Localization.LocalizedRoute继承Route类进行扩展多语言Seo的支持
1 public static Route MapLocalizedRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces) 2 { 3 if (routes == null) 4 { 5 throw new ArgumentNullException("routes"); 6 } 7 if (url == null) 8 { 9 throw new ArgumentNullException("url"); 10 } 11 //LocalizedRoute 进行了多语言Seo优化
12 var route = new LocalizedRoute(url, new MvcRouteHandler()) 13 { 14 Defaults = new RouteValueDictionary(defaults), 15 Constraints = new RouteValueDictionary(constraints), 16 DataTokens = new RouteValueDictionary() 17 }; 18 19 if ((namespaces != null) && (namespaces.Length > 0)) 20 { 21 route.DataTokens["Namespaces"] = namespaces; 22 } 23 24 routes.Add(name, route); 25 26 return route; 27 }
LocalizedRoute对路由进行了扩展,主要重写了GetRouteData,和GetVirtualPath这两个方法。
GetRouteData:解析Url,它的作用简单理解是通过url匹配到正确的路由。
开启多语言Seo后URL格式为: http://www.yourStore.com/en/ 或 http://www.yourStore.com/zh/ (SEO比较友好),
LocalizedRoute重写GetRouteData方法,会去掉en或zh后,匹配正确的路由位置。
例如输入http://localhost:15536/en,会正确的匹配到http://localhost:15536/
1 routes.MapLocalizedRoute("HomePage", 2 "", 3 new { controller = "Home", action = "Index" }, 4 new[] { "Nop.Web.Controllers" });
GetVirtualPath:生成Url,我们在Razor视图中常会看到<a href="@Url.Action("Index", "Home")">首页</a>这种标签,
GetVirtualPath负责将"@Url.Action("Index", "Home")"生成支持多语言Seo的url字符串http://www.yourStore.com/en/ ,自动会加上en或zh。
更好的理解GetRouteData和GetVirtualPath,可自行搜索下。
三.搜索引擎友好名称实现
除了对多语言Seo友好链接支持,nop还支持Seo友好链接的支持。
我们发现Nop.Web.Infrastructure.GenericUrlRouteProvider类主要用于Seo友好链接的路由注册,代码如下:
Nop.Web.Infrastructure.GenericUrlRouteProvider
我们发现多了MapGenericPathRoute的扩展
1 //generic URLs 2 routes.MapGenericPathRoute("GenericUrl", 3 "{generic_se_name}", 4 new {controller = "Common", action = "GenericUrl"}, 5 new[] {"Nop.Web.Controllers"});
我们来看看MapGenericPathRoute方法来自Nop.Web.Framework.Seo.GenericPathRouteExtensions类中。
通过Nop.Web.Framework.Seo.GenericPathRoute完成Seo友好链接的路由扩展
1 public static Route MapGenericPathRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces) 2 { 3 if (routes == null) 4 { 5 throw new ArgumentNullException("routes"); 6 } 7 if (url == null) 8 { 9 throw new ArgumentNullException("url"); 10 } 11 //GenericPathRoute中实现Seo友好链接路由 12 var route = new GenericPathRoute(url, new MvcRouteHandler()) 13 { 14 Defaults = new RouteValueDictionary(defaults), 15 Constraints = new RouteValueDictionary(constraints), 16 DataTokens = new RouteValueDictionary() 17 }; 18 19 if ((namespaces != null) && (namespaces.Length > 0)) 20 { 21 route.DataTokens["Namespaces"] = namespaces; 22 } 23 24 routes.Add(name, route); 25 26 return route; 27 }
GenericPathRoute对路由进行扩展,只重写了GetRouteData方法用于解析url,帮助路由到正确的执行位置。代码如下:
GetRouteData
路由匹配到支持Seo友好链接会重定向链接新的路由位置,nop 3.9目前支持下图中的路由
提示:数据库UrlRecord表对Seo友情链接提供支持。
四.总结
1.继承IRouteProvider对路由进行扩展。(注意路由注册顺序,ASP.NET MVC 只匹配第一次成功的路由信息)
2.多语言Seo友好链接通过LocalizedRoute类进行路由扩展(MapLocalizedRoute扩展中调用)
3.页面Seo友好链接通过GenericPathRoute类进行路由扩展(MapGenericPathRoute扩展中调用)
文中有错误的理解和不正确的观点,请留言,一起交流共同进步。
本文地址:http://www.cnblogs.com/yaoshangjin/p/7228177.html
本文为大波浪原创、转载请注明出处。
如果您认为这篇文章还不错或者有所收获,可以点击下方的【关注】按钮,因为你的支持是我继续写作,分享的最大动力!
作者:大波浪
来源:http://www.cnblogs.com/yaoshangjin/
声明: 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。如果您发现博客中出现了错误,或者有更好的建议、想法,请及时与我联系!!如果想找我私下交流,可以私信或者加我QQ。
http://www.cnblogs.com/yaoshangjin/p/7228177.html