【问题标题】:Overwrite Generic Route in nopcommerce beta version 4.3在 nopcommerce 测试版 4.3 中覆盖通用路由
【发布时间】:2020-04-25 18:41:10
【问题描述】:

我正在为 nopcommerce beta 4.3 编写一个插件,并试图覆盖一个通用路由(Category/Slug)。该应用程序已移至 .net core 3.x,因此路由现在驻留在中间件中,并且处理方式与以前不同。我试图覆盖 Nop.Web.Infrastructure.GenericUrlRouteProvider 和 Nop.Web.Framework.Mvc.Routing.SlugRouteTransformer 如下...

public partial class GenericUrlRouteProviderExt : IRouteProvider
{
    #region Methods

    /// <summary>
    /// Register routes
    /// </summary>
    /// <param name="endpointRouteBuilder">Route builder</param>
    public void RegisterRoutes(IEndpointRouteBuilder endpointRouteBuilder)
    {
        var pattern = "{SeName}";
        if (DataSettingsManager.DatabaseIsInstalled)
        {
            var localizationSettings = endpointRouteBuilder.ServiceProvider.GetRequiredService<LocalizationSettings>();
            if (localizationSettings.SeoFriendlyUrlsForLanguagesEnabled)
            {
                var langservice = endpointRouteBuilder.ServiceProvider.GetRequiredService<ILanguageService>();
                var languages = langservice.GetAllLanguages().ToList();
                pattern = "{language:lang=" + languages.FirstOrDefault().UniqueSeoCode + "}/{SeName}";
            }
        }
        endpointRouteBuilder.MapDynamicControllerRoute<SlugRouteTransformerExt>(pattern);

        endpointRouteBuilder.MapControllerRoute("WineCategory", pattern,
             new { controller = "Wine", action = "WineCategory" });
   }

    #endregion

    #region Properties

    /// <summary>
    /// Gets a priority of route provider
    /// </summary>
    /// <remarks>
    /// it should be the last route. we do not set it to -int.MaxValue so it could be overridden (if required)
    /// </remarks>
    public int Priority => 1000;

    /// <summary>
    /// Gets the order value of endpoint.
    /// </summary>
    /// <remarks>
    /// The order value provides absolute control over the priority
    /// of an endpoint. Endpoints with a lower numeric value of order have higher priority.
    /// </remarks>
    public int Order => 1;

    #endregion
}

public class SlugRouteTransformerExt : DynamicRouteValueTransformer
{
    private readonly ILanguageService _languageService;
    private readonly LocalizationSettings _localizationSettings;
    private readonly IUrlRecordService _urlRecordService;

    public SlugRouteTransformerExt(ILanguageService languageService,
        LocalizationSettings localizationSettings,
        IUrlRecordService urlRecordService)
    {
        _languageService = languageService;
        _localizationSettings = localizationSettings;
        _urlRecordService = urlRecordService;
    }

    public override ValueTask<RouteValueDictionary> TransformAsync(HttpContext httpContext, RouteValueDictionary values)
    {
        if (values == null)
            return new ValueTask<RouteValueDictionary>(values);

        if (!values.TryGetValue("SeName", out var slugValue) || string.IsNullOrEmpty(slugValue as string))
            return new ValueTask<RouteValueDictionary>(values);

        var slug = slugValue as string;

        //performance optimization, we load a cached verion here. It reduces number of SQL requests for each page load
        var urlRecord = _urlRecordService.GetBySlug(slug);

        //no URL record found
        if (urlRecord == null)
            return new ValueTask<RouteValueDictionary>(values);

        //virtual directory path
        var pathBase = httpContext.Request.PathBase;

        //if URL record is not active let's find the latest one
        if (!urlRecord.IsActive)
        {
            var activeSlug = _urlRecordService.GetActiveSlug(urlRecord.EntityId, urlRecord.EntityName, urlRecord.LanguageId);
            if (string.IsNullOrEmpty(activeSlug))
                return new ValueTask<RouteValueDictionary>(values);

            //redirect to active slug if found
            values[NopPathRouteDefaults.ControllerFieldKey] = "Common";
            values[NopPathRouteDefaults.ActionFieldKey] = "InternalRedirect";
            values[NopPathRouteDefaults.UrlFieldKey] = $"{pathBase}/{activeSlug}{httpContext.Request.QueryString}";
            values[NopPathRouteDefaults.PermanentRedirectFieldKey] = true;
            httpContext.Items["nop.RedirectFromGenericPathRoute"] = true;

            return new ValueTask<RouteValueDictionary>(values);
        }

        //Ensure that the slug is the same for the current language, 
        //otherwise it can cause some issues when customers choose a new language but a slug stays the same
        if (_localizationSettings.SeoFriendlyUrlsForLanguagesEnabled)
        {
            var urllanguage = values["language"];
            if (urllanguage != null && !string.IsNullOrEmpty(urllanguage.ToString()))
            {
                var language = _languageService.GetAllLanguages().FirstOrDefault(x => x.UniqueSeoCode.ToLowerInvariant() == urllanguage.ToString().ToLowerInvariant());
                if (language == null)
                    language = _languageService.GetAllLanguages().FirstOrDefault();

                var slugForCurrentLanguage = _urlRecordService.GetActiveSlug(urlRecord.EntityId, urlRecord.EntityName, language.Id);
                if (!string.IsNullOrEmpty(slugForCurrentLanguage) && !slugForCurrentLanguage.Equals(slug, StringComparison.InvariantCultureIgnoreCase))
                {
                    //we should make validation above because some entities does not have SeName for standard (Id = 0) language (e.g. news, blog posts)

                    //redirect to the page for current language
                    values[NopPathRouteDefaults.ControllerFieldKey] = "Common";
                    values[NopPathRouteDefaults.ActionFieldKey] = "InternalRedirect";
                    values[NopPathRouteDefaults.UrlFieldKey] = $"{pathBase}/{slugForCurrentLanguage}{httpContext.Request.QueryString}";
                    values[NopPathRouteDefaults.PermanentRedirectFieldKey] = false;
                    httpContext.Items["nop.RedirectFromGenericPathRoute"] = true;

                    return new ValueTask<RouteValueDictionary>(values);
                }
            }
        }

        //since we are here, all is ok with the slug, so process URL
        switch (urlRecord.EntityName.ToLowerInvariant())
        {
            case "product":
                values[NopPathRouteDefaults.ControllerFieldKey] = "Product";
                values[NopPathRouteDefaults.ActionFieldKey] = "ProductDetails";
                values[NopPathRouteDefaults.ProductIdFieldKey] = urlRecord.EntityId;
                values[NopPathRouteDefaults.SeNameFieldKey] = urlRecord.Slug;
                break;
            case "producttag":
                values[NopPathRouteDefaults.ControllerFieldKey] = "Catalog";
                values[NopPathRouteDefaults.ActionFieldKey] = "ProductsByTag";
                values[NopPathRouteDefaults.ProducttagIdFieldKey] = urlRecord.EntityId;
                values[NopPathRouteDefaults.SeNameFieldKey] = urlRecord.Slug;
                break;
            case "category":
                if (!pathBase.ToString().Contains("wine-category"))
                {
                    values[NopPathRouteDefaults.ControllerFieldKey] = "Wine";
                    values[NopPathRouteDefaults.ActionFieldKey] = "WineCategory";
                    values[NopPathRouteDefaults.CategoryIdFieldKey] = urlRecord.EntityId;
                    values[NopPathRouteDefaults.SeNameFieldKey] = urlRecord.Slug;
                }
                else
                {
                    values[NopPathRouteDefaults.ControllerFieldKey] = "Catalog";
                    values[NopPathRouteDefaults.ActionFieldKey] = "Category";
                    values[NopPathRouteDefaults.CategoryIdFieldKey] = urlRecord.EntityId;
                    values[NopPathRouteDefaults.SeNameFieldKey] = urlRecord.Slug;
                }
                break;
            case "manufacturer":
                values[NopPathRouteDefaults.ControllerFieldKey] = "Catalog";
                values[NopPathRouteDefaults.ActionFieldKey] = "Manufacturer";
                values[NopPathRouteDefaults.ManufacturerIdFieldKey] = urlRecord.EntityId;
                values[NopPathRouteDefaults.SeNameFieldKey] = urlRecord.Slug;
                break;
            case "vendor":
                values[NopPathRouteDefaults.ControllerFieldKey] = "Catalog";
                values[NopPathRouteDefaults.ActionFieldKey] = "Vendor";
                values[NopPathRouteDefaults.VendorIdFieldKey] = urlRecord.EntityId;
                values[NopPathRouteDefaults.SeNameFieldKey] = urlRecord.Slug;
                break;
            case "newsitem":
                values[NopPathRouteDefaults.ControllerFieldKey] = "News";
                values[NopPathRouteDefaults.ActionFieldKey] = "NewsItem";
                values[NopPathRouteDefaults.NewsItemIdFieldKey] = urlRecord.EntityId;
                values[NopPathRouteDefaults.SeNameFieldKey] = urlRecord.Slug;
                break;
            case "blogpost":
                values[NopPathRouteDefaults.ControllerFieldKey] = "Blog";
                values[NopPathRouteDefaults.ActionFieldKey] = "BlogPost";
                values[NopPathRouteDefaults.BlogPostIdFieldKey] = urlRecord.EntityId;
                values[NopPathRouteDefaults.SeNameFieldKey] = urlRecord.Slug;
                break;
            case "topic":
                values[NopPathRouteDefaults.ControllerFieldKey] = "Topic";
                values[NopPathRouteDefaults.ActionFieldKey] = "TopicDetails";
                values[NopPathRouteDefaults.TopicIdFieldKey] = urlRecord.EntityId;
                values[NopPathRouteDefaults.SeNameFieldKey] = urlRecord.Slug;
                break;
            default:
                //no record found, thus generate an event this way developers could insert their own types
                break;
        }

        return new ValueTask<RouteValueDictionary>(values);
    }
}

但收到错误消息:使用 ExpandEndpoint 要求被替换的端点具有唯一的优先级。发现以下端点具有相同的优先级...

我正在寻找一种有效的方法来拦截指定的路由并重新路由它......

我也在 PluginStratup 中考虑过这样做,不知道该找谁...

public void Configure(IApplicationBuilder application)
    {

        //our custom middleware
        application.Use(async (context, next) =>
        {


            await next();

        });
    }

有没有人研究过这个并找到了解决方案?

【问题讨论】:

    标签: routes middleware nopcommerce intercept


    【解决方案1】:

    我没有阅读你发布的所有代码,但如果我理解正确,你只是想劫持路线。

    看看Nop.Web.Infrastructure.GenericUrlRouteProvider.RegisterRoutes(),这是定义类别/slug 路线的地方。

    您需要在插件中做的所有事情就是定义一个实现 IRouteProvider 的类,其优先级大于 -1000000(这是 GenericUrlRouteProvider 使用的优先级)

    如:

    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Routing;
    using Microsoft.Extensions.DependencyInjection;
    using Nop.Core.Domain.Localization;
    using Nop.Data;
    using Nop.Services.Localization;
    using Nop.Web.Framework.Mvc.Routing;
    using System.Linq;
    
    namespace Namespace
    {
        public class RouteProvider : IRouteProvider
        {
            /// <summary>
            /// Register routes
            /// </summary>
            /// <param name="endpointRouteBuilder">Route builder</param>
            public void RegisterRoutes(IEndpointRouteBuilder endpointRouteBuilder)
            {
                var pattern = "{SeName}";
                if (DataSettingsManager.DatabaseIsInstalled)
                {
                    var localizationSettings = endpointRouteBuilder.ServiceProvider.GetRequiredService<LocalizationSettings>();
                    if (localizationSettings.SeoFriendlyUrlsForLanguagesEnabled)
                    {
                        var langservice = endpointRouteBuilder.ServiceProvider.GetRequiredService<ILanguageService>();
                        var languages = langservice.GetAllLanguages().ToList();
                        pattern = "{language:lang=" + languages.FirstOrDefault().UniqueSeoCode + "}/{SeName}";
                    }
                }
    
                endpointRouteBuilder.MapControllerRoute("overriden_Category", pattern, new { controller = "OverridenCatalog", action = "Category" });
            }
    
            /// <summary>
            /// Gets a priority of route provider
            /// </summary>
            public int Priority => 0;
        }
    }
    

    更改它以指向正确的控制器/操作

    【讨论】:

      猜你喜欢
      • 2017-05-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-19
      • 1970-01-01
      • 2021-06-04
      • 2023-03-26
      • 1970-01-01
      相关资源
      最近更新 更多