Plugin doesn't override admin controller

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.
9 years ago
wooncherk wrote:
Why not try this instead? [url=Overriding (Intercepting) nopCommerce Controllers and Actions]http://www.pronopcommerce.com/overriding-intercepting-nopcommerce-controllers-and-actions[/url]

I have tried it, but seem like I need to redirect to the path that I customize it. Is there anyway, I just want to keep the url but the controller and action is the one I've created?

I don't get "but seem like I need to redirect to the path that I customize it". Can you explain again? :)

okay just get the example of StoreClosedAttribute, the system redirect to StoreClosed page and the url path is change to /StoreClosed. But what I want it is the url path didn't change. For example, /customer/info. Suppose the ActionName Info in CustomerController is executing, but I want it to be CustomCustomerController.

I've successfully make it work by creating RouteProvider for frontend. For backend, I've created an AreaRegistration to overlap it and it's work too, but sometimes doesn't work.

The line that make it redirect is

if (storeInformationSettings.StoreClosedAllowForAdmins && EngineContext.Current.Resolve<IWorkContext>().CurrentCustomer.IsAdmin())
{
    //do nothing - allow admin access
}
else
{
    var storeClosedUrl = new UrlHelper(filterContext.RequestContext).RouteUrl("StoreClosed");
    filterContext.Result = new RedirectResult(storeClosedUrl); // <-- this line makes it redirect
}


Remove it and it'll stay with the same Action. :)


I think I get what you means thanks
9 years ago
unfortunately doesn't work.

Okay let me explain again, for example Admin/Order/List normally the action List in OrderController will be executed.
Right now I want to intercept it to execute the List in CustomOrderController instead of OrderController, and the uri must remain the same.

At this moment, I am register at AreaRegistraion as below:-
 public class AdminAreaRegistration : AreaRegistration
    {
        public override string AreaName
        {
            get { return "Admin"; }
        }

        public override void RegisterArea(AreaRegistrationContext context)
        {

                    context.MapRoute(
                        "custom_admin_order",
                        "Admin/Order/List/",
                        new { controller = "CustomOrder", action = "List", area = "Admin", id = "" },
                        new[] { "Misc.CustomAdminOrder.Controllers" });

        }
    }


It is working, but sometime doesn't work and need to restart the application several times to make it work.

So right now I need a better way to make it 100% work.
9 years ago
etws14 wrote:
unfortunately doesn't work.

Okay let me explain again, for example Admin/Order/List normally the action List in OrderController will be executed.
Right now I want to intercept it to execute the List in CustomOrderController instead of OrderController, and the uri must remain the same.

At this moment, I am register at AreaRegistraion as below:-
 public class AdminAreaRegistration : AreaRegistration
    {
        public override string AreaName
        {
            get { return "Admin"; }
        }

        public override void RegisterArea(AreaRegistrationContext context)
        {

                    context.MapRoute(
                        "custom_admin_order",
                        "Admin/Order/List/",
                        new { controller = "CustomOrder", action = "List", area = "Admin", id = "" },
                        new[] { "Misc.CustomAdminOrder.Controllers" });

        }
    }


It is working, but sometime doesn't work and need to restart the application several times to make it work.

So right now I need a better way to make it 100% work.


Then:

1. Use the method I documented in my blog
2. Move the code from your custom Action into the OnActionExecuting() method in the your ActionFilter created in [1]

:)
9 years ago
In fact if your case, using RouteProvider might just work, wouldn't it?

So just make your route provider take the same URL, but set it at a higher priority, and point to your custom controller. This should work. (No need for ActionFilter then)
9 years ago
wooncherk wrote:
In fact if your case, using RouteProvider might just work, wouldn't it?

So just make your route provider take the same URL, but set it at a higher priority, and point to your custom controller. This should work. (No need for ActionFilter then)


For front-end it is working at all time, but for admin, I can't figure out the problem. Sometime I restart application or replace new library files, the system doesn't load it. I have been debugging it, everything look well, but at the end the result doesn't execute my custom controller but executing the original controller. After tried several, I found that after restart the application few times. The system will executing the custom controller.

And I found that this is not a better way, as customer doesn't know whether the custom controller is executed or the original.

That's why I am trying to get better method to resolve the issues
9 years ago
forgot to mention, I am creating a plugin to overwrite some admin page
9 years ago
In fact I suggest we continue using ActionFilter. Again,

1. Use ActionFilter like how I documented
2. Move your code from controller into ActionFilter.
2. Instead of returning a RedirectToRouteResult, return a ViewResult.

So it reads something like following:

OnActionExecuting(ActionExecutingContext filterContext)
{
    // codes migrated from your custom controller
    // ...
    // ...

    filterContext.Result = new ViewResult() { /* point to your view and model */ };
}


This should work. :)
9 years ago
wooncherk wrote:
In fact I suggest we continue using ActionFilter. Again,

1. Use ActionFilter like how I documented
2. Move your code from controller into ActionFilter.
2. Instead of returning a RedirectToRouteResult, return a ViewResult.

So it reads something like following:

OnActionExecuting(ActionExecutingContext filterContext)
{
    // codes migrated from your custom controller
    // ...
    // ...

    filterContext.Result = new ViewResult() { /* point to your view and model */ };
}


This should work. :)


Okay I got the idea. Thanks for your help.
9 years ago
etws14 wrote:
Does anybody facing this issues? I am trying to override admin controller with plugin, but then sometime the system doesn't override it, but after few restart it will work again. Is there any way to load it after restart application at one time only?

Any sample codes of how you are wiring things up? Without sample codes we can't comment much... :)


using Nop.Core.Infrastructure;
using Nop.Core.Plugins;
using System.Web.Mvc;
namespace Misc.ExportCustomer
{
    public class AdminAreaRegistration : AreaRegistration
    {
        public override string AreaName
        {
            get { return "Admin"; }
        }

        public override void RegisterArea(AreaRegistrationContext context)
        {
            var pluginFinder = EngineContext.Current.Resolve<IPluginFinder>();

            if (pluginFinder != null)
            {
                var pluginDescriptor = pluginFinder.GetPluginDescriptorBySystemName("Misc.ExportCustomer");
                if (pluginDescriptor != null)
                {
                    context.MapRoute(
                        "export_customer",
                        "Admin/Customer/ExportExcelAll",
                        new { controller = "CustomCustomer", action = "ExportExcelAll", area = "Admin" },
                        new[] { "Misc.ExportCustomer.Controllers" });
                }
            }
        }
    }
}


this is how I register it to override the ExportExcelAll action. Actually it is working, but sometime when I restart the application to load the update to the latest library files. It doesn't override the ExportExcelAll action, to resolve it I need to restart the application again, sometime few times.

What I concern is, as myself know that the library files is loaded properly, but customer don't. So I want to make sure the action is overrided 100% at all time.


There's already an area named "Admin" registered by nopCommerce and now you're registering the same area with a different route in a different AreaRegistration class. Your area will only be used if it is registered before the nopCommerce's default "Admin" area because the default "Admin" area has a route that matches the route of your area which will always be used if it is registered earlier. However, ASP.NET MVC doesn't guarantee the order of the areas being registered because it is assuming all areas to have very distinct routes that would not overlap each other. So sometimes, if you're lucky, your area is registered first and it is used, at other times, the default "Admin" area is registered first and your area wouldn't be used. Since the area registration code is in the Application_Start of global.asax, areas are registered once per application cycle. That explains why you need to restart your application in order for it to re-register hoping that your area would be registered first this time.

Registration of areas is just simply adding routes into the RouteTable.Routes collection. After the RouteTable.Routes has been built, ASP.NET MVC will use this lookup table to match routing for the rest of the lifetime of the application. Routes registered earlier will be at the top of the RouteTable.Routes thus having more precedence. Therefore your aim is to register the route as early as possible or at least earlier than nopCommerce's default "Admin" area route. However, as mentioned previously, the order of the registration is out of our control so what you can do when your area was registered later, is to move your route to the top of the lookup table:


var pluginDescriptor = pluginFinder.GetPluginDescriptorBySystemName("Misc.ExportCustomer");
if (pluginDescriptor != null)
{
    var route = context.MapRoute(
        "export_customer",
        "Admin/Customer/ExportExcelAll",
        new { controller = "CustomCustomer", action = "ExportExcelAll", area = "Admin" },
        new[] { "Misc.ExportCustomer.Controllers" });

    context.Routes.Remove(route); //remove your current route
    context.Routes.Insert(0, route); //move your route to the top of the lookup table
}


This should do the trick. This will move your route to the top of RouteTable.Routes if your area is registered later and doesn't do anything if it is registered earlier.

I personally prefer to do this in the IRouteProvider since it's sharing the same RouteTable.Routes with areas.
9 years ago
jason2k wrote:
Does anybody facing this issues? I am trying to override admin controller with plugin, but then sometime the system doesn't override it, but after few restart it will work again. Is there any way to load it after restart application at one time only?

Any sample codes of how you are wiring things up? Without sample codes we can't comment much... :)


using Nop.Core.Infrastructure;
using Nop.Core.Plugins;
using System.Web.Mvc;
namespace Misc.ExportCustomer
{
    public class AdminAreaRegistration : AreaRegistration
    {
        public override string AreaName
        {
            get { return "Admin"; }
        }

        public override void RegisterArea(AreaRegistrationContext context)
        {
            var pluginFinder = EngineContext.Current.Resolve<IPluginFinder>();

            if (pluginFinder != null)
            {
                var pluginDescriptor = pluginFinder.GetPluginDescriptorBySystemName("Misc.ExportCustomer");
                if (pluginDescriptor != null)
                {
                    context.MapRoute(
                        "export_customer",
                        "Admin/Customer/ExportExcelAll",
                        new { controller = "CustomCustomer", action = "ExportExcelAll", area = "Admin" },
                        new[] { "Misc.ExportCustomer.Controllers" });
                }
            }
        }
    }
}


this is how I register it to override the ExportExcelAll action. Actually it is working, but sometime when I restart the application to load the update to the latest library files. It doesn't override the ExportExcelAll action, to resolve it I need to restart the application again, sometime few times.

What I concern is, as myself know that the library files is loaded properly, but customer don't. So I want to make sure the action is overrided 100% at all time.

There's already an area named "Admin" registered by nopCommerce and now you're registering the same area with a different route in a different AreaRegistration class. Your area will only be used if it is registered before the nopCommerce's default "Admin" area because the default "Admin" area has a route that matches the route of your area which will always be used if it is registered earlier. However, ASP.NET MVC doesn't guarantee the order of the areas being registered because it is assuming all areas to have very distinct routes that would not overlap each other. So sometimes, if you're lucky, your area is registered first and it is used, at other times, the default "Admin" area is registered first and your area wouldn't be used. Since the area registration code is in the Application_Start of global.asax, areas are registered once per application cycle. That explains why you need to restart your application in order for it to re-register hoping that your area would be registered first this time.

Registration of areas is just simply adding routes into the RouteTable.Routes collection. After the RouteTable.Routes has been built, ASP.NET MVC will use this lookup table to match routing for the rest of the lifetime of the application. Routes registered earlier will be at the top of the RouteTable.Routes thus having more precedence. Therefore your aim is to register the route as early as possible or at least earlier than nopCommerce's default "Admin" area route. However, as mentioned previously, the order of the registration is out of our control so what you can do when your area was registered later, is to move your route to the top of the lookup table:


var pluginDescriptor = pluginFinder.GetPluginDescriptorBySystemName("Misc.ExportCustomer");
if (pluginDescriptor != null)
{
    var route = context.MapRoute(
        "export_customer",
        "Admin/Customer/ExportExcelAll",
        new { controller = "CustomCustomer", action = "ExportExcelAll", area = "Admin" },
        new[] { "Misc.ExportCustomer.Controllers" });

    context.Routes.Remove(route); //remove your current route
    context.Routes.Insert(0, route); //move your route to the top of the lookup table
}


This should do the trick. This will move your route to the top of RouteTable.Routes if your area is registered later and doesn't do anything if it is registered earlier.

I personally prefer to do this in the IRouteProvider since it's sharing the same RouteTable.Routes with areas.


Thanks jason2k

I have enhance the method that wooncherk mention at previous post, although I need to code more for some situations, but the system 100% loaded the custom and it hit my conditions.

May be next time I will try your methods. anyway thanks
This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.