Override a Controller Action

Topics: Customizing Orchard, Writing modules, Writing themes
May 19, 2011 at 9:25 AM

Hi all,

someone knows if one can override the action/controller of a module?

Let me explain:

I would like to override/rewrite the action Search of the Home controller in Orchard.Tags module to add some sorting functionalities that the module doesn't have.

Certainly I can do my custum stuff on the module itself but I don't want to edit the "core" functionalities, I'd prefer to do it in a theme or in a module.

Feasible?

May 19, 2011 at 10:55 AM

You can use the OrchardSuppressDependency attribute to, well, suppress dependencies. So you could suppress the Routes and Controller from Tags and implement your own. This is the only way to do it AFAIK.

May 19, 2011 at 11:43 AM

Sorry but maybe I don't understand... something like this:

namespace Custom.MyNameSpace
[OrchardSuppressDependency("Orchard.Tags.Controllers.HomeController")]
public class HomeController : Controller {
    //my controller implementation
}

Is it correct?

May 19, 2011 at 12:10 PM

Yes that should be exactly correct (I think!) - you'll have to implement routes as well of course.

May 19, 2011 at 3:07 PM

I've tried, but with no luck. Unfortunately I have to reference Orchard.Tags.Services and Orchard.Tags.ViewModels and I cannot because they are dynamically compiled.

I'm stuck.

May 19, 2011 at 3:12 PM

You can add a project reference to other Orchard modules.

May 19, 2011 at 5:16 PM
cd_ipertrade wrote:

Sorry but maybe I don't understand... something like this:

namespace Custom.MyNameSpace
[OrchardSuppressDependency("Orchard.Tags.Controllers.HomeController")]
public class HomeController : Controller {
    //my controller implementation
}

Is it correct?

This also works with drivers?

May 19, 2011 at 5:34 PM
Edited May 19, 2011 at 5:35 PM

And it works!

Thanks.

I don't know if it works whit drivers as well, but I think it could...

May 19, 2011 at 6:17 PM

You can suppress any dependency. Drivers are just a dependency. On the other hand you don't necessarily need to - you can have any number of drivers for a given content part, and you can use placement to hide the shapes you don't want.

Coordinator
May 19, 2011 at 6:54 PM

In this case I think it would have been a lot easier to override the route with a new one with higher priority, pointing to a new controller action.

May 20, 2011 at 5:33 AM

How is that done?

May 20, 2011 at 7:30 AM
randompete wrote:

You can suppress any dependency. Drivers are just a dependency. On the other hand you don't necessarily need to - you can have any number of drivers for a given content part, and you can use placement to hide the shapes you don't want.


But for the case i want to override a driver for the editor part, the SuppressDependency is a possible solution :D

May 20, 2011 at 7:36 AM

I would expect you would like to do something like this. 

public class Routes : IRouteProvider
    {
        public const string Admin = "Module.Admin_List";
        public const string Config = "Module.Config_Index";
        public const string Countries = "Module.Countries_Index";

        public IEnumerable<RouteDescriptor> GetRoutes()
        {
            return new RouteDescriptor[]{
                   new RouteDescriptor {
                    Name= Config,
                    Priority=13,
                    Route = new Route(
                        "Admin/Module/{controller}",
                        new RouteValueDictionary{
                            {"area", "Module"},
                            {"controller","MyController"},
                            {"action","Index"},
                            
                        },
                        new RouteValueDictionary{
                        },
                        new RouteValueDictionary{
                            {"area","Module"}
                        },
                        new MvcRouteHandler())
                   }
                   
            };

        }

        public void GetRoutes(ICollection<RouteDescriptor> routes)
        {
            foreach (var route in GetRoutes())
            {
                routes.Add(route);
            }
        }
    }

Set the priority as high as you have to in order to make ASP.NET Routing choose this route instead of the default one.

Aug 30, 2011 at 7:25 AM

can i  include Routes.cs    in a themes ?

Coordinator
Aug 30, 2011 at 7:28 AM

Can't see why not. Yes, sure. You just need to have a csproj in the theme, and to have it include that.

Aug 30, 2011 at 7:34 AM
Edited Aug 30, 2011 at 7:35 AM

it works,thanks

Nov 25, 2011 at 11:59 AM

We are trying to overriding the controller Orchard.Core.Containers.Controllers.ItemController, but with no luck. We had used [OrchardSuppressDependency("Orchard.Core.Containers.Controllers.ItemController")]

 

Any idea What we are doing worng?

 

Thanks in advance

Nov 25, 2011 at 12:08 PM

Should work, I've seen controllers suppressed successfully elsewhere. Your module might need a dependency on the Containers module (although I don't think it should).

Just to note, the ItemController is being changed in 1.4 to use a driver so it's more customisable. What are you trying to change in it?

Nov 25, 2011 at 12:21 PM

Thanks Pete,

What we are trying to change the tree of shapes generated for the List's from our costum Theme.

we have created a ItemController.cs file at Ourtheme/views/controllers/

Here it goes a resumé of the code:

[OrchardSuppressDependency("Orchard.Core.Containers.Controllers.ItemController")]

    public class ItemController : Controller
    {
        private readonly IContentManager _contentManager;
        private readonly IContainersPathConstraint _containersPathConstraint;
        private readonly ISiteService _siteService;
        private readonly IFeedManager _feedManager;
 
        public ItemController(
            IContentManager contentManager,
            IContainersPathConstraint containersPathConstraint,
            IShapeFactory shapeFactory,
            ISiteService siteService,
            IFeedManager feedManager)
        {
 
            _contentManager = contentManager;
            _containersPathConstraint = containersPathConstraint;
            _siteService = siteService;
            _feedManager = feedManager;
            Shape = shapeFactory;
        }
 
        dynamic Shape { get; set; }
 
        [Themed]
        public ActionResult Display(string path, PagerParameters pagerParameters)
        {

             ....

        }

Whats happening is that the Display method is never called, and it stiil being used the original ItemController.

Any ideas?

 

Nov 25, 2011 at 12:37 PM

The problem could come from the fact that it's in a theme. Themes *are* modules, but they work slightly differently in some regards, especially if they don't have a .csproj. Try building a custom module to add this code.

Also, have you remembered to also suppress and override routing? Otherwise your controller will be on a completely different path to the container ItemController. By default any action will be on the path ~/ModuleName/ControllerName/ActionName - unless you specify custom routing with an IRouteProvider.

Nov 25, 2011 at 12:43 PM

Oh, I also notice you said the controller is in Ourtheme/views/controllers - controllers should never be under the views folder, otherwise they won't work at all. Should just be Ourtheme/controllers.

May 23, 2012 at 4:48 AM
bertrandleroy wrote:

In this case I think it would have been a lot easier to override the route with a new one with higher priority, pointing to a new controller action.

Hi Bertrand,

Could you expand on any rule of thumb as to when you would recommend overriding the route and replacing the controller action vs using OrchardSuppressDependency?

Thanks

Sean

Coordinator
May 26, 2012 at 6:44 AM

suppressing the existing dependency won't help you at all: the existing route will still be resolved to the old action. So I would never use OrchardSuppressDependency to replace a route. It just won't work. I think.

Jan 9, 2014 at 7:23 PM
Edited Jan 9, 2014 at 7:24 PM
I set up my routes
                new HttpRouteDescriptor {
                    Name = "OverloadedMediaLibrary",
                    Priority = 0,
                    RouteTemplate = "Admin/Orchard.MediaLibrary/Folder/{action}",
                    Defaults = new {
                        area = "MyArea",
                        controller = "FolderController",
                        action = "Create",
                    },
                },
and added the suppression attribute to my version of the controller:
[OrchardSuppressDependency("Orchard.MediaLibrary.Controllers.FolderController")]
However, the page always shows the following:

{"Message":"No HTTP resource was found that matches the request URI 'http://.../Admin/Orchard.MediaLibrary/Folder/Create?folderPath='.","MessageDetail":"No controller was selected to handle this request."}

The other routes in that route.cs file are working, so I know they are being applied.

Any ideas? Noob error?