首页 > 代码库 > 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.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
我们发现多了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 }
路由匹配到支持Seo友好链接会重定向链接新的路由位置,nop 3.9目前支持下图中的路由
提示:数据库UrlRecord表对Seo友情链接提供支持。
四.总结
1.继承IRouteProvider对路由进行扩展。(注意路由注册顺序,ASP.NET MVC 只匹配第一次成功的路由信息)
2.多语言Seo友好链接通过LocalizedRoute类进行路由扩展(MapLocalizedRoute扩展中调用)
3.页面Seo友好链接通过GenericPathRoute类进行路由扩展(MapGenericPathRoute扩展中调用)
文中有错误的理解和不正确的观点,请留言,一起交流共同进步。
nopCommerce 3.9 大波浪系列 之 路由扩展 [多语言Seo的实现]