我的NopCommerce之旅(5): 路由分析
一、导图和基础介绍
本文主要介绍NopCommerce的路由机制,网上有一篇不错的文章,有兴趣的可以看看NopCommerce源码架构详解--对seo友好Url的路由机制实现源码分析
SEO,Search Engine Optimization,中文叫做搜索引擎优化,主要是为了提高网站关键词排名,提高访问量。SEO是一个很广的话题,我们这里主要了解NopCommerce的友好Url机制(它是实现SEO的一个步骤)。
二、承上启下
我的NopCommerce之旅(6): 应用启动中介绍在应用启动时,进行了常见的MVC物件的注册,包括Area、Route。这里通过调用公共接口方法,调用了所有实现了公共接口的类,实现对所有路由的注册。
1 //Registering some regular mvc stuff 2 AreaRegistration.RegisterAllAreas(); 3 RegisterRoutes(RouteTable.Routes);
1 //register custom routes (plugins, etc) 2 var routePublisher = EngineContext.Current.Resolve<IRoutePublisher>(); 3 routePublisher.RegisterRoutes(routes);
1 /// <summary> 2 /// Register routes 3 /// </summary> 4 /// <param name="routes">Routes</param> 5 public virtual void RegisterRoutes(RouteCollection routes) 6 { 7 var routeProviderTypes = typeFinder.FindClassesOfType<IRouteProvider>(); 8 var routeProviders = new List<IRouteProvider>(); 9 foreach (var providerType in routeProviderTypes) 10 { 11 //Ignore not installed plugins 12 var plugin = FindPlugin(providerType); 13 if (plugin != null && !plugin.Installed) 14 continue; 15 16 var provider = Activator.CreateInstance(providerType) as IRouteProvider; 17 routeProviders.Add(provider); 18 } 19 routeProviders = routeProviders.OrderByDescending(rp => rp.Priority).ToList(); 20 routeProviders.ForEach(rp => rp.RegisterRoutes(routes));//根据顺序,注册路由 21 }
三、公共接口
Nop.Web.Framework.Mvc.Routes.IRouteProvider,核心路由、友好路由以及Plugin等实现该接口进行路由注册。
Nop.Web.Framework.Mvc.Routes.IRoutePublisher
四、注册实现
1.核心路由注册,包括首页、部件、登录注册、购物车等,代码位置为Nop.Web.Infrastructure.RouteProvider。
1 public void RegisterRoutes(RouteCollection routes) 2 { 3 //We reordered our routes so the most used ones are on top. It can improve performance. 4 5 //home page 6 routes.MapLocalizedRoute("HomePage", 7 "", 8 new { controller = "Home", action = "Index" }, 9 new[] { "Nop.Web.Controllers" }); 10 11 //widgets 12 //we have this route for performance optimization because named routes are MUCH faster than usual Html.Action(...) 13 //and this route is highly used 14 routes.MapRoute("WidgetsByZone", 15 "widgetsbyzone/", 16 new { controller = "Widget", action = "WidgetsByZone" }, 17 new[] { "Nop.Web.Controllers" }); 18 19 //login 20 routes.MapLocalizedRoute("Login", 21 "login/", 22 new { controller = "Customer", action = "Login" }, 23 new[] { "Nop.Web.Controllers" }); 24 //register 25 routes.MapLocalizedRoute("Register", 26 "register/", 27 new { controller = "Customer", action = "Register" }, 28 new[] { "Nop.Web.Controllers" }); 29 //logout 30 routes.MapLocalizedRoute("Logout", 31 "logout/", 32 new { controller = "Customer", action = "Logout" }, 33 new[] { "Nop.Web.Controllers" }); 34 35 //shopping cart 36 routes.MapLocalizedRoute("ShoppingCart", 37 "cart/", 38 new { controller = "ShoppingCart", action = "Cart" }, 39 new[] { "Nop.Web.Controllers" }); 40 //wishlist 41 routes.MapLocalizedRoute("Wishlist", 42 "wishlist/{customerGuid}", 43 new { controller = "ShoppingCart", action = "Wishlist", customerGuid = UrlParameter.Optional }, 44 new[] { "Nop.Web.Controllers" }); 45 46 //customer account links 47 routes.MapLocalizedRoute("CustomerInfo", 48 "customer/info", 49 new { controller = "Customer", action = "Info" }, 50 new[] { "Nop.Web.Controllers" }); 51 ... 52 53 //contact us 54 routes.MapLocalizedRoute("ContactUs", 55 "contactus", 56 new { controller = "Common", action = "ContactUs" }, 57 new[] { "Nop.Web.Controllers" }); 58 //sitemap 59 routes.MapLocalizedRoute("Sitemap", 60 "sitemap", 61 new { controller = "Common", action = "Sitemap" }, 62 new[] { "Nop.Web.Controllers" }); 63 64 //product search 65 routes.MapLocalizedRoute("ProductSearch", 66 "search/", 67 new { controller = "Catalog", action = "Search" }, 68 new[] { "Nop.Web.Controllers" }); 69 routes.MapLocalizedRoute("ProductSearchAutoComplete", 70 "catalog/searchtermautocomplete", 71 new { controller = "Catalog", action = "SearchTermAutoComplete" }, 72 new[] { "Nop.Web.Controllers" }); 73 74 //change currency (AJAX link) 75 routes.MapLocalizedRoute("ChangeCurrency", 76 "changecurrency/{customercurrency}", 77 new { controller = "Common", action = "SetCurrency" }, 78 new { customercurrency = @"\d+" }, 79 new[] { "Nop.Web.Controllers" }); 80 //change language (AJAX link) 81 routes.MapLocalizedRoute("ChangeLanguage", 82 "changelanguage/{langid}", 83 new { controller = "Common", action = "SetLanguage" }, 84 new { langid = @"\d+" }, 85 new[] { "Nop.Web.Controllers" }); 86 //change tax (AJAX link) 87 routes.MapLocalizedRoute("ChangeTaxType", 88 "changetaxtype/{customertaxtype}", 89 new { controller = "Common", action = "SetTaxType" }, 90 new { customertaxtype = @"\d+" }, 91 new[] { "Nop.Web.Controllers" }); 92 93 //recently viewed products 94 routes.MapLocalizedRoute("RecentlyViewedProducts", 95 "recentlyviewedproducts/", 96 new { controller = "Product", action = "RecentlyViewedProducts" }, 97 new[] { "Nop.Web.Controllers" }); 98 //new products 99 routes.MapLocalizedRoute("NewProducts", 100 "newproducts/", 101 new { controller = "Product", action = "NewProducts" }, 102 new[] { "Nop.Web.Controllers" }); 103 //blog 104 routes.MapLocalizedRoute("Blog", 105 "blog", 106 new { controller = "Blog", action = "List" }, 107 new[] { "Nop.Web.Controllers" }); 108 //news 109 routes.MapLocalizedRoute("NewsArchive", 110 "news", 111 new { controller = "News", action = "List" }, 112 new[] { "Nop.Web.Controllers" }); 113 114 //forum 115 routes.MapLocalizedRoute("Boards", 116 "boards", 117 new { controller = "Boards", action = "Index" }, 118 new[] { "Nop.Web.Controllers" }); 119 120 //compare products 121 routes.MapLocalizedRoute("CompareProducts", 122 "compareproducts/", 123 new { controller = "Product", action = "CompareProducts" }, 124 new[] { "Nop.Web.Controllers" }); 125 126 //product tags 127 routes.MapLocalizedRoute("ProductTagsAll", 128 "producttag/all/", 129 new { controller = "Catalog", action = "ProductTagsAll" }, 130 new[] { "Nop.Web.Controllers" }); 131 132 //manufacturers 133 routes.MapLocalizedRoute("ManufacturerList", 134 "manufacturer/all/", 135 new { controller = "Catalog", action = "ManufacturerAll" }, 136 new[] { "Nop.Web.Controllers" }); 137 //vendors 138 routes.MapLocalizedRoute("VendorList", 139 "vendor/all/", 140 new { controller = "Catalog", action = "VendorAll" }, 141 new[] { "Nop.Web.Controllers" }); 142 143 144 //add product to cart (without any attributes and options). used on catalog pages. 145 routes.MapLocalizedRoute("AddProductToCart-Catalog", 146 "addproducttocart/catalog/{productId}/{shoppingCartTypeId}/{quantity}", 147 new { controller = "ShoppingCart", action = "AddProductToCart_Catalog" }, 148 new { productId = @"\d+", shoppingCartTypeId = @"\d+", quantity = @"\d+" }, 149 new[] { "Nop.Web.Controllers" }); 150 //add product to cart (with attributes and options). used on the product details pages. 151 routes.MapLocalizedRoute("AddProductToCart-Details", 152 "addproducttocart/details/{productId}/{shoppingCartTypeId}", 153 new { controller = "ShoppingCart", action = "AddProductToCart_Details" }, 154 new { productId = @"\d+", shoppingCartTypeId = @"\d+" }, 155 new[] { "Nop.Web.Controllers" }); 156 157 //product tags 158 routes.MapLocalizedRoute("ProductsByTag", 159 "producttag/{productTagId}/{SeName}", 160 new { controller = "Catalog", action = "ProductsByTag", SeName = UrlParameter.Optional }, 161 new { productTagId = @"\d+" }, 162 new[] { "Nop.Web.Controllers" }); 163 //comparing products 164 routes.MapLocalizedRoute("AddProductToCompare", 165 "compareproducts/add/{productId}", 166 new { controller = "Product", action = "AddProductToCompareList" }, 167 new { productId = @"\d+" }, 168 new[] { "Nop.Web.Controllers" }); 169 //product email a friend 170 routes.MapLocalizedRoute("ProductEmailAFriend", 171 "productemailafriend/{productId}", 172 new { controller = "Product", action = "ProductEmailAFriend" }, 173 new { productId = @"\d+" }, 174 new[] { "Nop.Web.Controllers" }); 175 //reviews 176 routes.MapLocalizedRoute("ProductReviews", 177 "productreviews/{productId}", 178 new { controller = "Product", action = "ProductReviews" }, 179 new[] { "Nop.Web.Controllers" }); 180 //back in stock notifications 181 routes.MapLocalizedRoute("BackInStockSubscribePopup", 182 "backinstocksubscribe/{productId}", 183 new { controller = "BackInStockSubscription", action = "SubscribePopup" }, 184 new { productId = @"\d+" }, 185 new[] { "Nop.Web.Controllers" }); 186 //downloads 187 routes.MapRoute("GetSampleDownload", 188 "download/sample/{productid}", 189 new { controller = "Download", action = "Sample" }, 190 new { productid = @"\d+" }, 191 new[] { "Nop.Web.Controllers" }); 192 193 194 195 //checkout pages 196 routes.MapLocalizedRoute("Checkout", 197 "checkout/", 198 new { controller = "Checkout", action = "Index" }, 199 new[] { "Nop.Web.Controllers" }); 200 ... 201 202 //subscribe newsletters 203 routes.MapLocalizedRoute("SubscribeNewsletter", 204 "subscribenewsletter", 205 new { controller = "Newsletter", action = "SubscribeNewsletter" }, 206 new[] { "Nop.Web.Controllers" }); 207 208 //email wishlist 209 routes.MapLocalizedRoute("EmailWishlist", 210 "emailwishlist", 211 new { controller = "ShoppingCart", action = "EmailWishlist" }, 212 new[] { "Nop.Web.Controllers" }); 213 214 //login page for checkout as guest 215 routes.MapLocalizedRoute("LoginCheckoutAsGuest", 216 "login/checkoutasguest", 217 new { controller = "Customer", action = "Login", checkoutAsGuest = true }, 218 new[] { "Nop.Web.Controllers" }); 219 //register result page 220 routes.MapLocalizedRoute("RegisterResult", 221 "registerresult/{resultId}", 222 new { controller = "Customer", action = "RegisterResult" }, 223 new { resultId = @"\d+" }, 224 new[] { "Nop.Web.Controllers" }); 225 //check username availability 226 routes.MapLocalizedRoute("CheckUsernameAvailability", 227 "customer/checkusernameavailability", 228 new { controller = "Customer", action = "CheckUsernameAvailability" }, 229 new[] { "Nop.Web.Controllers" }); 230 231 //passwordrecovery 232 routes.MapLocalizedRoute("PasswordRecovery", 233 "passwordrecovery", 234 new { controller = "Customer", action = "PasswordRecovery" }, 235 new[] { "Nop.Web.Controllers" }); 236 //password recovery confirmation 237 routes.MapLocalizedRoute("PasswordRecoveryConfirm", 238 "passwordrecovery/confirm", 239 new { controller = "Customer", action = "PasswordRecoveryConfirm" }, 240 new[] { "Nop.Web.Controllers" }); 241 242 //topics 243 routes.MapLocalizedRoute("TopicPopup", 244 "t-popup/{SystemName}", 245 new { controller = "Topic", action = "TopicDetailsPopup" }, 246 new[] { "Nop.Web.Controllers" }); 247 248 //blog 249 routes.MapLocalizedRoute("BlogByTag", 250 "blog/tag/{tag}", 251 new { controller = "Blog", action = "BlogByTag" }, 252 new[] { "Nop.Web.Controllers" }); 253 routes.MapLocalizedRoute("BlogByMonth", 254 "blog/month/{month}", 255 new { controller = "Blog", action = "BlogByMonth" }, 256 new[] { "Nop.Web.Controllers" }); 257 //blog RSS 258 routes.MapLocalizedRoute("BlogRSS", 259 "blog/rss/{languageId}", 260 new { controller = "Blog", action = "ListRss" }, 261 new { languageId = @"\d+" }, 262 new[] { "Nop.Web.Controllers" }); 263 264 //news RSS 265 routes.MapLocalizedRoute("NewsRSS", 266 "news/rss/{languageId}", 267 new { controller = "News", action = "ListRss" }, 268 new { languageId = @"\d+" }, 269 new[] { "Nop.Web.Controllers" }); 270 271 //set review helpfulness (AJAX link) 272 routes.MapRoute("SetProductReviewHelpfulness", 273 "setproductreviewhelpfulness", 274 new { controller = "Product", action = "SetProductReviewHelpfulness" }, 275 new[] { "Nop.Web.Controllers" }); 276 277 //customer account links 278 routes.MapLocalizedRoute("CustomerReturnRequests", 279 "returnrequest/history", 280 new { controller = "ReturnRequest", action = "CustomerReturnRequests" }, 281 new[] { "Nop.Web.Controllers" }); 282 ... 283 //customer profile page 284 routes.MapLocalizedRoute("CustomerProfile", 285 "profile/{id}", 286 new { controller = "Profile", action = "Index" }, 287 new { id = @"\d+" }, 288 new[] { "Nop.Web.Controllers" }); 289 routes.MapLocalizedRoute("CustomerProfilePaged", 290 "profile/{id}/page/{page}", 291 new { controller = "Profile", action = "Index" }, 292 new { id = @"\d+", page = @"\d+" }, 293 new[] { "Nop.Web.Controllers" }); 294 295 //orders 296 routes.MapLocalizedRoute("OrderDetails", 297 "orderdetails/{orderId}", 298 new { controller = "Order", action = "Details" }, 299 new { orderId = @"\d+" }, 300 new[] { "Nop.Web.Controllers" }); 301 ... 302 //order downloads 303 routes.MapRoute("GetDownload", 304 "download/getdownload/{orderItemId}/{agree}", 305 new { controller = "Download", action = "GetDownload", agree = UrlParameter.Optional }, 306 new { orderItemId = new GuidConstraint(false) }, 307 new[] { "Nop.Web.Controllers" }); 308 ... 309 310 //contact vendor 311 routes.MapLocalizedRoute("ContactVendor", 312 "contactvendor/{vendorId}", 313 new { controller = "Common", action = "ContactVendor" }, 314 new[] { "Nop.Web.Controllers" }); 315 //apply for vendor account 316 routes.MapLocalizedRoute("ApplyVendorAccount", 317 "vendor/apply", 318 new { controller = "Vendor", action = "ApplyVendor" }, 319 new[] { "Nop.Web.Controllers" }); 320 321 //poll vote AJAX link 322 routes.MapLocalizedRoute("PollVote", 323 "poll/vote", 324 new { controller = "Poll", action = "Vote" }, 325 new[] { "Nop.Web.Controllers" }); 326 327 //comparing products 328 routes.MapLocalizedRoute("RemoveProductFromCompareList", 329 "compareproducts/remove/{productId}", 330 new { controller = "Product", action = "RemoveProductFromCompareList" }, 331 new[] { "Nop.Web.Controllers" }); 332 routes.MapLocalizedRoute("ClearCompareList", 333 "clearcomparelist/", 334 new { controller = "Product", action = "ClearCompareList" }, 335 new[] { "Nop.Web.Controllers" }); 336 337 //new RSS 338 routes.MapLocalizedRoute("NewProductsRSS", 339 "newproducts/rss", 340 new { controller = "Product", action = "NewProductsRss" }, 341 new[] { "Nop.Web.Controllers" }); 342 343 //get state list by country ID (AJAX link) 344 routes.MapRoute("GetStatesByCountryId", 345 "country/getstatesbycountryid/", 346 new { controller = "Country", action = "GetStatesByCountryId" }, 347 new[] { "Nop.Web.Controllers" }); 348 349 //EU Cookie law accept button handler (AJAX link) 350 routes.MapRoute("EuCookieLawAccept", 351 "eucookielawaccept", 352 new { controller = "Common", action = "EuCookieLawAccept" }, 353 new[] { "Nop.Web.Controllers" }); 354 355 //authenticate topic AJAX link 356 routes.MapLocalizedRoute("TopicAuthenticate", 357 "topic/authenticate", 358 new { controller = "Topic", action = "Authenticate" }, 359 new[] { "Nop.Web.Controllers" }); 360 361 //product attributes with "upload file" type 362 routes.MapLocalizedRoute("UploadFileProductAttribute", 363 "uploadfileproductattribute/{attributeId}", 364 new { controller = "ShoppingCart", action = "UploadFileProductAttribute" }, 365 new { attributeId = @"\d+" }, 366 new[] { "Nop.Web.Controllers" }); 367 //checkout attributes with "upload file" type 368 routes.MapLocalizedRoute("UploadFileCheckoutAttribute", 369 "uploadfilecheckoutattribute/{attributeId}", 370 new { controller = "ShoppingCart", action = "UploadFileCheckoutAttribute" }, 371 new { attributeId = @"\d+" }, 372 new[] { "Nop.Web.Controllers" }); 373 374 //forums 375 routes.MapLocalizedRoute("ActiveDiscussions", 376 "boards/activediscussions", 377 new { controller = "Boards", action = "ActiveDiscussions" }, 378 new[] { "Nop.Web.Controllers" }); 379 ... 380 381 //private messages 382 routes.MapLocalizedRoute("PrivateMessages", 383 "privatemessages/{tab}", 384 new { controller = "PrivateMessages", action = "Index", tab = UrlParameter.Optional }, 385 new[] { "Nop.Web.Controllers" }); 386 ... 387 388 //activate newsletters 389 routes.MapLocalizedRoute("NewsletterActivation", 390 "newsletter/subscriptionactivation/{token}/{active}", 391 new { controller = "Newsletter", action = "SubscriptionActivation" }, 392 new { token = new GuidConstraint(false) }, 393 new[] { "Nop.Web.Controllers" }); 394 395 //robots.txt 396 routes.MapRoute("robots.txt", 397 "robots.txt", 398 new { controller = "Common", action = "RobotsTextFile" }, 399 new[] { "Nop.Web.Controllers" }); 400 401 //sitemap (XML) 402 routes.MapLocalizedRoute("sitemap.xml", 403 "sitemap.xml", 404 new { controller = "Common", action = "SitemapXml" }, 405 new[] { "Nop.Web.Controllers" }); 406 407 //store closed 408 routes.MapLocalizedRoute("StoreClosed", 409 "storeclosed", 410 new { controller = "Common", action = "StoreClosed" }, 411 new[] { "Nop.Web.Controllers" }); 412 413 //install 414 routes.MapRoute("Installation", 415 "install", 416 new { controller = "Install", action = "Index" }, 417 new[] { "Nop.Web.Controllers" }); 418 419 //page not found 420 routes.MapLocalizedRoute("PageNotFound", 421 "page-not-found", 422 new { controller = "Common", action = "PageNotFound" }, 423 new[] { "Nop.Web.Controllers" }); 424 }
2.SEO友好路由注册,包括产品、种类、生产商、供应商、新闻、博客、主题等具体信息的路由,代码位置为Nop.Web.Infrastructure.GenericUrlRouteProvider。
经过优化过的友好Url为http://localhost/apple-macbook-pro-13-inch,而经过解析后访问的实际http://localhost/Product/ProductDetails/{productId}。
1 public void RegisterRoutes(RouteCollection routes) 2 { 3 //generic URLs 4 routes.MapGenericPathRoute("GenericUrl", 5 "{generic_se_name}", 6 new {controller = "Common", action = "GenericUrl"}, 7 new[] {"Nop.Web.Controllers"}); 8 9 //define this routes to use in UI views (in case if you want to customize some of them later) 10 routes.MapLocalizedRoute("Product", 11 "{SeName}", 12 new { controller = "Product", action = "ProductDetails" }, 13 new[] {"Nop.Web.Controllers"}); 14 15 routes.MapLocalizedRoute("Category", 16 "{SeName}", 17 new { controller = "Catalog", action = "Category" }, 18 new[] { "Nop.Web.Controllers" }); 19 20 routes.MapLocalizedRoute("Manufacturer", 21 "{SeName}", 22 new { controller = "Catalog", action = "Manufacturer" }, 23 new[] { "Nop.Web.Controllers" }); 24 25 routes.MapLocalizedRoute("Vendor", 26 "{SeName}", 27 new { controller = "Catalog", action = "Vendor" }, 28 new[] { "Nop.Web.Controllers" }); 29 30 routes.MapLocalizedRoute("NewsItem", 31 "{SeName}", 32 new { controller = "News", action = "NewsItem" }, 33 new[] { "Nop.Web.Controllers" }); 34 35 routes.MapLocalizedRoute("BlogPost", 36 "{SeName}", 37 new { controller = "Blog", action = "BlogPost" }, 38 new[] { "Nop.Web.Controllers" }); 39 40 routes.MapLocalizedRoute("Topic", 41 "{SeName}", 42 new { controller = "Topic", action = "TopicDetails" }, 43 new[] { "Nop.Web.Controllers" }); 44 45 46 47 //the last route. it's used when none of registered routes could be used for the current request 48 //but it this case we cannot process non-registered routes (/controller/action) 49 //routes.MapLocalizedRoute( 50 // "PageNotFound-Wildchar", 51 // "{*url}", 52 // new { controller = "Common", action = "PageNotFound" }, 53 // new[] { "Nop.Web.Controllers" }); 54 }
五、友好Url解析
NopCommerce中通过继承Route类,重写RouteData GetRouteData(HttpContextBase httpContext)方法来获取真正路由。代码位置为Nop.Web.Framework.Localization.LocalizedRoute和Nop.Web.Framework.Seo.GenericPathRoute。
GenericPathRoute类的GetRouteData()方法是我们要讲的重点,它实现了友好Url的解析。下面是方法代码的分析:
1.获取Url的标识值。
获取请求中generic_se_name的值。
1 public override RouteData GetRouteData(HttpContextBase httpContext) 2 { 3 RouteData data = base.GetRouteData(httpContext); 4 if (data != null && DataSettingsHelper.DatabaseIsInstalled()) 5 { 6 var urlRecordService = EngineContext.Current.Resolve<IUrlRecordService>(); 7 var slug = data.Values["generic_se_name"] as string;//获取标识值,如"apple-macbook-pro-13-inch" 8 ... 9 } 10 return data; 11 }
2.根据标识解析实际路由信息
2.1 从缓存中读取该标识关联的值,值包括访问的controller和Id
1 public override RouteData GetRouteData(HttpContextBase httpContext) 2 { 3 ... 4 var slug = data.Values["generic_se_name"] as string; 5 //performance optimization. 6 //we load a cached verion here. it reduces number of SQL requests for each page load 7 var urlRecord = urlRecordService.GetBySlugCached(slug); 8 ... 9 }
1 /// <summary> 2 /// Find URL record (cached version). 3 /// This method works absolutely the same way as "GetBySlug" one but caches the results. 4 /// Hence, it's used only for performance optimization in public store 5 /// </summary> 6 /// <param name="slug">Slug</param> 7 /// <returns>Found URL record</returns> 8 public virtual UrlRecordForCaching GetBySlugCached(string slug) 9 { 10 if (String.IsNullOrEmpty(slug)) 11 return null; 12 13 if (_localizationSettings.LoadAllUrlRecordsOnStartup) 14 { 15 //load all records (we know they are cached) 16 var source = GetAllUrlRecordsCached(); 17 var query = from ur in source 18 where ur.Slug.Equals(slug, StringComparison.InvariantCultureIgnoreCase) 19 select ur; 20 var urlRecordForCaching = query.FirstOrDefault(); 21 return urlRecordForCaching; 22 } 23 24 //gradual loading 25 string key = string.Format(URLRECORD_BY_SLUG_KEY, slug); 26 return _cacheManager.Get(key, () => 27 { 28 var urlRecord = GetBySlug(slug);//从数据库读取 29 if (urlRecord == null) 30 return null; 31 32 var urlRecordForCaching = Map(urlRecord); 33 return urlRecordForCaching; 34 }); 35 }
2.2 若缓存中不存在则读取数据库数据,数据库表为[dbo].[UrlRecord]
1 /// <summary> 2 /// Find URL record 3 /// </summary> 4 /// <param name="slug">Slug</param> 5 /// <returns>Found URL record</returns> 6 public virtual UrlRecord GetBySlug(string slug) 7 { 8 if (String.IsNullOrEmpty(slug)) 9 return null; 10 11 var query = from ur in _urlRecordRepository.Table 12 where ur.Slug == slug 13 select ur; 14 var urlRecord = query.FirstOrDefault(); 15 return urlRecord; 16 }
2.3 根据读取的值的EntityName,返回路由信息。
1 //process URL 2 switch (urlRecord.EntityName.ToLowerInvariant()) 3 { 4 case "product": 5 { 6 data.Values["controller"] = "Product"; 7 data.Values["action"] = "ProductDetails"; 8 data.Values["productid"] = urlRecord.EntityId; 9 data.Values["SeName"] = urlRecord.Slug; 10 ...
3.访问路由信息