• 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)方法进行路由注册。

    下图为主要接口之间的调用关系

    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扩展中调用)

  • 相关阅读:
    Document
    Document
    Document
    Document
    Document
    Document
    set常见操作:
    select 不存在字段,并设置默认值
    c#为字段设置默认值,以及构造函数初始化List对象。
    ThreadLocal
  • 原文地址:https://www.cnblogs.com/zhangruisoldier/p/8042465.html
Copyright © 2020-2023  润新知