A nopCommerce architecture question when doing customization

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.
10 năm cách đây
sproaty wrote:
Great topics of discussion guys - I'm writing a nopCommerce research guide for my boss to decide whether it's a viable platform for us to leverage and I've covered some of these areas - just trying to summarise a lot of my findings!

Sunny - I thought you'd managed to wire your custom service as a dependency replacement? In a plugin you can implement a DependencyRegistrar:


Nope, I updated DI in the framework, in the old day, DI sits in only 1 place, not all over the place. More like a factory pattern, you put your IoC/DI in 1 place and the rest is magic.

sproaty wrote:


- Extend controller via plugin, make what's needed protected. Mark methods as virtual. Register existing URL route that you're overriding to your extended controller - deal with partials etc



You don't need to mark it again if you use the same controller name in a different namespace.

This is valid


namespace Nop.Admin.Controllers.Custom
{
    public class ProductController : Nop.Admin.Controllers.ProductController

.....




In your RouteProvider, you explicitly set the namespace to use Custom, then the Nop.Admin.Controllers.ProductController can never be reached from browser BUT since we inherited it and actions are public, so you can access them via the CustomController
10 năm cách đây
sproaty wrote:


I'm also going to be doing a lot of view customisation most likely, so I'm trying to find some limits. Just moving the shopping basket in the header outside of its containing <div> was tricky because it relied on information inside the model passed in by a controller, and a partial view was rendering this containing div.



"Overriding" view is not an issue. With MVC, it separates nop logic from presentation layer (HTML), and for that you can play around with your HTML as much as you like.
10 năm cách đây
sunnyw wrote:


If write CustomCatalog instead of remarking all the old controller to something else, you lose SEO as your URL will look ugly now, you lose most of the original functionalities except your "extra".  There is another way to change how URL mapped in RouteProvider, but again, a bit of pain.



I just want to clear up something very specific. Maybe I chose a bad example. Lets use an existing example


routes.MapRoute("CustomCheckout", // Route name
                           "/checkout",          // URL with parameters
                            new { controller = "CustomCheckoutController", action = "CustomCheckoutAction" }
                            // Parameter defaults );



Does nothing to your SEO. ~/checkout is still checkout, but it calls your new controller instead of the old one. All the other routes still map to the old checkout controller.

I think you are locking in on the idea of overriding a CONTROLLER with routes, as opposed to overriding individual ACTIONS.

In this case, your CustomCheckoutController would not need to have any relation to CheckoutController (utility functions aside). It could even be a class of just one action if that's all you need.

I guess there becomes a tipping point between how many routes you override vs. how many routes you leave the same, but if you have to override the majority of the routes or install a significant amount of functionality, why inherit/partial in the first place?
10 năm cách đây
mattsoundworld wrote:


If write CustomCatalog instead of remarking all the old controller to something else, you lose SEO as your URL will look ugly now, you lose most of the original functionalities except your "extra".  There is another way to change how URL mapped in RouteProvider, but again, a bit of pain.



I just want to clear up something very specific. Maybe I chose a bad example. Lets use an existing example


routes.MapRoute("CustomCheckout", // Route name
                           "/checkout",          // URL with parameters
                            new { controller = "CustomCheckoutController", action = "CustomCheckoutAction" }
                            // Parameter defaults );



Does nothing to your SEO. ~/checkout is still checkout, but it calls your new controller instead of the old one. All the other routes still map to the old checkout controller.

I think you are locking in on the idea of overriding a CONTROLLER with routes, as opposed to overriding individual ACTIONS.

In this case, your CustomCheckoutController would not need to have any relation to CheckoutController (utility functions aside). It could even be a class of just one action if that's all you need.

I guess there becomes a tipping point between how many routes you override vs. how many routes you leave the same, but if you have to override the majority of the routes or install a significant amount of functionality, why inherit/partial in the first place?


Sorry when I said SEO, I meant if you leave CustomCheckoutController as is without replacing the name, then your URL will become mydomain.com/CustomCheckout/{action} which is quite ugly from SEO perspective. You will have Custom everywhere.. or everyone will have Custom everywhere and google weight heavier on words in the URL.


In terms of tipping point, I totally agree. At this stage, I might only change 1 method, maybe I add some services to the ctor, but I can't tell what my team will do after we go live. Easier future upgrade is always my considerations when I choose a technology.

1 of my other requirements is multi-tenant. With partials, I am going to end up with Brand1PartialProductController, Brand2PartialProductController etc... and that their functionality maybe completely different.


With inheritance, IoC took care of it.

To add to the complexity, I am implementing a MyCoreController, that would implement nopCoreController, and all my brands will implement MyCoreController. This way I have flexibility to add functionalities to all 15 brands in MyCore or only add brand specific in Brand1Controller, and I can still leave upgrade path for nopCoreController.


I hope I am making sense, and I am not ruling out anything, I also went down to the partial path at the very beginning, it seems it is the way how nop designed but looking at the requirements of all 15 brands, I can't estimates how many partials I will end up with?
10 năm cách đây
sunnyw wrote:


Sorry when I said SEO, I meant if you leave CustomCheckoutController as is without replacing the name, then your URL will become mydomain.com/CustomCheckout/{action} which is quite ugly from SEO perspective. You will have Custom everywhere.. or everyone will have Custom everywhere and google weight heavier on words in the URL.



Agree its ugly, but that's not what I'm suggesting. I'm saying you can get mydomain.com/Checkout/{action} to work by overriding the route map. Google doesn't care which controller handles the request, it just cares that it gets handles and can parse the response.

Even better is mydomain.com/action, which is actually closer to the example. mydomain.com/checkout is not assuming a phantom index as in mydomain.com/checkout/index, it is directly routed to the checkout ACTION in the CheckoutController. Without mapping, the default url would be mydomain.com/checkout/checkout, which really is ugly.
10 năm cách đây
sunnyw wrote:


1 of my other requirements is multi-tenant. With partials, I am going to end up with Brand1PartialProductController, Brand2PartialProductController etc... and that their functionality maybe completely different.



Ooooh.... You might wanna go factory pattern REALLLLL quick. If this is really where you are headed, I would refactor the crap outta the existing controllers so you can slice and dice as required.

Look into implementing IControllerFactory. I think Autofac will work with that to handle instance logic at the controller level
10 năm cách đây
sunnyw wrote:


To add to the complexity, I am implementing a MyCoreController, that would implement nopCoreController, and all my brands will implement MyCoreController. This way I have flexibility to add functionalities to all 15 brands in MyCore or only add brand specific in Brand1Controller, and I can still leave upgrade path for nopCoreController.



Understand, that all your controllers in scope will resolve for all your brands unless you do something to interrupt that. The theme engine, work context, and store context can help you decide what to show when someone requests a route, but it will execute the request unless you prevent it with an action filter or purposely redirect based on the incoming request.

Specifically, Brand1 will have access to Brand2Partial and vice versa in the above scenario
10 năm cách đây
mattsoundworld wrote:


1 of my other requirements is multi-tenant. With partials, I am going to end up with Brand1PartialProductController, Brand2PartialProductController etc... and that their functionality maybe completely different.



Ooooh.... You might wanna go factory pattern REALLLLL quick. If this is really where you are headed, I would refactor the crap outta the existing controllers so you can slice and dice as required.

Look into implementing IControllerFactory. I think Autofac will work with that to handle instance logic at the controller level


Thanks for the heads up, will have a look, just afraid won't be spending much time in refactoring. We are looking for something internal use only and it won't be SaaS, so hopefully I can find something quick without refactoring the whole nop.
8 năm cách đây
I know this is an old post but I thought I'd chime in as a plugin author.

Here's what has worked for me over the years.

Quite simply, you need to hook in to the event system to perform customizations. Of course this doesn't always work, especially controller based mods, but you need to consider future upgrades to the platform. Subscribing to events and keeping that code in a plugin is by far the easiest way to keep Nop fresh with the least amount of work.

For controller based mods I surround all code I "touch" using comments

// Start Change
some code goes here
// End Change

You might think this is silly but you need to consider any future upgrade paths otherwise you'll have a nightmare on your hands.

What I see some people do is inherit from services and overriding methods to customise Nop and then registering those services with Autofac.

This becomes problematic, especially if other plugins inherit from these services. The NopCommerce Lucene.NET plugin is a good example, it inherits from the ProductService in order to override the Search method. If you decide to inherit from ProductService and register your class with Autofac you'll break the Lucene.NET plugin.

Depending on my customisation, you could inherit from the ProductService in the Lucene.NET plugin but a future update to the plugin could break what you're trying to do.

Try sticking to the event system. It's not perfect, i.e. you can't cancel propagation, but it's way better than overriding services.
8 năm cách đây
Unfortunately, there aren't too many events defined.  (At my suggestion, Andrei has only just recently added Login & Registration in upcoming 3.70).   Also consider using Action Filters.
This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.