nopCommerce 3.9 大波浪系列 之 路由擴展 [多語言Seo的實現]

一.nop中的路由註冊

在Global.asax,Application_Start()方法中會進行路由註冊,代碼以下。web

複製代碼
  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)方法進行路由註冊。代碼以下:cookie

複製代碼
  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 }
複製代碼

該方法作了以下工做:app

第一步:經過ITyperFinder接口找到全部實現了IRouteProvider接口的類類型。保存在routeProviderTypes集合中ide

第二步:遍歷routeProviderTypes集合,經過PluginManager類找到未安裝IRouteProvider類類型。並從routeProviderTypes集合中排除掉。post

第三步:實例化IRouteProvider實現類。優化

第四步:調用IRouteProvider實現類RegisterRoutes(routes)方法進行路由註冊。ui

下圖爲主要接口之間的調用關係this

image

經過上述分析nop路由註冊主要是經過IRouteProvider接口實現的,如今咱們看看項目中實現該接口的類都有哪些。搜索引擎

下圖紅色是在Nop.Web項目中,其餘都是在nop插件中。

image_thumb1

接下來咱們看下路由的註冊順序以下圖,咱們看到最早匹配的Nop.Web.Infrastructure.RouteProvider中的路由註冊。

image_thumb3

二.啓用支持多語言的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.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友好連接的支持。

 

image_thumb6

咱們發現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 
複製代碼

咱們發現多了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 = 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 }
複製代碼

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

提示:數據庫UrlRecord表對Seo友情連接提供支持。

image_thumb11

四.總結

1.繼承IRouteProvider對路由進行擴展。(注意路由註冊順序,ASP.NET MVC 只匹配第一次成功的路由信息)

2.多語言Seo友好連接經過LocalizedRoute類進行路由擴展(MapLocalizedRoute擴展中調用)

3.頁面Seo友好連接經過GenericPathRoute類進行路由擴展(MapGenericPathRoute擴展中調用)

相關文章
相關標籤/搜索