NopCommerce源码架构详解--路由相关源码分析

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

NopCommerce源码架构详解--路由相关源码分析

上面就是NopCommerce路由相关功能主要的类、接口及关系。有以下类:

1、mvcApplication

2、IRoutePublisher、RoutePublisher

3、IRouteProvider、RouteProvider、GenericUrlRouteProvider

其中RoutePublisher是用来发布RouteProvider、GenericUrlRouteProvider里面配置的路由规则的,二者都有一个抽象的接口。接下来我们就来看看这些类或接口中代码是如何实现的:

Nop.Web.MvcApplication


  1. public static void RegisterRoutes(RouteCollection routes)
  2. {
  3. routes.IgnoreRoute("favicon.ico");
  4. routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
  5. //注册自定义的路由规则及插件相关路由
  6. var routePublisher = EngineContext.Current.Resolve<IRoutePublisher>();
  7. routePublisher.RegisterRoutes(routes);
  8. routes.MapRoute(
  9. "Default", // Route name
  10. "{controller}/{action}/{id}", // URL with parameters
  11. new { controller = "Home", action = "Index", id = UrlParameter.Optional },
  12. new[] { "Nop.Web.Controllers" }
  13. );
  14. }


EngineContext.Current.Resolve<IRoutePublisher>()这名代码表示,从Ioc容器Autofac中获取接口IRoutePublisher所依赖的具体实现类。如果对Nop的依赖注入原理还是很了解,可以参考我之前的文章NopCommerce源码架构详解--Autofac依赖注入分析

在Nop.Web.Framework.DependencyRegistrar中有以下代码:


  1. builder.RegisterType<RoutePublisher>().As<IRoutePublisher>().SingleInstance();

Nop.Web.Framework.Mvc.Routes.RoutePublisher

我们找到这个RoutePublisher类(Nop.Web.Framework.Mvc.Routes.RoutePublisher)其中关键的代码如下:


  1. public virtual void RegisterRoutes(RouteCollection routes)
  2. {
  3. //通过typeFinder找出所有(包括插件)实现了接口IRouteProvider相关的类型
  4.  var routeProviderTypes = typeFinder.FindClassesOfType<IRouteProvider>();
  5. var routeProviders = new List<IRouteProvider>();
  6. foreach (var providerType in routeProviderTypes)
  7. {
  8. //Ignore not installed plugins
  9. var plugin = FindPlugin(providerType);
  10. if (plugin != null && !plugin.Installed)
  11. continue;
  12. //采用反射动态创建IRouteProvider的具体类的实例
  13. var provider = Activator.CreateInstance(providerType) as IRouteProvider;
  14. routeProviders.Add(provider);
  15. }
  16. routeProviders = routeProviders.OrderByDescending(rp => rp.Priority).ToList();
  17. //依次调用RouteProvider的RegisterRoutes方法,注册路由规则
  18. routeProviders.ForEach(rp => rp.RegisterRoutes(routes));
  19. }

Nop.Web.Infrastructure.RouteProvider

现在我们来看看一个具体的RouteProvider里面都有些什么东东。在项目Nop.Web根目录下面有一个文件夹Infrastructure,里面有一个RouteProvider类,如下图:

NopCommerce源码架构详解--路由相关源码分析


  1. public void RegisterRoutes(RouteCollection routes)
  2. {
  3. //We reordered our routes so the most used ones are on top. It can improve performance.
  4. //home page
  5. routes.MapLocalizedRoute("HomePage",
  6. "",
  7. new { controller = "Home", action = "Index" },
  8. new[] { "Nop.Web.Controllers" });
  9. //widgets
  10. //we have this route for performance optimization because named routes are MUCH faster than usual Html.Action(...)
  11. //and this route is highly used
  12. routes.MapRoute("WidgetsByZone",
  13. "widgetsbyzone/",
  14. new { controller = "Widget", action = "WidgetsByZone" },
  15. new[] { "Nop.Web.Controllers" });
  16. //login
  17. routes.MapLocalizedRoute("Login",
  18. "login/",
  19. new { controller = "Customer", action = "Login" },
  20. new[] { "Nop.Web.Controllers" });
  21. //register
  22. routes.MapLocalizedRoute("Register",
  23. "register/",
  24. new { controller = "Customer", action = "Register" },
  25. new[] { "Nop.Web.Controllers" });
  26. //logout
  27. routes.MapLocalizedRoute("Logout",
  28. "logout/",
  29. new { controller = "Customer", action = "Logout" },
  30. new[] { "Nop.Web.Controllers" });
  31. //shopping cart
  32. routes.MapLocalizedRoute("ShoppingCart",
  33. "cart/",
  34. new { controller = "ShoppingCart", action = "Cart" },
  35. new[] { "Nop.Web.Controllers" });
  36. //wishlist
  37. routes.MapLocalizedRoute("Wishlist",
  38. "wishlist/{customerGuid}",
  39. new { controller = "ShoppingCart", action = "Wishlist", customerGuid = UrlParameter.Optional },
  40. new[] { "Nop.Web.Controllers" });
  41. //customer
  42. routes.MapLocalizedRoute("CustomerInfo",
  43. "customer/info",
  44. new { controller = "Customer", action = "Info" },
  45. new[] { "Nop.Web.Controllers" });
  46. //....省略剩余代码
  47. }

RouteProvider的方法RegisterRoutes就是真正自定义路由规则。我们如果要找一个Url对应的Controller就要先在这里面查找一下,才好定位到是哪一个Controller。至于插件的路由我接下来会用专门一篇文章来介绍Nop的插件机制。

Nop.Web.Infrastructure.GenericUrlRouteProvider

GenericUrlRouteProvider和Nop.Web.Infrastructure.RouteProvider是相同级别的都是实现了接口IRouteProvider,区别GenericUrlRouteProvider定义的一般公用的Url规则。如下代码:


  1. public partial class GenericUrlRouteProvider : IRouteProvider
  2. {
  3. public void RegisterRoutes(RouteCollection routes)
  4. {
  5. //generic URLs
  6. routes.MapGenericPathRoute("GenericUrl",
  7. "{generic_se_name}",
  8. new {controller = "Common", action = "GenericUrl"},
  9. new[] {"Nop.Web.Controllers"});
  10. //define this routes to use in UI views (in case if you want to customize some of them later)
  11. routes.MapLocalizedRoute("Product",
  12. "{SeName}",
  13. new { controller = "Product", action = "ProductDetails" },
  14. new[] {"Nop.Web.Controllers"});
  15. routes.MapLocalizedRoute("Category",
  16. "{SeName}",
  17. new { controller = "Catalog", action = "Category" },
  18. new[] { "Nop.Web.Controllers" });
  19. routes.MapLocalizedRoute("Manufacturer",
  20. "{SeName}",
  21. new { controller = "Catalog", action = "Manufacturer" },
  22. new[] { "Nop.Web.Controllers" });
  23. routes.MapLocalizedRoute("Vendor",
  24. "{SeName}",
  25. new { controller = "Catalog", action = "Vendor" },
  26. new[] { "Nop.Web.Controllers" });
  27. routes.MapLocalizedRoute("NewsItem",
  28. "{SeName}",
  29. new { controller = "News", action = "NewsItem" },
  30. new[] { "Nop.Web.Controllers" });
  31. routes.MapLocalizedRoute("BlogPost",
  32. "{SeName}",
  33. new { controller = "Blog", action = "BlogPost" },
  34. new[] { "Nop.Web.Controllers" });
  35. routes.MapLocalizedRoute("Topic",
  36. "{SeName}",
  37. new { controller = "Topic", action = "TopicDetails" },
  38. new[] { "Nop.Web.Controllers" });
  39. }
  40. public int Priority
  41. {
  42. get
  43. {
  44. //it should be the last route
  45. //we do not set it to -int.MaxValue so it could be overriden (if required)
  46. return -1000000;
  47. }
  48. }
  49. }
可以看到上面可以看到上面定义了商品列表、商品详情及新闻等相关的Url规则。