NopCommerce 4.3 extend model and use it in child theme view

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.
3 years ago
builder.RegisterType<ArcaneProductModelFactory>().As<Nop.Web.Factories.IProductModelFactory>().InstancePerLifetimeScope();


Before it was ProductModelFactory. Now it works. I tried to override routes:
public class RouteProvider : IRouteProvider
    {
        /// <summary>
        /// Register routes
        /// </summary>
        /// <param name="endpointRouteBuilder">Route builder</param>
        public void RegisterRoutes(IEndpointRouteBuilder endpointRouteBuilder)
        {
            var pattern = "compareproducts";
            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 + "}/compareproducts";
                }
            }

            endpointRouteBuilder.MapControllerRoute("CompareProducts", pattern, new { controller = "ArcaneProductController", action = "CompareProducts" });
        }

        /// <summary>
        /// Gets a priority of route provider
        /// </summary>
        public int Priority => 0;
    }

but breakpoint still  hits old controller.
3 years ago
Looks like you are trying to override CompareProducts in the ProductController?  If the override method in your overridden controller is also named CompareProducts then you should not need a route provider.  

Could you copy/paste your ArcaneProductController code here?
3 years ago
Thank You for an advice. Here is the code:
[AutoValidateAntiforgeryToken]
    public partial class ArcaneProductController : ProductController
    {
        #region Fields

        private readonly CaptchaSettings _captchaSettings;
        private readonly CatalogSettings _catalogSettings;
        private readonly IAclService _aclService;
        private readonly ICompareProductsService _compareProductsService;
        private readonly ICustomerActivityService _customerActivityService;
        private readonly ICustomerService _customerService;
        private readonly IEventPublisher _eventPublisher;
        private readonly ILocalizationService _localizationService;
        private readonly IOrderService _orderService;
        private readonly IPermissionService _permissionService;
        private readonly IProductAttributeParser _productAttributeParser;
        private readonly ArcaneProductModelFactory _productModelFactory;
        private readonly IProductService _productService;
        private readonly IRecentlyViewedProductsService _recentlyViewedProductsService;
        private readonly IReviewTypeService _reviewTypeService;
        private readonly IShoppingCartModelFactory _shoppingCartModelFactory;
        private readonly IShoppingCartService _shoppingCartService;
        private readonly IStoreContext _storeContext;
        private readonly IStoreMappingService _storeMappingService;
        private readonly IUrlRecordService _urlRecordService;
        private readonly IWebHelper _webHelper;
        private readonly IWorkContext _workContext;
        private readonly IWorkflowMessageService _workflowMessageService;
        private readonly LocalizationSettings _localizationSettings;
        private readonly ShoppingCartSettings _shoppingCartSettings;

        #endregion

        #region Ctor

        public ArcaneProductController(CaptchaSettings captchaSettings,
            CatalogSettings catalogSettings,
            IAclService aclService,
            ICompareProductsService compareProductsService,
            ICustomerActivityService customerActivityService,
            ICustomerService customerService,
            IEventPublisher eventPublisher,
            ILocalizationService localizationService,
            IOrderService orderService,
            IPermissionService permissionService,
            IProductAttributeParser productAttributeParser,
            ArcaneProductModelFactory productModelFactory,
            IProductService productService,
            IRecentlyViewedProductsService recentlyViewedProductsService,
            IReviewTypeService reviewTypeService,
            IShoppingCartModelFactory shoppingCartModelFactory,
            IShoppingCartService shoppingCartService,
            IStoreContext storeContext,
            IStoreMappingService storeMappingService,
            IUrlRecordService urlRecordService,
            IWebHelper webHelper,
            IWorkContext workContext,
            IWorkflowMessageService workflowMessageService,
            LocalizationSettings localizationSettings,
            ShoppingCartSettings shoppingCartSettings) : base
                (captchaSettings,
            catalogSettings,
            aclService,
            compareProductsService,
            customerActivityService,
            customerService,
            eventPublisher,
            localizationService,
            orderService,
            permissionService,
            productAttributeParser,
            productModelFactory,
            productService,
            recentlyViewedProductsService,
            reviewTypeService,
            shoppingCartModelFactory,
            shoppingCartService,
            storeContext,
            storeMappingService,
            urlRecordService,
            webHelper,
            workContext,
            workflowMessageService,
            localizationSettings,
            shoppingCartSettings
                )
        {
            _captchaSettings = captchaSettings;
            _catalogSettings = catalogSettings;
            _aclService = aclService;
            _compareProductsService = compareProductsService;
            _customerActivityService = customerActivityService;
            _customerService = customerService;
            _eventPublisher = eventPublisher;
            _localizationService = localizationService;
            _orderService = orderService;
            _permissionService = permissionService;
            _productAttributeParser = productAttributeParser;
            _productModelFactory = productModelFactory;
            _productService = productService;
            _reviewTypeService = reviewTypeService;
            _recentlyViewedProductsService = recentlyViewedProductsService;
            _shoppingCartModelFactory = shoppingCartModelFactory;
            _shoppingCartService = shoppingCartService;
            _storeContext = storeContext;
            _storeMappingService = storeMappingService;
            _urlRecordService = urlRecordService;
            _webHelper = webHelper;
            _workContext = workContext;
            _workflowMessageService = workflowMessageService;
            _localizationSettings = localizationSettings;
            _shoppingCartSettings = shoppingCartSettings;
        }

        #endregion

        #region Methods
        override public IActionResult RecentlyViewedProducts()
        {
            if (!_catalogSettings.RecentlyViewedProductsEnabled)
                return Content("");

            var products = _recentlyViewedProductsService.GetRecentlyViewedProducts(_catalogSettings.RecentlyViewedProductsNumber);

            var model = new List<ProductOverviewModel>();
            model.AddRange(_productModelFactory.PrepareArcaneProductOverviewModels(products));

            return View(model);
        }
        override public IActionResult NewProducts()
        {
            if (!_catalogSettings.NewProductsEnabled)
                return Content("");

            var products = _productService.SearchProducts(
                storeId: _storeContext.CurrentStore.Id,
                visibleIndividuallyOnly: true,
                markedAsNewOnly: true,
                orderBy: ProductSortingEnum.CreatedOn,
                pageSize: _catalogSettings.NewProductsNumber);

            var model = new List<ProductOverviewModel>();
            model.AddRange(_productModelFactory.PrepareArcaneProductOverviewModels(products));

            return View(model);
        }
        public override IActionResult CompareProducts()
        {
            if (!_catalogSettings.CompareProductsEnabled)
                return RedirectToRoute("Homepage");

            var model = new CompareProductsModel
            {
                IncludeShortDescriptionInCompareProducts = _catalogSettings.IncludeShortDescriptionInCompareProducts,
                IncludeFullDescriptionInCompareProducts = _catalogSettings.IncludeFullDescriptionInCompareProducts,
            };

            var products = _compareProductsService.GetComparedProducts();

            //ACL and store mapping
            products = products.Where(p => _aclService.Authorize(p) && _storeMappingService.Authorize(p)).ToList();
            //availability dates
            products = products.Where(p => _productService.ProductIsAvailable(p)).ToList();

            //prepare model
            _productModelFactory.PrepareArcaneProductOverviewModels(products, prepareSpecificationAttributes: true)
                .ToList()
                .ForEach(model.Products.Add);
            return View(model);
        }
        #endregion
    }
3 years ago
That looks more or less correct.   The modifiers are out of order in the RecentlyViewedProducts and NewProducts methods which has no real effect, and my base ProductController only has 21 parameters in 4.2, but I made some minor changes and successfully hit the CompareProducts override (without a route provider) when visiting: http://localhost:15536/compareproducts  

Note that adding products to the compare list is a different method.  CompareProducts is when you view the products side by side.

If you put your ArcaneProductController file in a subfolder make sure that Visual Studio did not change the namespace to something Nop.Web.Controllers.Overrides, it should be Nop.Web.Controllers just like ProductController.

Double check that your Order is > 1000 in your DependencyRegistrar, I used:

using Autofac;
using Nop.Core.Configuration;
using Nop.Core.Infrastructure;
using Nop.Core.Infrastructure.DependencyManagement;

namespace Nop.Web.Controllers
{
    public class DependencyRegistrar : IDependencyRegistrar
    {
        public int Order => 2000;   // Use a high number here so we get added last and take precedence.

        public void Register(ContainerBuilder builder, ITypeFinder typeFinder, NopConfig config)
        {
            builder.RegisterType<BackInStockSubscriptionControllerOverride>().As<BackInStockSubscriptionController>().InstancePerLifetimeScope();
            builder.RegisterType<ArcaneProductController>().As<ProductController>().InstancePerLifetimeScope();
        }
    }
}
3 years ago
Also, if the only difference in your controller methods is how you prepare the models (PrepareArcaneProductOverviewModels), then you could just override the PrepareProductOverviewModels method in a ProductModelFactoryOverride.As<IProductModelFactory> instead (and leave the ProductController untouched).
3 years ago
ok thank you, and how then attach my plugin to new theme? I need extended model ArcaneProductOverviewModel to be available in _ProductBox.
3 years ago
Not something I have tried, but I would think it should be as simple as editing ProductBox.cshtml to use @model ArcaneProductOverviewModel

Is your ArcaneProductOverviewModel wildly different than the ProductOverviewModel ?  It is a partial class so if you just need additional properties you can extend the base class like this:


using Nop.Web.Framework.Models;

namespace Nop.Web.Models.Catalog
{
    public partial class ProductOverviewModel
    {
        public int SoldQuantity { get; set; }

        #region Nested Classes  

        public partial class ProductPriceModel : BaseNopModel
        {
            public bool? AddToCartForPrice { get; set; }  
        }

        #endregion
    }
}


Then you would only need to override PrepareProductOverviewModels in a custom _productModelFactory
3 years ago
I already made, but namespace or what does not allow to see my model in productbox.cshtml, that is the main problem.
using Nop.Core.Domain.Catalog;
using Nop.Web.Models.Catalog;

namespace ArcaneThemePlus.Models
{
    public partial class ArcaneProductOverviewModel : ProductOverviewModel
    {
        public string manufacturerSeName { get; set; }
        public Manufacturer manufacturer { get; set; }
        public ArcaneProductOverviewModel()
        {
            Manufacturer manufacturer = new Manufacturer();
        }      
    }
}
3 years ago
add your namespace to the cshtml:

@using ArcaneThemePlus.Models
3 years ago
The type or namespace name "ArcaneThemePlus" cannot be found (in pruductbox.cshtml):
@model ProductOverviewModel
@using Nop.Core
@using Nop.Core.Domain.Catalog
@using Nop.Core.Domain.Orders
@using Nop.Core.Domain.Tax
@using ArcaneThemePlus.Models
This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.