首页 > 代码库 > nopCommerce 3.9 大波浪系列 之 路由扩展 [多语言Seo的实现]

nopCommerce 3.9 大波浪系列 之 路由扩展 [多语言Seo的实现]

一.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中的路由注册代码

技术分享
  1 using System.Web.Mvc;
  2 using System.Web.Routing;
  3 using Nop.Web.Framework.Localization;
  4 using Nop.Web.Framework.Mvc.Routes;
  5 
  6 namespace Nop.Web.Infrastructure
  7 {
  8     public partial class RouteProvider : IRouteProvider
  9     {
 10         public void RegisterRoutes(RouteCollection routes)
 11         {
 12             //We reordered our routes so the most used ones are on top. It can improve performance.
 13             //本地化路由
 14             //home page
 15             routes.MapLocalizedRoute("HomePage",
 16                             "",
 17                             new { controller = "Home", action = "Index" },
 18                             new[] { "Nop.Web.Controllers" });
 19             //widgets
 20             //we have this route for performance optimization because named routes are MUCH faster than usual Html.Action(...)
 21             //and this route is highly used
 22             routes.MapRoute("WidgetsByZone",
 23                             "widgetsbyzone/",
 24                             new { controller = "Widget", action = "WidgetsByZone" },
 25                             new[] { "Nop.Web.Controllers" });
 26 
 27             //login
 28             routes.MapLocalizedRoute("Login",
 29                             "login/",
 30                             new { controller = "Customer", action = "Login" },
 31                             new[] { "Nop.Web.Controllers" });
 32             //register
 33             routes.MapLocalizedRoute("Register",
 34                             "register/",
 35                             new { controller = "Customer", action = "Register" },
 36                             new[] { "Nop.Web.Controllers" });
 37             //logout
 38             routes.MapLocalizedRoute("Logout",
 39                             "logout/",
 40                             new { controller = "Customer", action = "Logout" },
 41                             new[] { "Nop.Web.Controllers" });
 42 
 43             //shopping cart
 44             routes.MapLocalizedRoute("ShoppingCart",
 45                             "cart/",
 46                             new { controller = "ShoppingCart", action = "Cart" },
 47                             new[] { "Nop.Web.Controllers" });
 48             //estimate shipping
 49             routes.MapLocalizedRoute("EstimateShipping",
 50                             "cart/estimateshipping",
 51                             new {controller = "ShoppingCart", action = "GetEstimateShipping"},
 52                             new[] {"Nop.Web.Controllers"});
 53             //wishlist
 54             routes.MapLocalizedRoute("Wishlist",
 55                             "wishlist/{customerGuid}",
 56                             new { controller = "ShoppingCart", action = "Wishlist", customerGuid = UrlParameter.Optional },
 57                             new[] { "Nop.Web.Controllers" });
 58 
 59             //customer account links
 60             routes.MapLocalizedRoute("CustomerInfo",
 61                             "customer/info",
 62                             new { controller = "Customer", action = "Info" },
 63                             new[] { "Nop.Web.Controllers" });
 64             routes.MapLocalizedRoute("CustomerAddresses",
 65                             "customer/addresses",
 66                             new { controller = "Customer", action = "Addresses" },
 67                             new[] { "Nop.Web.Controllers" });
 68             routes.MapLocalizedRoute("CustomerOrders",
 69                             "order/history",
 70                             new { controller = "Order", action = "CustomerOrders" },
 71                             new[] { "Nop.Web.Controllers" });
 72 
 73             //contact us
 74             routes.MapLocalizedRoute("ContactUs",
 75                             "contactus",
 76                             new { controller = "Common", action = "ContactUs" },
 77                             new[] { "Nop.Web.Controllers" });
 78             //sitemap
 79             routes.MapLocalizedRoute("Sitemap",
 80                             "sitemap",
 81                             new { controller = "Common", action = "Sitemap" },
 82                             new[] { "Nop.Web.Controllers" });
 83 
 84             //product search
 85             routes.MapLocalizedRoute("ProductSearch",
 86                             "search/",
 87                             new { controller = "Catalog", action = "Search" },
 88                             new[] { "Nop.Web.Controllers" });
 89             routes.MapLocalizedRoute("ProductSearchAutoComplete",
 90                             "catalog/searchtermautocomplete",
 91                             new { controller = "Catalog", action = "SearchTermAutoComplete" },
 92                             new[] { "Nop.Web.Controllers" });
 93 
 94             //change currency (AJAX link)
 95             routes.MapLocalizedRoute("ChangeCurrency",
 96                             "changecurrency/{customercurrency}",
 97                             new { controller = "Common", action = "SetCurrency" },
 98                             new { customercurrency = @"\d+" },
 99                             new[] { "Nop.Web.Controllers" });
100             //change language (AJAX link)
101             routes.MapLocalizedRoute("ChangeLanguage",
102                             "changelanguage/{langid}",
103                             new { controller = "Common", action = "SetLanguage" },
104                             new { langid = @"\d+" },
105                             new[] { "Nop.Web.Controllers" });
106             //change tax (AJAX link)
107             routes.MapLocalizedRoute("ChangeTaxType",
108                             "changetaxtype/{customertaxtype}",
109                             new { controller = "Common", action = "SetTaxType" },
110                             new { customertaxtype = @"\d+" },
111                             new[] { "Nop.Web.Controllers" });
112 
113             //recently viewed products
114             routes.MapLocalizedRoute("RecentlyViewedProducts",
115                             "recentlyviewedproducts/",
116                             new { controller = "Product", action = "RecentlyViewedProducts" },
117                             new[] { "Nop.Web.Controllers" });
118             //new products
119             routes.MapLocalizedRoute("NewProducts",
120                             "newproducts/",
121                             new { controller = "Product", action = "NewProducts" },
122                             new[] { "Nop.Web.Controllers" });
123             //blog
124             routes.MapLocalizedRoute("Blog",
125                             "blog",
126                             new { controller = "Blog", action = "List" },
127                             new[] { "Nop.Web.Controllers" });
128             //news
129             routes.MapLocalizedRoute("NewsArchive",
130                             "news",
131                             new { controller = "News", action = "List" },
132                             new[] { "Nop.Web.Controllers" });
133 
134             //forum
135             routes.MapLocalizedRoute("Boards",
136                             "boards",
137                             new { controller = "Boards", action = "Index" },
138                             new[] { "Nop.Web.Controllers" });
139 
140             //compare products
141             routes.MapLocalizedRoute("CompareProducts",
142                             "compareproducts/",
143                             new { controller = "Product", action = "CompareProducts" },
144                             new[] { "Nop.Web.Controllers" });
145 
146             //product tags
147             routes.MapLocalizedRoute("ProductTagsAll",
148                             "producttag/all/",
149                             new { controller = "Catalog", action = "ProductTagsAll" },
150                             new[] { "Nop.Web.Controllers" });
151 
152             //manufacturers
153             routes.MapLocalizedRoute("ManufacturerList",
154                             "manufacturer/all/",
155                             new { controller = "Catalog", action = "ManufacturerAll" },
156                             new[] { "Nop.Web.Controllers" });
157             //vendors
158             routes.MapLocalizedRoute("VendorList",
159                             "vendor/all/",
160                             new { controller = "Catalog", action = "VendorAll" },
161                             new[] { "Nop.Web.Controllers" });
162 
163 
164             //add product to cart (without any attributes and options). used on catalog pages.
165             routes.MapLocalizedRoute("AddProductToCart-Catalog",
166                             "addproducttocart/catalog/{productId}/{shoppingCartTypeId}/{quantity}",
167                             new { controller = "ShoppingCart", action = "AddProductToCart_Catalog" },
168                             new { productId = @"\d+", shoppingCartTypeId = @"\d+", quantity = @"\d+" },
169                             new[] { "Nop.Web.Controllers" });
170             //add product to cart (with attributes and options). used on the product details pages.
171             routes.MapLocalizedRoute("AddProductToCart-Details",
172                             "addproducttocart/details/{productId}/{shoppingCartTypeId}",
173                             new { controller = "ShoppingCart", action = "AddProductToCart_Details" },
174                             new { productId = @"\d+", shoppingCartTypeId = @"\d+" },
175                             new[] { "Nop.Web.Controllers" });
176 
177             //product tags
178             routes.MapLocalizedRoute("ProductsByTag",
179                             "producttag/{productTagId}/{SeName}",
180                             new { controller = "Catalog", action = "ProductsByTag", SeName = UrlParameter.Optional },
181                             new { productTagId = @"\d+" },
182                             new[] { "Nop.Web.Controllers" });
183             //comparing products
184             routes.MapLocalizedRoute("AddProductToCompare",
185                             "compareproducts/add/{productId}",
186                             new { controller = "Product", action = "AddProductToCompareList" },
187                             new { productId = @"\d+" },
188                             new[] { "Nop.Web.Controllers" });
189             //product email a friend
190             routes.MapLocalizedRoute("ProductEmailAFriend",
191                             "productemailafriend/{productId}",
192                             new { controller = "Product", action = "ProductEmailAFriend" },
193                             new { productId = @"\d+" },
194                             new[] { "Nop.Web.Controllers" });
195             //reviews
196             routes.MapLocalizedRoute("ProductReviews",
197                             "productreviews/{productId}",
198                             new { controller = "Product", action = "ProductReviews" },
199                             new[] { "Nop.Web.Controllers" });
200             routes.MapLocalizedRoute("CustomerProductReviews",
201                             "customer/productreviews",
202                             new { controller = "Product", action = "CustomerProductReviews" },
203                             new[] { "Nop.Web.Controllers" });
204             routes.MapLocalizedRoute("CustomerProductReviewsPaged",
205                             "customer/productreviews/page/{page}",
206                             new { controller = "Product", action = "CustomerProductReviews" },
207                             new { page = @"\d+" },
208                             new[] { "Nop.Web.Controllers" });
209             //back in stock notifications
210             routes.MapLocalizedRoute("BackInStockSubscribePopup",
211                             "backinstocksubscribe/{productId}",
212                             new { controller = "BackInStockSubscription", action = "SubscribePopup" },
213                             new { productId = @"\d+" },
214                             new[] { "Nop.Web.Controllers" });
215             routes.MapLocalizedRoute("BackInStockSubscribeSend",
216                             "backinstocksubscribesend/{productId}",
217                             new { controller = "BackInStockSubscription", action = "SubscribePopupPOST" },
218                             new { productId = @"\d+" },
219                             new[] { "Nop.Web.Controllers" });
220             //downloads
221             routes.MapRoute("GetSampleDownload",
222                             "download/sample/{productid}",
223                             new { controller = "Download", action = "Sample" },
224                             new { productid = @"\d+" },
225                             new[] { "Nop.Web.Controllers" });
226 
227 
228 
229             //checkout pages
230             routes.MapLocalizedRoute("Checkout",
231                             "checkout/",
232                             new { controller = "Checkout", action = "Index" },
233                             new[] { "Nop.Web.Controllers" });
234             routes.MapLocalizedRoute("CheckoutOnePage",
235                             "onepagecheckout/",
236                             new { controller = "Checkout", action = "OnePageCheckout" },
237                             new[] { "Nop.Web.Controllers" });
238             routes.MapLocalizedRoute("CheckoutShippingAddress",
239                             "checkout/shippingaddress",
240                             new { controller = "Checkout", action = "ShippingAddress" },
241                             new[] { "Nop.Web.Controllers" });
242             routes.MapLocalizedRoute("CheckoutSelectShippingAddress",
243                             "checkout/selectshippingaddress",
244                             new { controller = "Checkout", action = "SelectShippingAddress" },
245                             new[] { "Nop.Web.Controllers" });
246             routes.MapLocalizedRoute("CheckoutBillingAddress",
247                             "checkout/billingaddress",
248                             new { controller = "Checkout", action = "BillingAddress" },
249                             new[] { "Nop.Web.Controllers" });
250             routes.MapLocalizedRoute("CheckoutSelectBillingAddress",
251                             "checkout/selectbillingaddress",
252                             new { controller = "Checkout", action = "SelectBillingAddress" },
253                             new[] { "Nop.Web.Controllers" });
254             routes.MapLocalizedRoute("CheckoutShippingMethod",
255                             "checkout/shippingmethod",
256                             new { controller = "Checkout", action = "ShippingMethod" },
257                             new[] { "Nop.Web.Controllers" });
258             routes.MapLocalizedRoute("CheckoutPaymentMethod",
259                             "checkout/paymentmethod",
260                             new { controller = "Checkout", action = "PaymentMethod" },
261                             new[] { "Nop.Web.Controllers" });
262             routes.MapLocalizedRoute("CheckoutPaymentInfo",
263                             "checkout/paymentinfo",
264                             new { controller = "Checkout", action = "PaymentInfo" },
265                             new[] { "Nop.Web.Controllers" });
266             routes.MapLocalizedRoute("CheckoutConfirm",
267                             "checkout/confirm",
268                             new { controller = "Checkout", action = "Confirm" },
269                             new[] { "Nop.Web.Controllers" });
270             routes.MapLocalizedRoute("CheckoutCompleted",
271                             "checkout/completed/{orderId}",
272                             new { controller = "Checkout", action = "Completed", orderId = UrlParameter.Optional },
273                             new { orderId = @"\d+" },
274                             new[] { "Nop.Web.Controllers" });
275 
276             //subscribe newsletters
277             routes.MapLocalizedRoute("SubscribeNewsletter",
278                             "subscribenewsletter",
279                             new { controller = "Newsletter", action = "SubscribeNewsletter" },
280                             new[] { "Nop.Web.Controllers" });
281 
282             //email wishlist
283             routes.MapLocalizedRoute("EmailWishlist",
284                             "emailwishlist",
285                             new { controller = "ShoppingCart", action = "EmailWishlist" },
286                             new[] { "Nop.Web.Controllers" });
287 
288             //login page for checkout as guest
289             routes.MapLocalizedRoute("LoginCheckoutAsGuest",
290                             "login/checkoutasguest",
291                             new { controller = "Customer", action = "Login", checkoutAsGuest = true },
292                             new[] { "Nop.Web.Controllers" });
293             //register result page
294             routes.MapLocalizedRoute("RegisterResult",
295                             "registerresult/{resultId}",
296                             new { controller = "Customer", action = "RegisterResult" },
297                             new { resultId = @"\d+" },
298                             new[] { "Nop.Web.Controllers" });
299             //check username availability
300             routes.MapLocalizedRoute("CheckUsernameAvailability",
301                             "customer/checkusernameavailability",
302                             new { controller = "Customer", action = "CheckUsernameAvailability" },
303                             new[] { "Nop.Web.Controllers" });
304 
305             //passwordrecovery
306             routes.MapLocalizedRoute("PasswordRecovery",
307                             "passwordrecovery",
308                             new { controller = "Customer", action = "PasswordRecovery" },
309                             new[] { "Nop.Web.Controllers" });
310             //password recovery confirmation
311             routes.MapLocalizedRoute("PasswordRecoveryConfirm",
312                             "passwordrecovery/confirm",
313                             new { controller = "Customer", action = "PasswordRecoveryConfirm" },
314                             new[] { "Nop.Web.Controllers" });
315 
316             //topics
317             routes.MapLocalizedRoute("TopicPopup",
318                             "t-popup/{SystemName}",
319                             new { controller = "Topic", action = "TopicDetailsPopup" },
320                             new[] { "Nop.Web.Controllers" });
321 
322             //blog
323             routes.MapLocalizedRoute("BlogByTag",
324                             "blog/tag/{tag}",
325                             new { controller = "Blog", action = "BlogByTag" },
326                             new[] { "Nop.Web.Controllers" });
327             routes.MapLocalizedRoute("BlogByMonth",
328                             "blog/month/{month}",
329                             new { controller = "Blog", action = "BlogByMonth" },
330                             new[] { "Nop.Web.Controllers" });
331             //blog RSS
332             routes.MapLocalizedRoute("BlogRSS",
333                             "blog/rss/{languageId}",
334                             new { controller = "Blog", action = "ListRss" },
335                             new { languageId = @"\d+" },
336                             new[] { "Nop.Web.Controllers" });
337 
338             //news RSS
339             routes.MapLocalizedRoute("NewsRSS",
340                             "news/rss/{languageId}",
341                             new { controller = "News", action = "ListRss" },
342                             new { languageId = @"\d+" },
343                             new[] { "Nop.Web.Controllers" });
344 
345             //set review helpfulness (AJAX link)
346             routes.MapRoute("SetProductReviewHelpfulness",
347                             "setproductreviewhelpfulness",
348                             new { controller = "Product", action = "SetProductReviewHelpfulness" },
349                             new[] { "Nop.Web.Controllers" });
350 
351             //customer account links
352             routes.MapLocalizedRoute("CustomerReturnRequests",
353                             "returnrequest/history",
354                             new { controller = "ReturnRequest", action = "CustomerReturnRequests" },
355                             new[] { "Nop.Web.Controllers" });
356             routes.MapLocalizedRoute("CustomerDownloadableProducts",
357                             "customer/downloadableproducts",
358                             new { controller = "Customer", action = "DownloadableProducts" },
359                             new[] { "Nop.Web.Controllers" });
360             routes.MapLocalizedRoute("CustomerBackInStockSubscriptions",
361                             "backinstocksubscriptions/manage",
362                             new { controller = "BackInStockSubscription", action = "CustomerSubscriptions" },
363                             new[] { "Nop.Web.Controllers" });
364             routes.MapLocalizedRoute("CustomerBackInStockSubscriptionsPaged",
365                             "backinstocksubscriptions/manage/{page}",
366                             new { controller = "BackInStockSubscription", action = "CustomerSubscriptions", page = UrlParameter.Optional },
367                             new { page = @"\d+" },
368                             new[] { "Nop.Web.Controllers" });
369             routes.MapLocalizedRoute("CustomerRewardPoints",
370                             "rewardpoints/history",
371                             new { controller = "Order", action = "CustomerRewardPoints" },
372                             new[] { "Nop.Web.Controllers" });
373             routes.MapLocalizedRoute("CustomerRewardPointsPaged",
374                             "rewardpoints/history/page/{page}",
375                             new { controller = "Order", action = "CustomerRewardPoints" },
376                             new { page = @"\d+" },
377                             new[] { "Nop.Web.Controllers" });
378             routes.MapLocalizedRoute("CustomerChangePassword",
379                             "customer/changepassword",
380                             new { controller = "Customer", action = "ChangePassword" },
381                             new[] { "Nop.Web.Controllers" });
382             routes.MapLocalizedRoute("CustomerAvatar",
383                             "customer/avatar",
384                             new { controller = "Customer", action = "Avatar" },
385                             new[] { "Nop.Web.Controllers" });
386             routes.MapLocalizedRoute("AccountActivation",
387                             "customer/activation",
388                             new { controller = "Customer", action = "AccountActivation" },
389                             new[] { "Nop.Web.Controllers" });
390             routes.MapLocalizedRoute("EmailRevalidation",
391                             "customer/revalidateemail",
392                             new { controller = "Customer", action = "EmailRevalidation" },
393                             new[] { "Nop.Web.Controllers" });
394             routes.MapLocalizedRoute("CustomerForumSubscriptions",
395                             "boards/forumsubscriptions",
396                             new { controller = "Boards", action = "CustomerForumSubscriptions" },
397                             new[] { "Nop.Web.Controllers" });
398             routes.MapLocalizedRoute("CustomerForumSubscriptionsPaged",
399                             "boards/forumsubscriptions/{page}",
400                             new { controller = "Boards", action = "CustomerForumSubscriptions", page = UrlParameter.Optional },
401                             new { page = @"\d+" },
402                             new[] { "Nop.Web.Controllers" });
403             routes.MapLocalizedRoute("CustomerAddressEdit",
404                             "customer/addressedit/{addressId}",
405                             new { controller = "Customer", action = "AddressEdit" },
406                             new { addressId = @"\d+" },
407                             new[] { "Nop.Web.Controllers" });
408             routes.MapLocalizedRoute("CustomerAddressAdd",
409                             "customer/addressadd",
410                             new { controller = "Customer", action = "AddressAdd" },
411                             new[] { "Nop.Web.Controllers" });
412             //customer profile page
413             routes.MapLocalizedRoute("CustomerProfile",
414                             "profile/{id}",
415                             new { controller = "Profile", action = "Index" },
416                             new { id = @"\d+" },
417                             new[] { "Nop.Web.Controllers" });
418             routes.MapLocalizedRoute("CustomerProfilePaged",
419                             "profile/{id}/page/{page}",
420                             new { controller = "Profile", action = "Index" },
421                             new { id = @"\d+", page = @"\d+" },
422                             new[] { "Nop.Web.Controllers" });
423 
424             //orders
425             routes.MapLocalizedRoute("OrderDetails",
426                             "orderdetails/{orderId}",
427                             new { controller = "Order", action = "Details" },
428                             new { orderId = @"\d+" },
429                             new[] { "Nop.Web.Controllers" });
430             routes.MapLocalizedRoute("ShipmentDetails",
431                             "orderdetails/shipment/{shipmentId}",
432                             new { controller = "Order", action = "ShipmentDetails" },
433                             new[] { "Nop.Web.Controllers" });
434             routes.MapLocalizedRoute("ReturnRequest",
435                             "returnrequest/{orderId}",
436                             new { controller = "ReturnRequest", action = "ReturnRequest" },
437                             new { orderId = @"\d+" },
438                             new[] { "Nop.Web.Controllers" });
439             routes.MapLocalizedRoute("ReOrder",
440                             "reorder/{orderId}",
441                             new { controller = "Order", action = "ReOrder" },
442                             new { orderId = @"\d+" },
443                             new[] { "Nop.Web.Controllers" });
444             routes.MapLocalizedRoute("GetOrderPdfInvoice",
445                             "orderdetails/pdf/{orderId}",
446                             new { controller = "Order", action = "GetPdfInvoice" },
447                             new[] { "Nop.Web.Controllers" });
448             routes.MapLocalizedRoute("PrintOrderDetails",
449                             "orderdetails/print/{orderId}",
450                             new { controller = "Order", action = "PrintOrderDetails" },
451                             new[] { "Nop.Web.Controllers" });
452             //order downloads
453             routes.MapRoute("GetDownload",
454                             "download/getdownload/{orderItemId}/{agree}",
455                             new { controller = "Download", action = "GetDownload", agree = UrlParameter.Optional },
456                             new { orderItemId = new GuidConstraint(false) },
457                             new[] { "Nop.Web.Controllers" });
458             routes.MapRoute("GetLicense",
459                             "download/getlicense/{orderItemId}/",
460                             new { controller = "Download", action = "GetLicense" },
461                             new { orderItemId = new GuidConstraint(false) },
462                             new[] { "Nop.Web.Controllers" });
463             routes.MapLocalizedRoute("DownloadUserAgreement",
464                             "customer/useragreement/{orderItemId}",
465                             new { controller = "Customer", action = "UserAgreement" },
466                             new { orderItemId = new GuidConstraint(false) },
467                             new[] { "Nop.Web.Controllers" });
468             routes.MapRoute("GetOrderNoteFile",
469                             "download/ordernotefile/{ordernoteid}",
470                             new { controller = "Download", action = "GetOrderNoteFile" },
471                             new { ordernoteid = @"\d+" },
472                             new[] { "Nop.Web.Controllers" });
473 
474             //contact vendor
475             routes.MapLocalizedRoute("ContactVendor",
476                             "contactvendor/{vendorId}",
477                             new { controller = "Common", action = "ContactVendor" },
478                             new[] { "Nop.Web.Controllers" });
479             //apply for vendor account
480             routes.MapLocalizedRoute("ApplyVendorAccount",
481                             "vendor/apply",
482                             new { controller = "Vendor", action = "ApplyVendor" },
483                             new[] { "Nop.Web.Controllers" });
484             //vendor info
485             routes.MapLocalizedRoute("CustomerVendorInfo",
486                             "customer/vendorinfo",
487                             new { controller = "Vendor", action = "Info" },
488                             new[] { "Nop.Web.Controllers" });
489 
490             //poll vote AJAX link
491             routes.MapLocalizedRoute("PollVote",
492                             "poll/vote",
493                             new { controller = "Poll", action = "Vote" },
494                             new[] { "Nop.Web.Controllers" });
495 
496             //comparing products
497             routes.MapLocalizedRoute("RemoveProductFromCompareList",
498                             "compareproducts/remove/{productId}",
499                             new { controller = "Product", action = "RemoveProductFromCompareList" },
500                             new[] { "Nop.Web.Controllers" });
501             routes.MapLocalizedRoute("ClearCompareList",
502                             "clearcomparelist/",
503                             new { controller = "Product", action = "ClearCompareList" },
504                             new[] { "Nop.Web.Controllers" });
505 
506             //new RSS
507             routes.MapLocalizedRoute("NewProductsRSS",
508                             "newproducts/rss",
509                             new { controller = "Product", action = "NewProductsRss" },
510                             new[] { "Nop.Web.Controllers" });
511 
512             //get state list by country ID  (AJAX link)
513             routes.MapRoute("GetStatesByCountryId",
514                             "country/getstatesbycountryid/",
515                             new { controller = "Country", action = "GetStatesByCountryId" },
516                             new[] { "Nop.Web.Controllers" });
517 
518             //EU Cookie law accept button handler (AJAX link)
519             routes.MapRoute("EuCookieLawAccept",
520                             "eucookielawaccept",
521                             new { controller = "Common", action = "EuCookieLawAccept" },
522                             new[] { "Nop.Web.Controllers" });
523 
524             //authenticate topic AJAX link
525             routes.MapLocalizedRoute("TopicAuthenticate",
526                             "topic/authenticate",
527                             new { controller = "Topic", action = "Authenticate" },
528                             new[] { "Nop.Web.Controllers" });
529 
530             //product attributes with "upload file" type
531             routes.MapLocalizedRoute("UploadFileProductAttribute",
532                             "uploadfileproductattribute/{attributeId}",
533                             new { controller = "ShoppingCart", action = "UploadFileProductAttribute" },
534                             new { attributeId = @"\d+" },
535                             new[] { "Nop.Web.Controllers" });
536             //checkout attributes with "upload file" type
537             routes.MapLocalizedRoute("UploadFileCheckoutAttribute",
538                             "uploadfilecheckoutattribute/{attributeId}",
539                             new { controller = "ShoppingCart", action = "UploadFileCheckoutAttribute" },
540                             new { attributeId = @"\d+" },
541                             new[] { "Nop.Web.Controllers" });
542             //return request with "upload file" tsupport
543             routes.MapLocalizedRoute("UploadFileReturnRequest",
544                             "uploadfilereturnrequest",
545                             new { controller = "ReturnRequest", action = "UploadFileReturnRequest" },
546                             new[] { "Nop.Web.Controllers" });
547 
548             //forums
549             routes.MapLocalizedRoute("ActiveDiscussions",
550                             "boards/activediscussions",
551                             new { controller = "Boards", action = "ActiveDiscussions" },
552                             new[] { "Nop.Web.Controllers" });
553             routes.MapLocalizedRoute("ActiveDiscussionsPaged",
554                             "boards/activediscussions/page/{page}",
555                             new { controller = "Boards", action = "ActiveDiscussions", page = UrlParameter.Optional },
556                             new { page = @"\d+" },
557                             new[] { "Nop.Web.Controllers" });
558             routes.MapLocalizedRoute("ActiveDiscussionsRSS",
559                             "boards/activediscussionsrss",
560                             new { controller = "Boards", action = "ActiveDiscussionsRSS" },
561                             new[] { "Nop.Web.Controllers" });
562             routes.MapLocalizedRoute("PostEdit",
563                             "boards/postedit/{id}",
564                             new { controller = "Boards", action = "PostEdit" },
565                             new { id = @"\d+" },
566                             new[] { "Nop.Web.Controllers" });
567             routes.MapLocalizedRoute("PostDelete",
568                             "boards/postdelete/{id}",
569                             new { controller = "Boards", action = "PostDelete" },
570                             new { id = @"\d+" },
571                             new[] { "Nop.Web.Controllers" });
572             routes.MapLocalizedRoute("PostCreate",
573                             "boards/postcreate/{id}",
574                             new { controller = "Boards", action = "PostCreate" },
575                             new { id = @"\d+" },
576                             new[] { "Nop.Web.Controllers" });
577             routes.MapLocalizedRoute("PostCreateQuote",
578                             "boards/postcreate/{id}/{quote}",
579                             new { controller = "Boards", action = "PostCreate" },
580                             new { id = @"\d+", quote = @"\d+" },
581                             new[] { "Nop.Web.Controllers" });
582             routes.MapLocalizedRoute("TopicEdit",
583                             "boards/topicedit/{id}",
584                             new { controller = "Boards", action = "TopicEdit" },
585                             new { id = @"\d+" },
586                             new[] { "Nop.Web.Controllers" });
587             routes.MapLocalizedRoute("TopicDelete",
588                             "boards/topicdelete/{id}",
589                             new { controller = "Boards", action = "TopicDelete" },
590                             new { id = @"\d+" },
591                             new[] { "Nop.Web.Controllers" });
592             routes.MapLocalizedRoute("TopicCreate",
593                             "boards/topiccreate/{id}",
594                             new { controller = "Boards", action = "TopicCreate" },
595                             new { id = @"\d+" },
596                             new[] { "Nop.Web.Controllers" });
597             routes.MapLocalizedRoute("TopicMove",
598                             "boards/topicmove/{id}",
599                             new { controller = "Boards", action = "TopicMove" },
600                             new { id = @"\d+" },
601                             new[] { "Nop.Web.Controllers" });
602             routes.MapLocalizedRoute("TopicWatch",
603                             "boards/topicwatch/{id}",
604                             new { controller = "Boards", action = "TopicWatch" },
605                             new { id = @"\d+" },
606                             new[] { "Nop.Web.Controllers" });
607             routes.MapLocalizedRoute("TopicSlug",
608                             "boards/topic/{id}/{slug}",
609                             new { controller = "Boards", action = "Topic", slug = UrlParameter.Optional },
610                             new { id = @"\d+" },
611                             new[] { "Nop.Web.Controllers" });
612             routes.MapLocalizedRoute("TopicSlugPaged",
613                             "boards/topic/{id}/{slug}/page/{page}",
614                             new { controller = "Boards", action = "Topic", slug = UrlParameter.Optional, page = UrlParameter.Optional },
615                             new { id = @"\d+", page = @"\d+" },
616                             new[] { "Nop.Web.Controllers" });
617             routes.MapLocalizedRoute("ForumWatch",
618                             "boards/forumwatch/{id}",
619                             new { controller = "Boards", action = "ForumWatch" },
620                             new { id = @"\d+" },
621                             new[] { "Nop.Web.Controllers" });
622             routes.MapLocalizedRoute("ForumRSS",
623                             "boards/forumrss/{id}",
624                             new { controller = "Boards", action = "ForumRSS" },
625                             new { id = @"\d+" },
626                             new[] { "Nop.Web.Controllers" });
627             routes.MapLocalizedRoute("ForumSlug",
628                             "boards/forum/{id}/{slug}",
629                             new { controller = "Boards", action = "Forum", slug = UrlParameter.Optional },
630                             new { id = @"\d+" },
631                             new[] { "Nop.Web.Controllers" });
632             routes.MapLocalizedRoute("ForumSlugPaged",
633                             "boards/forum/{id}/{slug}/page/{page}",
634                             new { controller = "Boards", action = "Forum", slug = UrlParameter.Optional, page = UrlParameter.Optional },
635                             new { id = @"\d+", page = @"\d+" },
636                             new[] { "Nop.Web.Controllers" });
637             routes.MapLocalizedRoute("ForumGroupSlug",
638                             "boards/forumgroup/{id}/{slug}",
639                             new { controller = "Boards", action = "ForumGroup", slug = UrlParameter.Optional },
640                             new { id = @"\d+" },
641                             new[] { "Nop.Web.Controllers" });
642             routes.MapLocalizedRoute("Search",
643                             "boards/search",
644                             new { controller = "Boards", action = "Search" },
645                             new[] { "Nop.Web.Controllers" });
646 
647             //private messages
648             routes.MapLocalizedRoute("PrivateMessages",
649                             "privatemessages/{tab}",
650                             new { controller = "PrivateMessages", action = "Index", tab = UrlParameter.Optional },
651                             new[] { "Nop.Web.Controllers" });
652             routes.MapLocalizedRoute("PrivateMessagesPaged",
653                             "privatemessages/{tab}/page/{page}",
654                             new { controller = "PrivateMessages", action = "Index", tab = UrlParameter.Optional },
655                             new { page = @"\d+" },
656                             new[] { "Nop.Web.Controllers" });
657             routes.MapLocalizedRoute("PrivateMessagesInbox",
658                             "inboxupdate",
659                             new { controller = "PrivateMessages", action = "InboxUpdate" },
660                             new[] { "Nop.Web.Controllers" });
661             routes.MapLocalizedRoute("PrivateMessagesSent",
662                             "sentupdate",
663                             new { controller = "PrivateMessages", action = "SentUpdate" },
664                             new[] { "Nop.Web.Controllers" });
665             routes.MapLocalizedRoute("SendPM",
666                             "sendpm/{toCustomerId}",
667                             new { controller = "PrivateMessages", action = "SendPM" },
668                             new { toCustomerId = @"\d+" },
669                             new[] { "Nop.Web.Controllers" });
670             routes.MapLocalizedRoute("SendPMReply",
671                             "sendpm/{toCustomerId}/{replyToMessageId}",
672                             new { controller = "PrivateMessages", action = "SendPM" },
673                             new { toCustomerId = @"\d+", replyToMessageId = @"\d+" },
674                             new[] { "Nop.Web.Controllers" });
675             routes.MapLocalizedRoute("ViewPM",
676                             "viewpm/{privateMessageId}",
677                             new { controller = "PrivateMessages", action = "ViewPM" },
678                             new { privateMessageId = @"\d+" },
679                             new[] { "Nop.Web.Controllers" });
680             routes.MapLocalizedRoute("DeletePM",
681                             "deletepm/{privateMessageId}",
682                             new { controller = "PrivateMessages", action = "DeletePM" },
683                             new { privateMessageId = @"\d+" },
684                             new[] { "Nop.Web.Controllers" });
685 
686             //activate newsletters
687             routes.MapLocalizedRoute("NewsletterActivation",
688                             "newsletter/subscriptionactivation/{token}/{active}",
689                             new { controller = "Newsletter", action = "SubscriptionActivation" },
690                             new { token = new GuidConstraint(false) },
691                             new[] { "Nop.Web.Controllers" });
692 
693             //robots.txt
694             routes.MapRoute("robots.txt",
695                             "robots.txt",
696                             new { controller = "Common", action = "RobotsTextFile" },
697                             new[] { "Nop.Web.Controllers" });
698 
699             //sitemap (XML)
700             routes.MapLocalizedRoute("sitemap.xml",
701                             "sitemap.xml",
702                             new { controller = "Common", action = "SitemapXml" },
703                             new[] { "Nop.Web.Controllers" });
704             routes.MapLocalizedRoute("sitemap-indexed.xml",
705                             "sitemap-{Id}.xml",
706                             new { controller = "Common", action = "SitemapXml" },
707                             new { Id = @"\d+" },
708                             new[] { "Nop.Web.Controllers" });
709 
710             //store closed
711             routes.MapLocalizedRoute("StoreClosed",
712                             "storeclosed",
713                             new { controller = "Common", action = "StoreClosed" },
714                             new[] { "Nop.Web.Controllers" });
715 
716             //install
717             routes.MapRoute("Installation",
718                             "install",
719                             new { controller = "Install", action = "Index" },
720                             new[] { "Nop.Web.Controllers" });
721 
722             //page not found
723             routes.MapLocalizedRoute("PageNotFound",
724                             "page-not-found",
725                             new { controller = "Common", action = "PageNotFound" },
726                             new[] { "Nop.Web.Controllers" });
727         }
728 
729         public int Priority
730         {
731             get
732             {
733                 return 0;
734             }
735         }
736     }
737 }
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="http://www.mamicode.com/@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友好链接的路由注册,代码如下:

技术分享
  1 using System.Web.Routing;
  2 using Nop.Web.Framework.Localization;
  3 using Nop.Web.Framework.Mvc.Routes;
  4 using Nop.Web.Framework.Seo;
  5 
  6 namespace Nop.Web.Infrastructure
  7 {
  8     public partial class GenericUrlRouteProvider : IRouteProvider
  9     {
 10         public void RegisterRoutes(RouteCollection routes)
 11         {
 12             //generic URLs
 13             routes.MapGenericPathRoute("GenericUrl",
 14                                        "{generic_se_name}",
 15                                        new {controller = "Common", action = "GenericUrl"},
 16                                        new[] {"Nop.Web.Controllers"});
 17 
 18             //define this routes to use in UI views (in case if you want to customize some of them later)
 19             routes.MapLocalizedRoute("Product",
 20                                      "{SeName}",
 21                                      new { controller = "Product", action = "ProductDetails" },
 22                                      new[] {"Nop.Web.Controllers"});
 23 
 24             routes.MapLocalizedRoute("Category",
 25                             "{SeName}",
 26                             new { controller = "Catalog", action = "Category" },
 27                             new[] { "Nop.Web.Controllers" });
 28 
 29             routes.MapLocalizedRoute("Manufacturer",
 30                             "{SeName}",
 31                             new { controller = "Catalog", action = "Manufacturer" },
 32                             new[] { "Nop.Web.Controllers" });
 33 
 34             routes.MapLocalizedRoute("Vendor",
 35                             "{SeName}",
 36                             new { controller = "Catalog", action = "Vendor" },
 37                             new[] { "Nop.Web.Controllers" });
 38 
 39             routes.MapLocalizedRoute("NewsItem",
 40                             "{SeName}",
 41                             new { controller = "News", action = "NewsItem" },
 42                             new[] { "Nop.Web.Controllers" });
 43 
 44             routes.MapLocalizedRoute("BlogPost",
 45                             "{SeName}",
 46                             new { controller = "Blog", action = "BlogPost" },
 47                             new[] { "Nop.Web.Controllers" });
 48 
 49             routes.MapLocalizedRoute("Topic",
 50                             "{SeName}",
 51                             new { controller = "Topic", action = "TopicDetails" },
 52                             new[] { "Nop.Web.Controllers" });
 53 
 54 
 55 
 56             //the last route. it‘s used when none of registered routes could be used for the current request
 57             //but in this case we cannot process non-registered routes (/controller/action)
 58             //routes.MapLocalizedRoute(
 59             //    "PageNotFound-Wildchar",
 60             //    "{*url}",
 61             //    new { controller = "Common", action = "PageNotFound" },
 62             //    new[] { "Nop.Web.Controllers" });
 63         }
 64 
 65         public int Priority
 66         {
 67             get
 68             {
 69                 //it should be the last route
 70                 //we do not set it to -int.MaxValue so it could be overridden (if required)
 71                 return -1000000;
 72             }
 73         }
 74     }
 75 }
 76 
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,帮助路由到正确的执行位置。代码如下:

技术分享
  1 /// <summary>
  2         /// Returns information about the requested route.
  3         /// </summary>
  4         /// <param name="httpContext">An object that encapsulates information about the HTTP request.</param>
  5         /// <returns>
  6         /// An object that contains the values from the route definition.
  7         /// </returns>
  8         public override RouteData GetRouteData(HttpContextBase httpContext)
  9         {
 10             RouteData data = http://www.mamicode.com/base.GetRouteData(httpContext); return null;
 11             if (data != null && DataSettingsHelper.DatabaseIsInstalled())
 12             {
 13                 var urlRecordService = EngineContext.Current.Resolve<IUrlRecordService>();
 14                 var slug = data.Values["generic_se_name"] as string;
 15                 //performance optimization.
 16                 //we load a cached verion here. it reduces number of SQL requests for each page load
 17                 var urlRecord = urlRecordService.GetBySlugCached(slug);
 18                 //comment the line above and uncomment the line below in order to disable this performance "workaround"
 19                 //var urlRecord = urlRecordService.GetBySlug(slug);
 20                 if (urlRecord == null)
 21                 {
 22                     //no URL record found
 23 
 24                     //var webHelper = EngineContext.Current.Resolve<IWebHelper>();
 25                     //var response = httpContext.Response;
 26                     //response.Status = "302 Found";
 27                     //response.RedirectLocation = webHelper.GetStoreLocation(false);
 28                     //response.End();
 29                     //return null;
 30 
 31                     data.Values["controller"] = "Common";
 32                     data.Values["action"] = "PageNotFound";
 33                     return data;
 34                 }
 35                 //ensure that URL record is active
 36                 if (!urlRecord.IsActive)
 37                 {
 38                     //URL record is not active. let‘s find the latest one
 39                     var activeSlug = urlRecordService.GetActiveSlug(urlRecord.EntityId, urlRecord.EntityName, urlRecord.LanguageId);
 40                     if (string.IsNullOrWhiteSpace(activeSlug))
 41                     {
 42                         //no active slug found
 43 
 44                         //var webHelper = EngineContext.Current.Resolve<IWebHelper>();
 45                         //var response = httpContext.Response;
 46                         //response.Status = "302 Found";
 47                         //response.RedirectLocation = webHelper.GetStoreLocation(false);
 48                         //response.End();
 49                         //return null;
 50 
 51                         data.Values["controller"] = "Common";
 52                         data.Values["action"] = "PageNotFound";
 53                         return data;
 54                     }
 55 
 56                     //the active one is found
 57                     var webHelper = EngineContext.Current.Resolve<IWebHelper>();
 58                     var response = httpContext.Response;
 59                     response.Status = "301 Moved Permanently";
 60                     response.RedirectLocation = string.Format("{0}{1}", webHelper.GetStoreLocation(), activeSlug);
 61                     response.End();
 62                     return null;
 63                 }
 64 
 65                 //ensure that the slug is the same for the current language
 66                 //otherwise, it can cause some issues when customers choose a new language but a slug stays the same
 67                 var workContext = EngineContext.Current.Resolve<IWorkContext>();
 68                 var slugForCurrentLanguage = SeoExtensions.GetSeName(urlRecord.EntityId, urlRecord.EntityName, workContext.WorkingLanguage.Id);
 69                 if (!String.IsNullOrEmpty(slugForCurrentLanguage) &&
 70                     !slugForCurrentLanguage.Equals(slug, StringComparison.InvariantCultureIgnoreCase))
 71                 {
 72                     //we should make not null or "" validation above because some entities does not have SeName for standard (ID=0) language (e.g. news, blog posts)
 73                     var webHelper = EngineContext.Current.Resolve<IWebHelper>();
 74                     var response = httpContext.Response;
 75                     //response.Status = "302 Found";
 76                     response.Status = "302 Moved Temporarily";
 77                     response.RedirectLocation = string.Format("{0}{1}", webHelper.GetStoreLocation(), slugForCurrentLanguage);
 78                     response.End();
 79                     return null;
 80                 }
 81 
 82                 //process URL
 83                 switch (urlRecord.EntityName.ToLowerInvariant())
 84                 {
 85                     case "product":
 86                         {
 87                             data.Values["controller"] = "Product";
 88                             data.Values["action"] = "ProductDetails";
 89                             data.Values["productid"] = urlRecord.EntityId;
 90                             data.Values["SeName"] = urlRecord.Slug;
 91                         }
 92                         break;
 93                     case "category":
 94                         {
 95                             data.Values["controller"] = "Catalog";
 96                             data.Values["action"] = "Category";
 97                             data.Values["categoryid"] = urlRecord.EntityId;
 98                             data.Values["SeName"] = urlRecord.Slug;
 99                         }
100                         break;
101                     case "manufacturer":
102                         {
103                             data.Values["controller"] = "Catalog";
104                             data.Values["action"] = "Manufacturer";
105                             data.Values["manufacturerid"] = urlRecord.EntityId;
106                             data.Values["SeName"] = urlRecord.Slug;
107                         }
108                         break;
109                     case "vendor":
110                         {
111                             data.Values["controller"] = "Catalog";
112                             data.Values["action"] = "Vendor";
113                             data.Values["vendorid"] = urlRecord.EntityId;
114                             data.Values["SeName"] = urlRecord.Slug;
115                         }
116                         break;
117                     case "newsitem":
118                         {
119                             data.Values["controller"] = "News";
120                             data.Values["action"] = "NewsItem";
121                             data.Values["newsItemId"] = urlRecord.EntityId;
122                             data.Values["SeName"] = urlRecord.Slug;
123                         }
124                         break;
125                     case "blogpost":
126                         {
127                             data.Values["controller"] = "Blog";
128                             data.Values["action"] = "BlogPost";
129                             data.Values["blogPostId"] = urlRecord.EntityId;
130                             data.Values["SeName"] = urlRecord.Slug;
131                         }
132                         break;
133                     case "topic":
134                         {
135                             data.Values["controller"] = "Topic";
136                             data.Values["action"] = "TopicDetails";
137                             data.Values["topicId"] = urlRecord.EntityId;
138                             data.Values["SeName"] = urlRecord.Slug;
139                         }
140                         break;
141                     default:
142                         {
143                             //no record found
144 
145                             //generate an event this way developers could insert their own types
146                             EngineContext.Current.Resolve<IEventPublisher>()
147                                 .Publish(new CustomUrlRecordEntityNameRequested(data, urlRecord));
148                         }
149                         break;
150                 }
151             }
152             return data;
153         }
GetRouteData

路由匹配到支持Seo友好链接会重定向链接新的路由位置,nop 3.9目前支持下图中的路由

提示:数据库UrlRecord表对Seo友情链接提供支持。

技术分享

四.总结

1.继承IRouteProvider对路由进行扩展。(注意路由注册顺序,ASP.NET MVC 只匹配第一次成功的路由信息)

2.多语言Seo友好链接通过LocalizedRoute类进行路由扩展(MapLocalizedRoute扩展中调用)

3.页面Seo友好链接通过GenericPathRoute类进行路由扩展(MapGenericPathRoute扩展中调用)

文中有错误的理解和不正确的观点,请留言,一起交流共同进步。

nopCommerce 3.9 大波浪系列 之 路由扩展 [多语言Seo的实现]