0

While creating a Plugin for a MVC site, I'm facing an issue about controller resolution.

Here are all the routes that concern the current context :

routes.MapRoute("Route1",
    "Admin/Product/{action}/{id}",
    new { controller = "Product", action = "Index", area = "Admin", id = UrlParameter.Optional },
    new[] { "Plugin.Controllers" }
)

routes.MapRoute(
    "Admin_default",
    "Admin/{controller}/{action}/{id}",
    new { controller = "Home", action = "Index", area = "Admin", id = "" },
    new[] { "Admin.Controllers" }
);

routes.MapRoute(
    "Default", // Route name
    "{controller}/{action}/{id}", // URL with parameters
    new { controller = "Home", action = "Index", id = UrlParameter.Optional },
    new[] { "Public.Controllers" }
);

There are 3 ProductController classes in the entire solution :

  • Plugin.Controllers.ProductController (inherits from the Admin one)
  • Admin.Controllers.ProductController
  • Public.Controllers.ProductController

In my view "/Views/Home/Index.cshtml" (i.e. the "Index" action of the HomeController without any area) I have the following code :

@Html.Action("HomepageProducts", "Product")

It refers to the action "HomepageProducts" of the Public.Controllers.ProductController.

MVC looks for the plugin controller instead of the public one and throws the following exception :

[HttpException (0x80004005): A public action method 'HomepageProducts' was not found on controller 'Plugin.Controllers.ProductController'.] System.Web.Mvc.Controller.HandleUnknownAction(String actionName) +291 System.Web.Mvc.Controller.b__1d(IAsyncResult asyncResult, ExecuteCoreState innerState) +31 System.Web.Mvc.Async.WrappedAsyncVoid1.CallEndDelegate(IAsyncResult asyncResult) +29 System.Web.Mvc.Async.WrappedAsyncResultBase1.End() +49 System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +36 System.Web.Mvc.Controller.b__15(IAsyncResult asyncResult, Controller controller) +12 System.Web.Mvc.Async.WrappedAsyncVoid1.CallEndDelegate(IAsyncResult asyncResult) +22 System.Web.Mvc.Async.WrappedAsyncResultBase1.End() +49 System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +26 System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult) +10 System.Web.Mvc.MvcHandler.b__5(IAsyncResult asyncResult, ProcessRequestState innerState) +21 System.Web.Mvc.Async.WrappedAsyncVoid1.CallEndDelegate(IAsyncResult asyncResult) +29 System.Web.Mvc.Async.WrappedAsyncResultBase1.End() +49 System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +28 System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +9 System.Web.Mvc.<>c__DisplayClassa.b__9() +22 System.Web.Mvc.<>c__DisplayClass4.b__3() +10 System.Web.Mvc.ServerExecuteHttpHandlerWrapper.Wrap(Func`1 func) +27

[HttpException (0x80004005): Execution of the child request failed. Please examine the InnerException for more information.] System.Web.Mvc.ServerExecuteHttpHandlerWrapper.Wrap(Func`1 func) +102 System.Web.Mvc.ServerExecuteHttpHandlerWrapper.Wrap(Action action) +64 System.Web.Mvc.ServerExecuteHttpHandlerAsyncWrapper.EndProcessRequest(IAsyncResult result) +71 System.Web.HttpServerUtility.ExecuteInternal(IHttpHandler handler, TextWriter writer, Boolean preserveForm, Boolean setPreviousPage, VirtualPath path, VirtualPath filePath, String physPath, Exception error, String queryStringOverride) +1436

[HttpException (0x80004005): Erreur d'exécution de la demande enfant pour le gestionnaire 'System.Web.Mvc.HttpHandlerUtil+ServerExecuteHttpHandlerAsyncWrapper'.] System.Web.HttpServerUtility.ExecuteInternal(IHttpHandler handler, TextWriter writer, Boolean preserveForm, Boolean setPreviousPage, VirtualPath path, VirtualPath filePath, String physPath, Exception error, String queryStringOverride) +3428452 System.Web.HttpServerUtility.Execute(IHttpHandler handler, TextWriter writer, Boolean preserveForm, Boolean setPreviousPage) +76 System.Web.HttpServerUtility.Execute(IHttpHandler handler, TextWriter writer, Boolean preserveForm) +29 System.Web.HttpServerUtilityWrapper.Execute(IHttpHandler handler, TextWriter writer, Boolean preserveForm) +24 System.Web.Mvc.Html.ChildActionExtensions.ActionHelper(HtmlHelper htmlHelper, String actionName, String controllerName, RouteValueDictionary routeValues, TextWriter textWriter) +464 System.Web.Mvc.Html.ChildActionExtensions.Action(HtmlHelper htmlHelper, String actionName, String controllerName, RouteValueDictionary routeValues) +83 System.Web.Mvc.Html.ChildActionExtensions.Action(HtmlHelper htmlHelper, String actionName, String controllerName) +10 ASP._Page_Views_Home_Index_cshtml.Execute() in c:\Path\To\My\Project\Views\Home\Index.cshtml:14

If this helps, the solution use Autofac.MVC5... Any help/comment/idea is welcome.

Am I missing something or only the routes are implied in controllers resolution ?

UPDATE

When browsing the "Admin" area all actions are well performed, the plugin and the admin controllers works fine.

If I comment the plugin route, the error is not thrown anymore. Of course my plugin controller is not called anymore.

// routes.MapRoute("Route1",
//     "Admin/Product/{action}/{id}",
//     new { controller = "Product", action = "Index", area = "Admin", id = UrlParameter.Optional },
//     new[] { "Plugin.Controllers" }
// )

So I guess the issue is due to the plugin route, the plugin controller itself or the way the route is resolved by MVC ?

UPDATE 2

I tried to uncomment all my routes and specify area in @Html.Action() as follow:

@Html.Action("HomepageProducts", "Product", new { area = "" })

But MVC ignore the area and try to load the Plugin controller...

[HttpException (0x80004005): A public action method 'HomepageProducts' was not found on controller 'Plugin.Controllers.ProductController'.]

8
  • In your controller, Plugin.Controllers.ProductController.. do you have an ActionResult method named HomepageProducts that returns a View? Commented Oct 26, 2016 at 12:33
  • No I don't. Only the public one have this action Commented Oct 26, 2016 at 12:34
  • I would assume this is happening because in your Route.config, specifically for Route 1.. you're calling @Html.Action("HomepageProducts", "Product") which is going to the Product Controller, which matches the URL you provided in Route 1.. Commented Oct 26, 2016 at 12:53
  • I'm not sure to understand. The HomeController is a "public" one (not in an area) and the Html.Action() doesn't specify any "area". Why is MVC looking for a controller associated to an area route ? Commented Oct 26, 2016 at 13:05
  • Are you using Area for Admin? If so see stackoverflow.com/questions/7842293/… Commented Oct 26, 2016 at 18:49

1 Answer 1

0

I'm definitely sure I miss something but I bypass my issue by register each Plugin.ProductController action routes I've overridden from the Admin one.

routes.MapRoute("Route1",
    "Admin/Product/{action}/{id}",
    new { controller = "Product", action = "Index", area = "Admin", id = UrlParameter.Optional },
    new[] { "Plugin.Controllers" }
)

//...becomes...

routes.MapRoute("Product.Action1",
    "Admin/Product/Action1/{id}",
    new { controller = "Product", action = "Action1", area = "Admin", id = UrlParameter.Optional },
    new[] { "Plugin.Controllers" }
)

routes.MapRoute("Product.Action2",
    "Admin/Product/Action2/{id}",
    new { controller = "Product", action = "Action2", area = "Admin", id = UrlParameter.Optional },
    new[] { "Plugin.Controllers" }
)

//...

All works fine now. With this, I'm able to derive controllers.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.