Slug Implement for Admin Site in Nopcommerce Plugin

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.
1 year ago
I am new in Nopcommerce Development. I tried to make a plugin Which have person class and can access from admin site. So, I am implementing Slug on persons. When I Am creating new person then the url record is automatically created. But when I am trying access, the person using slug from admin site it always showing not found. Here is my code below. How can I solve this?

//For Creating Person
[HttpPost]
        public virtual async Task<IActionResult> Create([Bind("Id,Name,DateOfBirth,Gender,MaritalStatus")] PersonModel model)
        {
            if (model == null || model.Id < 0)
            {
                return new NullJsonResult();
            }
            if (ModelState.IsValid)
            {
                var person = model.ToEntity<Person>();
                await _personServices.InsertPersonAsync(person);

                model.SeName = await _urlRecordService.ValidateSeNameAsync(person, model.SeName, person.Name, true);
                await _urlRecordService.SaveSlugAsync(person, model.SeName, 0);

                return RedirectToAction("List");
            }
            else
            {
                return View(model);
            }
        }


Plugins router transformer.

public partial class SlugRouteTransformer : DynamicRouteValueTransformer
    {

        private readonly LocalizationSettings _localizationSettings;
        private readonly IUrlRecordService _urlRecordService;
        private readonly IEventPublisher _eventPublisher;

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

        protected async Task SingleSlugRoutingAsync(HttpContext httpContext, RouteValueDictionary values, UrlRecord urlRecord, string catalogPath)
        {
            //if URL record is not active let's find the latest one
            var slug = urlRecord.IsActive
                ? urlRecord.Slug
                : await _urlRecordService.GetActiveSlugAsync(urlRecord.EntityId, urlRecord.EntityName, urlRecord.LanguageId);
            if (string.IsNullOrEmpty(slug))
                return;
            RouteToAction(values, "Person", "PersonDetails", slug, (NopRoutingDefaults.RouteValue.PersonId, urlRecord.EntityId));
        }


        protected void RouteToAction(RouteValueDictionary values, string controller, string action, string slug, params (string Key, object Value)[] parameters)
        {
            values[NopRoutingDefaults.RouteValue.Controller] = controller;
            values[NopRoutingDefaults.RouteValue.Action] = action;
            values[NopRoutingDefaults.RouteValue.SeName] = slug;
            foreach (var (key, value) in parameters)
                values[key] = value;

        }


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

            var values = new RouteValueDictionary(routeValues);
            if (values is null)
                return values;

            if (!values.TryGetValue(NopRoutingDefaults.RouteValue.SeName, out var slug))
                return values;

            //find record by the URL slug
            if (await _urlRecordService.GetBySlugAsync(slug.ToString()) is not UrlRecord urlRecord)
                return values;

            //allow third-party handlers to select an action by the found URL record
            var routingEvent = new GenericRoutingEvent(httpContext, values, urlRecord);
            await _eventPublisher.PublishAsync(routingEvent);
            if (routingEvent.Handled)
                return values;

            var personlogPath = values.TryGetValue(NopRoutingDefaults.RouteValue.SeName, out var personPathValue)
                ? personPathValue?.ToString()
                : string.Empty;

            //finally, select an action by the URL record only
            await SingleSlugRoutingAsync(httpContext, values, urlRecord, personlogPath);

            return values;

        }


    }

routing provider setup


namespace Nop.Plugin.Widget.PersonInfoInDifferentLanguages.Routing
{
    public class GenericUrlRouteProviderConfig : BaseRouteProvider, IRouteProvider
    {
        public void RegisterRoutes(IEndpointRouteBuilder endpointRouteBuilder)
        {
            var genericPattern = $"Admin/{{{NopRoutingDefaults.RouteValue.SeName}}}";
            endpointRouteBuilder.MapDynamicControllerRoute<SlugRouteTransformer>(genericPattern);

            endpointRouteBuilder.MapControllerRoute(name: NopRoutingDefaults.RouteName.Generic.Person,
                                                    pattern: genericPattern,
                                                    defaults: new
                                                    {
                                                        controller = "Person",
                                                        action = "PersonDetails",
                                                        area = "Admin"
                                                    });
        }
        public int Priority => 0;
    }
}




Register Slug

public class NopStartup : INopStartup
    {
        public int Order => 0;

        public void Configure(IApplicationBuilder application)
        {
            
        }



        public void ConfigureServices(IServiceCollection services, IConfiguration configuration)
        {
            services.Configure<RazorViewEngineOptions>(options =>
                                                        options.ViewLocationExpanders.Add(new CustomViewEngine()));
            services.AddScoped<ILanguageServices, LanguageServices>();
            services.AddScoped<IPersonServices, PersonServices>();
            services.AddScoped<IPersonInfosInDifferentLanguagesServices, PersonInfosInDifferentLanguagesServices>();
            services.AddScoped<ILanguageFactory,LanguageFactory>();
            services.AddScoped<IPersonFactory, PersonFactory>();
            services.AddScoped<IPersonInfoInDifferentLanguagesFactory, PersonInfoInDifferentLanguagesFactory>();
            services.AddScoped<Routing.SlugRouteTransformer>();
            services.AddScoped<GenericUrlRouteProviderConfig>();
        }
    }


If there are any easy way please explain or give an example. Thank you..
1 year ago
I got this solution. When slug is implementing it rises an event. we can catch the event and after catching the event we can setup the routing details. In this method. And then it's working.

public class RoutingEventConsumer : IConsumer<GenericRoutingEvent>
    {
        public Task HandleEventAsync(GenericRoutingEvent eventMessage)
        {
            var values = eventMessage.RouteValues;
            var urlRecord = eventMessage.UrlRecord;
            if (urlRecord.EntityName.Equals(nameof(Person), StringComparison.InvariantCultureIgnoreCase))
            {
                values[NopRoutingDefaults.RouteValue.Controller] = "Person";
                values[NopRoutingDefaults.RouteValue.Action] = "PersonDetails";
                values[NopRoutingDefaults.RouteValue.SeName] = urlRecord.Slug;
                values["area"] = "Admin";
                values["id"] = urlRecord.EntityId;
            }
            /*eventMessage.Handled = true;*/
            return Task.CompletedTask;
        }
    }
This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.