文章目录
概述
NopCommerce源码架构详解-路由相关源码分析。
内容
刚开始研究nop的同学要找到里面一个Url对应Controller相关代码,可能会有点晕。因为NopCommerce为了对seo友好,对其Url做了一些处理,自定义了路由规则,同时为了支持插件机制,加了一些自己的类进行扩展。本文就来分析一个NopCommerce路由相关源码设计思路,同样我们也先来看看相关的类图:

上面就是NopCommerce路由相关功能主要的类、接口及关系。有以下类:
1、mvcApplication
2、IRoutePublisher、RoutePublisher
3、IRouteProvider、RouteProvider、GenericUrlRouteProvider
其中RoutePublisher是用来发布RouteProvider、GenericUrlRouteProvider里面配置的路由规则的,二者都有一个抽象的接口。接下来我们就来看看这些类或接口中代码是如何实现的:
Nop.Web.MvcApplication
public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("favicon.ico"); routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); //注册自定义的路由规则及插件相关路由 var routePublisher = EngineContext.Current.Resolve<IRoutePublisher>(); routePublisher.RegisterRoutes(routes); routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { controller = "Home", action = "Index", id = UrlParameter.Optional }, new[] { "Nop.Web.Controllers" } ); }
EngineContext.Current.Resolve()这名代码表示,从Ioc容器Autofac中获取接口IRoutePublisher所依赖的具体实现类。如果对Nop的依赖注入原理还不是很了解,可以参考我之前的文章NopCommerce源码架构详解-Autofac依赖注入分析。
在Nop.Web.Framework.DependencyRegistrar中有以下代码:
builder.RegisterType<RoutePublisher>().As<IRoutePublisher>().SingleInstance();
Nop.Web.Framework.Mvc.Routes.RoutePublisher
我们找到这个RoutePublisher类(Nop.Web.Framework.Mvc.Routes.RoutePublisher)其中关键的代码如下:
public virtual void RegisterRoutes(RouteCollection routes) { //通过typeFinder找出所有(包括插件)实现了接口IRouteProvider相关的类型 var routeProviderTypes = typeFinder.FindClassesOfType<IRouteProvider>(); var routeProviders = new List<IRouteProvider>(); foreach (var providerType in routeProviderTypes) { //Ignore not installed plugins var plugin = FindPlugin(providerType); if (plugin != null && !plugin.Installed) continue; //采用反射动态创建IRouteProvider的具体类的实例 var provider = Activator.CreateInstance(providerType) as IRouteProvider; routeProviders.Add(provider); } routeProviders = routeProviders.OrderByDescending(rp => rp.Priority).ToList(); //依次调用RouteProvider的RegisterRoutes方法,注册路由规则 routeProviders.ForEach(rp => rp.RegisterRoutes(routes)); }
Nop.Web.Infrastructure.RouteProvider
现在我们来看看一个具体的RouteProvider里面都有些什么东东。在项目Nop.Web根目录下面有一个文件夹Infrastructure,里面有一个RouteProvider类,如下图:

public void RegisterRoutes(RouteCollection routes) { //We reordered our routes so the most used ones are on top. It can improve performance. //home page routes.MapLocalizedRoute("HomePage", "", new { controller = "Home", action = "Index" }, new[] { "Nop.Web.Controllers" }); //widgets //we have this route for performance optimization because named routes are MUCH faster than usual Html.Action(...) //and this route is highly used routes.MapRoute("WidgetsByZone", "widgetsbyzone/", new { controller = "Widget", action = "WidgetsByZone" }, new[] { "Nop.Web.Controllers" }); //login routes.MapLocalizedRoute("Login", "login/", new { controller = "Customer", action = "Login" }, new[] { "Nop.Web.Controllers" }); //register routes.MapLocalizedRoute("Register", "register/", new { controller = "Customer", action = "Register" }, new[] { "Nop.Web.Controllers" }); //logout routes.MapLocalizedRoute("Logout", "logout/", new { controller = "Customer", action = "Logout" }, new[] { "Nop.Web.Controllers" }); //shopping cart routes.MapLocalizedRoute("ShoppingCart", "cart/", new { controller = "ShoppingCart", action = "Cart" }, new[] { "Nop.Web.Controllers" }); //wishlist routes.MapLocalizedRoute("Wishlist", "wishlist/{customerGuid}", new { controller = "ShoppingCart", action = "Wishlist", customerGuid = UrlParameter.Optional }, new[] { "Nop.Web.Controllers" }); //customer routes.MapLocalizedRoute("CustomerInfo", "customer/info", new { controller = "Customer", action = "Info" }, new[] { "Nop.Web.Controllers" }); //....省略剩余代码 }
RouteProvider的方法RegisterRoutes就是真正自定义路由规则。我们如果要找一个Url对应的Controller就要先在这里面查找一下,才好定位到是哪一个Controller。至于插件的路由我接下来会用专门一篇文章来介绍Nop的插件机制。
Nop.Web.Infrastructure.GenericUrlRouteProvider
GenericUrlRouteProvider和Nop.Web.Infrastructure.RouteProvider是相同级别的都是实现了接口IRouteProvider,区别GenericUrlRouteProvider定义的一般公用的Url规则。如下代码:
public partial class GenericUrlRouteProvider : IRouteProvider { public void RegisterRoutes(RouteCollection routes) { //generic URLs routes.MapGenericPathRoute("GenericUrl", "{generic_se_name}", new {controller = "Common", action = "GenericUrl"}, new[] {"Nop.Web.Controllers"}); //define this routes to use in UI views (in case if you want to customize some of them later) routes.MapLocalizedRoute("Product", "{SeName}", new { controller = "Product", action = "ProductDetails" }, new[] {"Nop.Web.Controllers"}); routes.MapLocalizedRoute("Category", "{SeName}", new { controller = "Catalog", action = "Category" }, new[] { "Nop.Web.Controllers" }); routes.MapLocalizedRoute("Manufacturer", "{SeName}", new { controller = "Catalog", action = "Manufacturer" }, new[] { "Nop.Web.Controllers" }); routes.MapLocalizedRoute("Vendor", "{SeName}", new { controller = "Catalog", action = "Vendor" }, new[] { "Nop.Web.Controllers" }); routes.MapLocalizedRoute("NewsItem", "{SeName}", new { controller = "News", action = "NewsItem" }, new[] { "Nop.Web.Controllers" }); routes.MapLocalizedRoute("BlogPost", "{SeName}", new { controller = "Blog", action = "BlogPost" }, new[] { "Nop.Web.Controllers" }); routes.MapLocalizedRoute("Topic", "{SeName}", new { controller = "Topic", action = "TopicDetails" }, new[] { "Nop.Web.Controllers" }); } public int Priority { get { //it should be the last route //we do not set it to -int.MaxValue so it could be overriden (if required) return -1000000; } } }
可以看到上面定义了商品列表、商品详情及新闻等相关的Url规则。