Popular blog tags

How to Override generic path route in NopCommerce 4.x

Published

Table of Content

 

version:NopCommerce 4.40

NopCommerce 4.40 .Net 5.x

 

 

├── step 1.All Route Provider                                          // All Route Provider   in Nopcommerce 4.3
│   ├──1.1 Nop.Plugin.*                              // nopCommerce-release-4.30\src\Plugins
│   │   ├── Nop.Plugin.Misc.SendinBlue.Infrastructure                             // example
│   │   │   ├── IRouteProvider 
│   │   │   └── RouteProvider                    // public void RegisterRoutes(IEndpointRouteBuilder endpointRouteBuilder) 
│   ├──1.2 Nop.Web class BackwardCompatibility1XRouteProvider                                 // nopCommerce-release-4.30\src\Presentation\Nop.Web\Infrastructure
│   │   │   ├── IRouteProvider 
│   │   │   └── RouteProvider                    //Nop.Web.Infrastructure-> public void RegisterRoutes(IEndpointRouteBuilder endpointRouteBuilder) 
│   ├──1.3 Nop.Web GenericUrlRouteProvider      //nopCommerce-release-4.30\src\Presentation\Nop.Web\Infrastructure
│   │   │   ├── IRouteProvider 
│   │   │   └── RouteProvider                    // Nop.Web.Infrastructure->public void RegisterRoutes(IEndpointRouteBuilder endpointRouteBuilder)                              // 
│   ├──1.4 Nop.Web RouteProvider                          //nopCommerce-release-4.30\src\Presentation\Nop.Web\Infrastructure
│   │   │   ├── IRouteProvider 
│   │   │   └── RouteProvider                    //Nop.Web.Infrastructure-> public void RegisterRoutes(IEndpointRouteBuilder endpointRouteBuilder)   
├──step 2. Route Publish                                          // All Route Provider   in Nopcommerce 4.3
│   ├──2.1 Nop.Web.Framework register all provided routes  class                            // 
│   │   ├── class RoutePublisher                            // nopCommerce-release-4.30\src\Presentation\Nop.Web.Framework\Mvc\Routing
│   │   │   ├── IRoutePublisher 
│   │   │   └── RoutePublisher                   // nopCommerce-release-4.30\src\Presentation\Nop.Web.Framework\Mvc\Routing
│   ├──2.2 Nop.Web register Service                              // 
│   │   ├── class DependencyRegistrar.cs                            // nopCommerce-release-4.30\src\Presentation\Nop.Web.Framework\Mvc\Routing
│   │   │   ├── IRoutePublisher              //builder.RegisterType<RoutePublisher>().As<IRoutePublisher>().SingleInstance();
│   │   │   └── Startup.cs                                  //  builder.RegisterType<RoutePublisher>().As<IRoutePublisher>().SingleInstance();
│   │   ├── benefit
│   │   │   ├── benefit.vue                     // 红包页
│   │   │   └── children
│   │   │       ├── commend.vue                 // 推荐有奖
│   │   │       ├── coupon.vue                  // 代金券说明
│   │   │       ├── exchange.vue                // 兑换红包
│   │   │       ├── hbDescription.vue           // 红包说明
│   │   │       └── hbHistory.vue               // 历史红包
│   │   ├── city                 
│   │   │   └── city.vue                        // 当前城市页
│   │   ├── confirmOrder
│   │   │   ├── children
│   │   │   │   ├── children
│   │   │   │   │   ├── addAddress.vue          // 添加地址页
│   │   │   │   │   └── children
│   │   │   │   │       └── searchAddress.vue   // 搜索地址页
│   │   │   │   ├── chooseAddress.vue           // 选择地址页
│   │   │   │   ├── invoice.vue                 // 选择发票页
│   │   │   │   ├── payment.vue                 // 付款页
│   │   │   │   ├── remark.vue                  // 订单备注页 
│   │   │   │   └── userValidation.vue          // 用户验证页
│   │   │   └── confirmOrder.vue                // 确认订单页
│   │   ├── download
│   │   │   └── download.vue                    // 下载App
│   │   ├── find
│   │   │   └── find.vue                        // 发现页
│   │   ├── food
│   │   │   └── food.vue                        // 食品筛选排序页
│   │   ├── forget
│   │   │   └── forget.vue                      // 忘记密码,修改密码页
│   │   ├── home
│   │   │   └── home.vue                        // 首页
│   │   ├── login
│   │   │   └── login.vue                       // 登录注册页
│   │   ├── msite
│   │   │   └── msite.vue                       // 商铺列表页
│   │   ├── order
│   │   │   ├── children
│   │   │   │   └── orderDetail.vue             // 订单详情页
│   │   │   └── order.vue                       // 订单列表页
│   │   ├── points
│   │   │   ├── children
│   │   │   │   └── detail.vue                  // 积分说明
│   │   │   └── points.vue                      // 积分页
│   │   ├── profile
│   │   │   ├── children
│   │   │   │   ├── children
│   │   │   │   │   ├── address.vue             // 地址
│   │   │   │   │   └── children
│   │   │   │   │       ├── add.vue             // 新增地址
│   │   │   │   │       └── children
│   │   │   │   │           └── addDetail.vue   // 搜索地址
│   │   │   │   ├── info.vue                    // 帐户信息
│   │   │   │   └── setusername.vue             // 重置用户名
│   │   │   └── profile.vue                     // 个人中心
│   │   ├── search
│   │   │   └── search.vue                      // 搜索页
│   │   ├── service
│   │   │   ├── children
│   │   │   │   └── questionDetail.vue          // 问题详情
│   │   │   └── service.vue                     // 服务中心
│   │   ├── shop
│   │   │   ├── children
│   │   │   │   ├── children
│   │   │   │   │   └── shopSafe.vue            // 商铺认证信息页
│   │   │   │   ├── foodDetail.vue              // 商铺信息页
│   │   │   │   └── shopDetail.vue              // 单个商铺信息页
│   │   │   └── shop.vue                        // 商铺筛选页
│   │   └── vipcard
│   │       ├── children
│   │       │   ├── invoiceRecord.vue           // 购买记录
│   │       │   ├── useCart.vue                 // 使用卡号购买
│   │       │   └── vipDescription.vue          // 会员说明
│   │       └── vipcard.vue                     // 会员卡办理页
│   ├── plugins                                 // 引用的插件
│   ├── router
│   │   └── router.js                           // 路由配置
│   ├── service                                 // 数据交互统一调配
│   │   ├── getData.js                          // 获取数据的统一调配文件,对接口进行统一管理
│   │   └── tempdata                            // 开发阶段的临时数据
│   ├── store                                   // vuex的状态管理
│   │   ├── action.js                           // 配置actions
│   │   ├── getters.js                          // 配置getters
│   │   ├── index.js                            // 引用vuex,创建store
│   │   ├── modules                             // store模块
│   │   ├── mutation-types.js                   // 定义常量muations名
│   │   └── mutations.js                        // 配置mutations
│   └── style
│       ├── common.scss                         // 公共样式文件
│       ├── mixin.scss                          // 样式配置文件
│       └── swiper.min.css
│   ├── App.vue                                 // 页面入口文件
│   ├── main.js                                 // 程序入口文件,加载各种公共组件
├── favicon.ico                                 // 图标
├── index.html                                  // 入口html文件



I have something like this:

endpoints.MapDefaultControllerRoute();
endpoints.MapDynamicControllerRoute<SeoTransformer>("{**path}");
endpoints.MapFallbackToController("Index", "Fallback");

 

Check existing default routes
If not found --> MapDynamicControllerRoute("{**path}")
If not found --> MapFallbackToController("Index", "Fallback");

If the url doesn't match any route, it will match this fallbacktocontroller method.

 

1.Order in which routes are registered is very important.requires that  have a unique priority

当有多个路由注册时,需要确定注册路由的顺序

 (1)静态路由应放在第一位。其中blog 相关应该放在最后位置。否则会出现login找不到错误

         see:

          https://www.iaspnetcore.com/Blog/BlogPost/5f8c4121f3819901ee0d9182/nopcommerce-4x-blog-url (.Net 3.x)

          https://www.iaspnetcore.com/Blog/BlogPost/5e3d7eb6145fd233991ae654/nopcommerce-4xcontactus (.Net 3.x)

 

GenericUrlRouteProvider /nopCommerce/src/Presentation/Nop.Web/Infrastructure/GenericUrlRouteProvider.cs

https://github.com/nopSolutions/nopCommerce/blob/12dd4825dfb56bbc64e192cd35d25e3205427646/src/Presentation/Nop.Web/Infrastructure/GenericUrlRouteProvider.cs

 

SlugRouteTransformer searches through 500000+ paths that have different controllers and actions.

 

1.add  SlugRouteTransformer.cs

workflow:

step 1: get url from http://url

step 2: lookup url in db.UrlRecord

step 3: return controll action and id as  ValueTask

http://url->lookup url in db.UrlRecord->get 

I am trying to setup a dynamic route catch-all so that all routes that do not match the hardcoded routes gets sent to DynamicRouteValueTransformer which tries to find the dynamic route in the database.

{
	"_id" : ObjectId("5f7bc20948c1c3420148dd65"),
	"GenericAttributes" : [ ],
	"EntityId" : ObjectId("5ace9e8c13bdf8193447c8fa"),
	"EntityName" : "BlogPost",
	"Slug" : "how-to-override-generic-path-route-in-nopcommerce-4x",
	"IsActive" : true,
	"LanguageId" : ObjectId("5cf6b5c32bac284b687fa506")
},

src/Presentation/Nop.Web.Framework/Mvc/Routing/SlugRouteTransformer.cs

To create a custom DynamicRouteValueTransformer, the class should inherit from DynamicRouteValueTransformer . This interface resides inside the Microsoft.AspNetCore.Mvc.Routing namespace.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Routing;// for DynamicRouteValueTransformer
using Microsoft.AspNetCore.Routing; //for RouteValueDictionary

using Nop.Core.Domain.Localization;
using Nop.Core.Events;
using Nop.Services.Localization;
using Nop.Services.Seo;

namespace Nop.Web.Framework.Mvc.Routing
{
    /// <summary>
    /// Represents slug route transformer
    /// come from:https://github.com/nopSolutions/nopCommerce/blob/c1d858bc653f2a7fc02f979c04451123c5d9b509/src/Presentation/Nop.Web.Framework/Mvc/Routing/SlugRouteTransformer.cs
    /// </summary>
    public class SlugRouteTransformer : DynamicRouteValueTransformer
    {

        #region Fields

      //  private readonly IEventPublisher _eventPublisher;
        private readonly ILanguageService _languageService;
        private readonly IUrlRecordService _urlRecordService;
        private readonly LocalizationSettings _localizationSettings;

        #endregion

        #region Ctor

        public SlugRouteTransformer(//IEventPublisher eventPublisher,
            ILanguageService languageService,
            IUrlRecordService urlRecordService,
            LocalizationSettings localizationSettings)
        {
           // _eventPublisher = eventPublisher;
            _languageService = languageService;
            _urlRecordService = urlRecordService;
            _localizationSettings = localizationSettings;
        }

        #endregion

        #region Methods

        public override ValueTask<RouteValueDictionary> TransformAsync(HttpContext httpContext, RouteValueDictionary values)
        {

         

            return new ValueTask<RouteValueDictionary>(values);

        }
        #endregion


    }
}

 

2.register service

src\Presentation\Nop.Web.Framework\DependencyRegistrar.cs

 //slug route transformer
            services.AddScoped<SlugRouteTransformer>();

 

startup.cs

 app.UseEndpoints(endpoints =>
            {
                var pattern = "{SeName}";

                endpoints.MapDynamicControllerRoute<SlugRouteTransformer>(pattern);

                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");


                endpoints.MapControllerRoute(
                            name: "areas",
                            pattern: "{area}/{controller}/{did?}/{action=Index}/{id?}");



                endpoints.MapModuleRoute3();
            });

 

2. register all provided routes

 

https://github.com/nopSolutions/nopCommerce/src/Presentation/Nop.Web/Infrastructure/RouteProvider.cs

step 1:write a static route table

 

using System.Linq;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Routing;




namespace Microsoft.AspNetCore.Builder
{
    public static class RegisterRoutes3
    {

        /// <summary>
        /// 注册静态路由
        /// come from;https://github.com/nopSolutions/nopCommerce/blob/12dd4825dfb56bbc64e192cd35d25e3205427646/src/Presentation/Nop.Web/Infrastructure/RouteProvider.cs   nop4.4
        /// </summary>
        /// <param name="routes"></param>
        public static void MapModuleRoute3(this IEndpointRouteBuilder endpointRouteBuilder)
        {


            //endpointRouteBuilder.MapControllerRoute(name, pattern,
            //    new { controller = "Topic", action = "TopicDetails" });

            //reorder routes so the most used ones are on top. It can improve performance

            //custom article RSS
            endpointRouteBuilder.MapControllerRoute("ArticleRSS", "article/rss/{languageId:min(0)}",
                new { controller = "Article", action = "ListRss" });



            //areas
          //  endpointRouteBuilder.MapControllerRoute(name: "areaRoute", template: "{area:exists}/{controller=Home}/{action=Index}/{id?}");

            //home page
            endpointRouteBuilder.MapControllerRoute("HomePage", "",
                new { controller = "Home", action = "Index" });

            //widgets
            //we have this route for performance optimization because named routes are MUCH faster than usual Html.Action(...)
            //and this route is highly used
            endpointRouteBuilder.MapControllerRoute("WidgetsByZone", "widgetsbyzone/",
                new { controller = "Widget", action = "WidgetsByZone" });

            //login
            endpointRouteBuilder.MapControllerRoute("Login", "login/",
                new { controller = "Customer", action = "Login" });

            //register
            endpointRouteBuilder.MapControllerRoute("Register", "register/",
                new { controller = "Customer", action = "Register" });

            //logout
            endpointRouteBuilder.MapControllerRoute("Logout", "logout/",
                new { controller = "Customer", action = "Logout" });

            //shopping cart
            endpointRouteBuilder.MapControllerRoute("ShoppingCart", "cart/",
                new { controller = "ShoppingCart", action = "Cart" });

            //estimate shipping
            endpointRouteBuilder.MapControllerRoute("EstimateShipping", "cart/estimateshipping",
                new { controller = "ShoppingCart", action = "GetEstimateShipping" });

            //wishlist
            endpointRouteBuilder.MapControllerRoute("Wishlist", "wishlist/{customerGuid?}",
                new { controller = "ShoppingCart", action = "Wishlist" });

            //customer account links
            endpointRouteBuilder.MapControllerRoute("CustomerInfo", "customer/info",
                new { controller = "Customer", action = "Info" });

            endpointRouteBuilder.MapControllerRoute("CustomerAddresses", "customer/addresses",
                new { controller = "Customer", action = "Addresses" });

            endpointRouteBuilder.MapControllerRoute("CustomerOrders", "order/history",
                new { controller = "Order", action = "CustomerOrders" });

            //contact us
            endpointRouteBuilder.MapControllerRoute("ContactUs", "contactus",
                new { controller = "Common", action = "ContactUs" });

            //sitemap
            endpointRouteBuilder.MapControllerRoute("Sitemap", "sitemap",
                new { controller = "Common", action = "Sitemap" });

            //product search
            endpointRouteBuilder.MapControllerRoute("ProductSearch", "search/",
                new { controller = "Catalog", action = "Search" });

            endpointRouteBuilder.MapControllerRoute("ProductSearchAutoComplete", "catalog/searchtermautocomplete",
                new { controller = "Catalog", action = "SearchTermAutoComplete" });

            //change currency (AJAX link)
            endpointRouteBuilder.MapControllerRoute("ChangeCurrency", "changecurrency/{customercurrency:min(0)}",
                new { controller = "Common", action = "SetCurrency" });

            //change language (AJAX link)
            endpointRouteBuilder.MapControllerRoute("ChangeLanguage", "changelanguage/{langid:min(0)}",
                new { controller = "Common", action = "SetLanguage" });

            //change tax (AJAX link)
            endpointRouteBuilder.MapControllerRoute("ChangeTaxType", "changetaxtype/{customertaxtype:min(0)}",
                new { controller = "Common", action = "SetTaxType" });

            //recently viewed products
            endpointRouteBuilder.MapControllerRoute("RecentlyViewedProducts", "recentlyviewedproducts/",
                new { controller = "Product", action = "RecentlyViewedProducts" });

            //new products
            endpointRouteBuilder.MapControllerRoute("NewProducts", "newproducts/",
                new { controller = "Product", action = "NewProducts" });

            //blog
            endpointRouteBuilder.MapControllerRoute("Blog", "blog",
                new { controller = "Blog", action = "List" });

            endpointRouteBuilder.MapControllerRoute("BlogArchive", "blog",
               new { controller = "Blog", action = "List" });


            //news
            endpointRouteBuilder.MapControllerRoute("NewsArchive", "news",
                new { controller = "News", action = "List" });

            //forum
            endpointRouteBuilder.MapControllerRoute("Boards", "boards",
                new { controller = "Boards", action = "Index" });

            //compare products
            endpointRouteBuilder.MapControllerRoute("CompareProducts", "compareproducts/",
                new { controller = "Product", action = "CompareProducts" });

            //product tags
            endpointRouteBuilder.MapControllerRoute("ProductTagsAll", "producttag/all/",
                new { controller = "Catalog", action = "ProductTagsAll" });

            //manufacturers
            endpointRouteBuilder.MapControllerRoute("ManufacturerList", "manufacturer/all/",
                new { controller = "Catalog", action = "ManufacturerAll" });

            //vendors
            endpointRouteBuilder.MapControllerRoute("VendorList", "vendor/all/",
                new { controller = "Catalog", action = "VendorAll" });


            //add product to cart (without any attributes and options). used on catalog pages.
            endpointRouteBuilder.MapControllerRoute("AddProductToCart-Catalog", "addproducttocart/catalog/{productId:min(0)}/{shoppingCartTypeId:min(0)}/{quantity:min(0)}",
                new { controller = "ShoppingCart", action = "AddProductToCart_Catalog" });

            //add product to cart (with attributes and options). used on the product details pages.
            endpointRouteBuilder.MapControllerRoute("AddProductToCart-Details", "addproducttocart/details/{productId:min(0)}/{shoppingCartTypeId:min(0)}",
                new { controller = "ShoppingCart", action = "AddProductToCart_Details" });

            //product tags
            endpointRouteBuilder.MapControllerRoute("ProductsByTag", "producttag/{productTagId:min(0)}/{SeName?}",
                new { controller = "Catalog", action = "ProductsByTag" });

            //comparing products
            endpointRouteBuilder.MapControllerRoute("AddProductToCompare", "compareproducts/add/{productId:min(0)}",
                new { controller = "Product", action = "AddProductToCompareList" });

            //product email a friend
            endpointRouteBuilder.MapControllerRoute("ProductEmailAFriend", "productemailafriend/{productId:min(0)}",
                new { controller = "Product", action = "ProductEmailAFriend" });

            //reviews
            endpointRouteBuilder.MapControllerRoute("ProductReviews", "productreviews/{productId}",
                new { controller = "Product", action = "ProductReviews" });

            endpointRouteBuilder.MapControllerRoute("CustomerProductReviews", "customer/productreviews",
                new { controller = "Product", action = "CustomerProductReviews" });

            endpointRouteBuilder.MapControllerRoute("CustomerProductReviewsPaged", "customer/productreviews/page/{page:min(0)}",
                new { controller = "Product", action = "CustomerProductReviews" });

            //back in stock notifications
            endpointRouteBuilder.MapControllerRoute("BackInStockSubscribePopup", "backinstocksubscribe/{productId:min(0)}",
                new { controller = "BackInStockSubscription", action = "SubscribePopup" });

            endpointRouteBuilder.MapControllerRoute("BackInStockSubscribeSend", "backinstocksubscribesend/{productId:min(0)}",
                new { controller = "BackInStockSubscription", action = "SubscribePopupPOST" });

            //downloads
            endpointRouteBuilder.MapControllerRoute("GetSampleDownload", "download/sample/{productid:min(0)}",
                new { controller = "Download", action = "Sample" });

            //checkout pages
            endpointRouteBuilder.MapControllerRoute("Checkout", "checkout/",
                new { controller = "Checkout", action = "Index" });

            endpointRouteBuilder.MapControllerRoute("CheckoutOnePage", "onepagecheckout/",
                new { controller = "Checkout", action = "OnePageCheckout" });

            endpointRouteBuilder.MapControllerRoute("CheckoutShippingAddress", "checkout/shippingaddress",
                new { controller = "Checkout", action = "ShippingAddress" });

            endpointRouteBuilder.MapControllerRoute("CheckoutSelectShippingAddress", "checkout/selectshippingaddress",
                new { controller = "Checkout", action = "SelectShippingAddress" });

            endpointRouteBuilder.MapControllerRoute("CheckoutBillingAddress", "checkout/billingaddress",
                new { controller = "Checkout", action = "BillingAddress" });

            endpointRouteBuilder.MapControllerRoute("CheckoutSelectBillingAddress", "checkout/selectbillingaddress",
                new { controller = "Checkout", action = "SelectBillingAddress" });

            endpointRouteBuilder.MapControllerRoute("CheckoutShippingMethod", "checkout/shippingmethod",
                new { controller = "Checkout", action = "ShippingMethod" });

            endpointRouteBuilder.MapControllerRoute("CheckoutPaymentMethod", "checkout/paymentmethod",
                new { controller = "Checkout", action = "PaymentMethod" });

            endpointRouteBuilder.MapControllerRoute("CheckoutPaymentInfo", "checkout/paymentinfo",
                new { controller = "Checkout", action = "PaymentInfo" });

            endpointRouteBuilder.MapControllerRoute("CheckoutConfirm", "checkout/confirm",
                new { controller = "Checkout", action = "Confirm" });

            endpointRouteBuilder.MapControllerRoute("CheckoutCompleted", "checkout/completed/{orderId:regex(\\d*)}",
                new { controller = "Checkout", action = "Completed" });

            //subscribe newsletters
            endpointRouteBuilder.MapControllerRoute("SubscribeNewsletter", "subscribenewsletter",
                new { controller = "Newsletter", action = "SubscribeNewsletter" });

            //email wishlist
            endpointRouteBuilder.MapControllerRoute("EmailWishlist", "emailwishlist",
                new { controller = "ShoppingCart", action = "EmailWishlist" });

            //login page for checkout as guest
            endpointRouteBuilder.MapControllerRoute("LoginCheckoutAsGuest", "login/checkoutasguest",
                new { controller = "Customer", action = "Login", checkoutAsGuest = true });

            //register result page
            endpointRouteBuilder.MapControllerRoute("RegisterResult", "registerresult/{resultId:min(0)}",
                new { controller = "Customer", action = "RegisterResult" });

            //check username availability
            endpointRouteBuilder.MapControllerRoute("CheckUsernameAvailability", "customer/checkusernameavailability",
                new { controller = "Customer", action = "CheckUsernameAvailability" });

            //passwordrecovery
            endpointRouteBuilder.MapControllerRoute("PasswordRecovery", "passwordrecovery",
                new { controller = "Customer", action = "PasswordRecovery" });

            //password recovery confirmation
            endpointRouteBuilder.MapControllerRoute("PasswordRecoveryConfirm", "passwordrecovery/confirm",
                new { controller = "Customer", action = "PasswordRecoveryConfirm" });

            //topics
            endpointRouteBuilder.MapControllerRoute("TopicPopup", "t-popup/{SystemName}",
                new { controller = "Topic", action = "TopicDetailsPopup" });

            //blog
            endpointRouteBuilder.MapControllerRoute("BlogByTag", "blog/tag/{tag}",
                new { controller = "Blog", action = "BlogByTag" });

            endpointRouteBuilder.MapControllerRoute("BlogByMonth", "blog/month/{month}",
                new { controller = "Blog", action = "BlogByMonth" });

            //blog RSS
            endpointRouteBuilder.MapControllerRoute("BlogRSS", "blog/rss/{languageId}",
                new { controller = "Blog", action = "ListRss" });

            //news RSS
            endpointRouteBuilder.MapControllerRoute("NewsRSS", "news/rss/{languageId}",
                new { controller = "News", action = "ListRss" });

            //set review helpfulness (AJAX link)
            endpointRouteBuilder.MapControllerRoute("SetProductReviewHelpfulness", "setproductreviewhelpfulness",
                new { controller = "Product", action = "SetProductReviewHelpfulness" });

            //customer account links
            endpointRouteBuilder.MapControllerRoute("CustomerReturnRequests", "returnrequest/history",
                new { controller = "ReturnRequest", action = "CustomerReturnRequests" });

            endpointRouteBuilder.MapControllerRoute("CustomerDownloadableProducts", "customer/downloadableproducts",
                new { controller = "Customer", action = "DownloadableProducts" });

            endpointRouteBuilder.MapControllerRoute("CustomerBackInStockSubscriptions", "backinstocksubscriptions/manage",
                new { controller = "BackInStockSubscription", action = "CustomerSubscriptions" });

            endpointRouteBuilder.MapControllerRoute("CustomerBackInStockSubscriptionsPaged", "backinstocksubscriptions/manage/{page:regex(\\d*)}",
                new { controller = "BackInStockSubscription", action = "CustomerSubscriptions" });

            endpointRouteBuilder.MapControllerRoute("CustomerRewardPoints", "rewardpoints/history",
                new { controller = "Order", action = "CustomerRewardPoints" });

            endpointRouteBuilder.MapControllerRoute("CustomerRewardPointsPaged", "rewardpoints/history/page/{page:min(0)}",
                new { controller = "Order", action = "CustomerRewardPoints" });

            endpointRouteBuilder.MapControllerRoute("CustomerChangePassword", "customer/changepassword",
                new { controller = "Customer", action = "ChangePassword" });

            endpointRouteBuilder.MapControllerRoute("CustomerAvatar", "customer/avatar",
                new { controller = "Customer", action = "Avatar" });

            endpointRouteBuilder.MapControllerRoute("AccountActivation", "customer/activation",
                new { controller = "Customer", action = "AccountActivation" });

            endpointRouteBuilder.MapControllerRoute("EmailRevalidation", "customer/revalidateemail",
                new { controller = "Customer", action = "EmailRevalidation" });

            endpointRouteBuilder.MapControllerRoute("CustomerForumSubscriptions", "boards/forumsubscriptions",
                new { controller = "Boards", action = "CustomerForumSubscriptions" });

            endpointRouteBuilder.MapControllerRoute("CustomerForumSubscriptionsPaged", "boards/forumsubscriptions/{page:regex(\\d*)}",
                new { controller = "Boards", action = "CustomerForumSubscriptions" });

            endpointRouteBuilder.MapControllerRoute("CustomerAddressEdit", "customer/addressedit/{addressId:min(0)}",
                new { controller = "Customer", action = "AddressEdit" });

            endpointRouteBuilder.MapControllerRoute("CustomerAddressAdd", "customer/addressadd",
                new { controller = "Customer", action = "AddressAdd" });

            //customer profile page
            endpointRouteBuilder.MapControllerRoute("CustomerProfile", "profile/{id:min(0)}",
                new { controller = "Profile", action = "Index" });

            endpointRouteBuilder.MapControllerRoute("CustomerProfilePaged", "profile/{id}/page/{page:min(0)}",
                new { controller = "Profile", action = "Index" });

            //orders
            endpointRouteBuilder.MapControllerRoute("OrderDetails", "orderdetails/{orderId:min(0)}",
                new { controller = "Order", action = "Details" });

            endpointRouteBuilder.MapControllerRoute("ShipmentDetails", "orderdetails/shipment/{shipmentId}",
                new { controller = "Order", action = "ShipmentDetails" });

            endpointRouteBuilder.MapControllerRoute("ReturnRequest", "returnrequest/{orderId:min(0)}",
                new { controller = "ReturnRequest", action = "ReturnRequest" });

            endpointRouteBuilder.MapControllerRoute("ReOrder", "reorder/{orderId:min(0)}",
                new { controller = "Order", action = "ReOrder" });

            endpointRouteBuilder.MapControllerRoute("GetOrderPdfInvoice", "orderdetails/pdf/{orderId}",
                new { controller = "Order", action = "GetPdfInvoice" });

            endpointRouteBuilder.MapControllerRoute("PrintOrderDetails", "orderdetails/print/{orderId}",
                new { controller = "Order", action = "PrintOrderDetails" });

            //order downloads
            endpointRouteBuilder.MapControllerRoute("GetDownload", "download/getdownload/{orderItemId:guid}/{agree?}",
                new { controller = "Download", action = "GetDownload" });

            endpointRouteBuilder.MapControllerRoute("GetLicense", "download/getlicense/{orderItemId:guid}/",
                new { controller = "Download", action = "GetLicense" });

            endpointRouteBuilder.MapControllerRoute("DownloadUserAgreement", "customer/useragreement/{orderItemId:guid}",
                new { controller = "Customer", action = "UserAgreement" });

            endpointRouteBuilder.MapControllerRoute("GetOrderNoteFile", "download/ordernotefile/{ordernoteid:min(0)}",
                new { controller = "Download", action = "GetOrderNoteFile" });

            //contact vendor
            endpointRouteBuilder.MapControllerRoute("ContactVendor", "contactvendor/{vendorId}",
                new { controller = "Common", action = "ContactVendor" });

            //apply for vendor account
            endpointRouteBuilder.MapControllerRoute("ApplyVendorAccount", "vendor/apply",
                new { controller = "Vendor", action = "ApplyVendor" });

            //vendor info
            endpointRouteBuilder.MapControllerRoute("CustomerVendorInfo", "customer/vendorinfo",
                new { controller = "Vendor", action = "Info" });

            //poll vote AJAX link
            endpointRouteBuilder.MapControllerRoute("PollVote", "poll/vote",
                new { controller = "Poll", action = "Vote" });

            //comparing products
            endpointRouteBuilder.MapControllerRoute("RemoveProductFromCompareList", "compareproducts/remove/{productId}",
                new { controller = "Product", action = "RemoveProductFromCompareList" });

            endpointRouteBuilder.MapControllerRoute("ClearCompareList", "clearcomparelist/",
                new { controller = "Product", action = "ClearCompareList" });

            //new RSS
            endpointRouteBuilder.MapControllerRoute("NewProductsRSS", "newproducts/rss",
                new { controller = "Product", action = "NewProductsRss" });

            //get state list by country ID  (AJAX link)
            endpointRouteBuilder.MapControllerRoute("GetStatesByCountryId", "country/getstatesbycountryid/",
                new { controller = "Country", action = "GetStatesByCountryId" });

            //EU Cookie law accept button handler (AJAX link)
            endpointRouteBuilder.MapControllerRoute("EuCookieLawAccept", "eucookielawaccept",
                new { controller = "Common", action = "EuCookieLawAccept" });

            //authenticate topic AJAX link
            endpointRouteBuilder.MapControllerRoute("TopicAuthenticate", "topic/authenticate",
                new { controller = "Topic", action = "Authenticate" });

            //topic on footer
            //endpointRouteBuilder.MapControllerRoute("Topic", "{SeName}",
            //   new { controller = "Topic", action = "TopicDetails" });

            //product attributes with "upload file" type
            endpointRouteBuilder.MapControllerRoute("UploadFileProductAttribute", "uploadfileproductattribute/{attributeId:min(0)}",
                new { controller = "ShoppingCart", action = "UploadFileProductAttribute" });

            //checkout attributes with "upload file" type
            endpointRouteBuilder.MapControllerRoute("UploadFileCheckoutAttribute", "uploadfilecheckoutattribute/{attributeId:min(0)}",
                new { controller = "ShoppingCart", action = "UploadFileCheckoutAttribute" });

            //return request with "upload file" tsupport
            endpointRouteBuilder.MapControllerRoute("UploadFileReturnRequest", "uploadfilereturnrequest",
                new { controller = "ReturnRequest", action = "UploadFileReturnRequest" });

            //forums
            endpointRouteBuilder.MapControllerRoute("ActiveDiscussions", "boards/activediscussions",
                new { controller = "Boards", action = "ActiveDiscussions" });

            endpointRouteBuilder.MapControllerRoute("ActiveDiscussionsPaged", "boards/activediscussions/page/{page:regex(\\d*)}",
                new { controller = "Boards", action = "ActiveDiscussions" });

            endpointRouteBuilder.MapControllerRoute("ActiveDiscussionsRSS", "boards/activediscussionsrss",
                new { controller = "Boards", action = "ActiveDiscussionsRSS" });

            endpointRouteBuilder.MapControllerRoute("PostEdit", "boards/postedit/{id:min(0)}",
                new { controller = "Boards", action = "PostEdit" });

            endpointRouteBuilder.MapControllerRoute("PostDelete", "boards/postdelete/{id:min(0)}",
                new { controller = "Boards", action = "PostDelete" });

            endpointRouteBuilder.MapControllerRoute("PostCreate", "boards/postcreate/{id:min(0)}",
                new { controller = "Boards", action = "PostCreate" });

            endpointRouteBuilder.MapControllerRoute("PostCreateQuote", "boards/postcreate/{id:min(0)}/{quote:min(0)}",
                new { controller = "Boards", action = "PostCreate" });

            endpointRouteBuilder.MapControllerRoute("TopicEdit", "boards/topicedit/{id:min(0)}",
                new { controller = "Boards", action = "TopicEdit" });

            endpointRouteBuilder.MapControllerRoute("TopicDelete", "boards/topicdelete/{id:min(0)}",
                new { controller = "Boards", action = "TopicDelete" });

            endpointRouteBuilder.MapControllerRoute("TopicCreate", "boards/topiccreate/{id:min(0)}",
                new { controller = "Boards", action = "TopicCreate" });

            endpointRouteBuilder.MapControllerRoute("TopicMove", "boards/topicmove/{id:min(0)}",
                new { controller = "Boards", action = "TopicMove" });

            endpointRouteBuilder.MapControllerRoute("TopicWatch", "boards/topicwatch/{id:min(0)}",
                new { controller = "Boards", action = "TopicWatch" });

            endpointRouteBuilder.MapControllerRoute("TopicSlug", "boards/topic/{id:min(0)}/{slug?}",
                new { controller = "Boards", action = "Topic" });

            endpointRouteBuilder.MapControllerRoute("TopicSlugPaged", "boards/topic/{id:min(0)}/{slug?}/page/{page:regex(\\d*)}",
                new { controller = "Boards", action = "Topic" });

            endpointRouteBuilder.MapControllerRoute("ForumWatch", "boards/forumwatch/{id:min(0)}",
                new { controller = "Boards", action = "ForumWatch" });

            endpointRouteBuilder.MapControllerRoute("ForumRSS", "boards/forumrss/{id:min(0)}",
                new { controller = "Boards", action = "ForumRSS" });

            endpointRouteBuilder.MapControllerRoute("ForumSlug", "boards/forum/{id:min(0)}/{slug?}",
                new { controller = "Boards", action = "Forum" });

            endpointRouteBuilder.MapControllerRoute("ForumSlugPaged", "boards/forum/{id:min(0)}/{slug?}/page/{page:regex(\\d*)}",
                new { controller = "Boards", action = "Forum" });

            endpointRouteBuilder.MapControllerRoute("ForumGroupSlug", "boards/forumgroup/{id:min(0)}/{slug?}",
                new { controller = "Boards", action = "ForumGroup" });

            endpointRouteBuilder.MapControllerRoute("Search", "boards/search",
                new { controller = "Boards", action = "Search" });

            //private messages
            endpointRouteBuilder.MapControllerRoute("PrivateMessages", "privatemessages/{tab?}",
                new { controller = "PrivateMessages", action = "Index" });

            endpointRouteBuilder.MapControllerRoute("PrivateMessagesPaged", "privatemessages/{tab?}/page/{page:min(0)}",
                new { controller = "PrivateMessages", action = "Index" });

            endpointRouteBuilder.MapControllerRoute("PrivateMessagesInbox", "inboxupdate",
                new { controller = "PrivateMessages", action = "InboxUpdate" });

            endpointRouteBuilder.MapControllerRoute("PrivateMessagesSent", "sentupdate",
                new { controller = "PrivateMessages", action = "SentUpdate" });

            endpointRouteBuilder.MapControllerRoute("SendPM", "sendpm/{toCustomerId:min(0)}",
                new { controller = "PrivateMessages", action = "SendPM" });

            endpointRouteBuilder.MapControllerRoute("SendPMReply", "sendpm/{toCustomerId:min(0)}/{replyToMessageId:min(0)}",
                new { controller = "PrivateMessages", action = "SendPM" });

            endpointRouteBuilder.MapControllerRoute("ViewPM", "viewpm/{privateMessageId:min(0)}",
                new { controller = "PrivateMessages", action = "ViewPM" });

            endpointRouteBuilder.MapControllerRoute("DeletePM", "deletepm/{privateMessageId:min(0)}",
                new { controller = "PrivateMessages", action = "DeletePM" });

            //activate newsletters
            endpointRouteBuilder.MapControllerRoute("NewsletterActivation", "newsletter/subscriptionactivation/{token:guid}/{active}",
                new { controller = "Newsletter", action = "SubscriptionActivation" });

            //robots.txt
            endpointRouteBuilder.MapControllerRoute("robots.txt", "robots.txt",
                new { controller = "Common", action = "RobotsTextFile" });

            //sitemap (XML)
            endpointRouteBuilder.MapControllerRoute("sitemap.xml", "sitemap.xml",
                new { controller = "Common", action = "SitemapXml" });

            endpointRouteBuilder.MapControllerRoute("sitemap-indexed.xml", "sitemap-{Id:min(0)}.xml",
                new { controller = "Common", action = "SitemapXml" });

            //store closed
            endpointRouteBuilder.MapControllerRoute("StoreClosed", "storeclosed",
                new { controller = "Common", action = "StoreClosed" });

            //install
            endpointRouteBuilder.MapControllerRoute("Installation", "install",
                new { controller = "Install", action = "Index" });

            //error page
            endpointRouteBuilder.MapControllerRoute("Error", "error",
                new { controller = "Common", action = "Error" });

            //page not found
            endpointRouteBuilder.MapControllerRoute("PageNotFound", "page-not-found",
                new { controller = "Common", action = "PageNotFound" });



            #region custom extend start
            //authenticate blog AJAX link 
            endpointRouteBuilder.MapControllerRoute("BlogAuthenticate",
                            "blog/authenticate",
                            new { controller = "Blog", action = "Authenticate" });

            // endpointRouteBuilder.MapControllerRoute("CustomBlogPost", "blogpost/{blogPostId?}/{SeName?}", new { controller = "Blog", action = "BlogPost" });

            // 1. for old
            endpointRouteBuilder.MapControllerRoute("OldBlogPost", "/blog/blogpost/{id?}/{SeName?}", new { controller = "Blog", action = "BlogPost" });

            //2.
            // endpointRouteBuilder.MapControllerRoute("BlogPost", "/blog/{id:length(24)}/{SeName}", new { controller = "Blog", action = "BlogPost" });

            //3. https://www.iaspnetcore.com/how-to-port-a-windows-forms-desktop-app-to-net-6x?id=6082e77e788a1b4f087ea7ed  login等都不行
           //  endpointRouteBuilder.MapControllerRoute("CustomBlogPost1", "{SeName}", new { controller = "Blog", action = "BlogPost" });

            // 4. for search
            endpointRouteBuilder.MapControllerRoute("BlogPost", "blogpost-{id}-{SeName}", new { controller = "Blog", action = "BlogPost" });

            //news
            endpointRouteBuilder.MapControllerRoute("NewsItem", "News/NewsItem/{Id?}/{SeName?}", new { controller = "News", action = "NewsItem" });

            endpointRouteBuilder.MapControllerRoute("customTopic", "Topic/TopicDetails/{topicId?}/{SeName?}", new { controller = "Topic", action = "topicdetail " });

            #endregion custom extend end

        }
    }
}

step 2: register in startup.cs

 app.UseMvc(routes =>
            {
                routes.MapRoute(
                name: "areas",
                template: "{area:exists}/{controller=Home}/{action=Index}/{id?}"
              );

                //定义一张路由表
                routes.MapModuleRoute();

 

3. custom RouteProvider

step 1:write a custom RouteProvider

using System.Threading.Tasks;

using Microsoft.AspNetCore.Routing;

using Microsoft.Extensions.DependencyInjection;

namespace Nop.Web.Framework.Mvc.Routes
{
    public class RouteProvider : IRouter
    {
        private readonly IRouter target;

        public RouteProvider(IRouter target)
        {
            this.target = target;
        }

        public async Task RouteAsync(RouteContext context)
        {

            //example http://www.iaspnetcore.com/about

            string domain = context.HttpContext.Request.Host.Host;//获取当前请求域名

           

            var requestPath = context.HttpContext.Request.Path.Value; //here requestPath="/about"

            if (!string.IsNullOrEmpty(requestPath) && requestPath[0] == '/')
            {
                // Trim the leading slash
                requestPath = requestPath.Substring(1);  //here requestPath="about"
            }

            if (requestPath == "/About")
            {

                var oldRouteData = context.RouteData;
                var newRouteData = new RouteData(oldRouteData);
                newRouteData.Routers.Add(target);

                newRouteData.Values["controller"] = "Article";
                newRouteData.Values["action"] = "Detail";
                newRouteData.Values["id"] = "586faeaf0141bf20236530f0";

                context.RouteData = newRouteData;
                await target.RouteAsync(context);

                return;
            }

 

step 2: add custom routerPovider in startup.cs

 app.UseMvc(routes =>
            {
                routes.MapRoute(
                name: "areas",
                template: "{area:exists}/{controller=Home}/{action=Index}/{id?}"
              );

                //定义一张路由表
                routes.MapModuleRoute();

                //自定义路由处理
                routes.Routes.Add(new RouteProvider(routes.DefaultHandler));