Skip to content
This repository has been archived by the owner on Mar 20, 2018. It is now read-only.

Separate controllers for groups of actions #80

Open
danmalcolm opened this issue Mar 29, 2014 · 2 comments
Open

Separate controllers for groups of actions #80

danmalcolm opened this issue Mar 29, 2014 · 2 comments

Comments

@danmalcolm
Copy link
Contributor

Could the routing be extended to support using different controllers for certain groups of actions?

I prefer not to have all of a resource's actions on a single controller - a bit of SRP at controller level really helps if you want to factor out common functionality using inheritance and generics.

In other projects, I've tended to split controllers along the following lines:

  • UserListController - handles Index (and search etc)
  • UserEditController - handles New, Edit, Update, Create and Delete
  • UserDisplayController - handles Show

Restful Routing currently mandates a controller-per-resource structure, e.g. map.Resources(..).

I guess we'd need to extend the API along the following lines:

map.Resources("users", users=> 
{
  users.Controllers(
     Use<UserListController>().For("Index"),
     Use<UserEditController>().For("New", "Edit", "Update", "Create", "Delete")
  );
  ...
};

You get the idea....

I'll go and spike something, but thought I'd invite some thoughts from other first.

@khalidabuhakmeh
Copy link
Collaborator

Hello Dan,

First, let me thank you for taking an interest in Restful Routing, for that I am truly appreciative.

So looking at your idea I'm not sure it works with the core philosophy of Restful Routing. Our idea is to be convention based, and your approach would have users defining each and every route. This would make it difficult to use the library. Additionally, we have strong opinions in Restful Routing, and although we let you diverge from them it becomes increasingly painful to do so.

Instead of implementing a new interface, you could utilize features already present in Restful Routing. I'll list them below and show you how to use each one.

Connecting RouteSets

Restful Routing already allows you to separate out routes with RouteSets. Check out this link http://restfulrouting.com/routeset#connect.

public class Routes : RouteSet
{
    public override void Map(IMapper map)
    {
        map.DebugRoute("routedebug");
        map.Connect<One>();
        map.Connect<Two>();
        map.Connect<APIRoutes>("api", new string[] { "RestfulRouting.Controllers.API" });
    }
}

Path and Route

Like I mentioned above, Restful Routing lets you diverge from the Resource pattern and just register routes yourself. Check out this link. http://restfulrouting.com/mappings/extras

area.Resource<ExtrasController>(extras => {
    // Use path
    extras.Path("using_path").To<ExtrasController>(e => e.UsingPath()).GetOnly();
    // Using route
    extras.Route(new Route("mappings/extras/with_route",
        new RouteValueDictionary(new { controller = "extras", action = "usingroute", area="mappings" }),
        new MvcRouteHandler()));
});

Solution to your Granularity

Let me first state that I believe you are getting way too granular and taking SRP to the extreme, but I don't want to argue philosophy here, I want to get you a solution :)

What I would do is this, with a few tweaks here and there.

  1. Create a new kind of RouteSet: SrpRouteSet maybe?
public class SrpRouteSet : RouteSet {    
      protected SrpRoutSet(string controllerPrefix) {}
}
  1. Create a convention in your code where a resource starts with the controller prefix.
  • UserListController
  • UserShowController
  • UserDestroyController
  1. Having a convention, you can then utilize the Path / Route feature in Restful Routing to register your routes appropriately.

As you can see above, you can already get to your solution without having to modify the core of Restful Routing, you can just extend it using some of the base classes and techniques already present.

Downsides

The thing I can't wrap my head around is how you would nest resources, it would become increasingly difficult to do so with every level you go. In Restful Routing we make a lot of assumptions to help you be productive. This approach would mean you have to re-develop those or throw them out the window.

The other major downside is you are going to see an explosion of controllers in your code. It might become increasingly difficult to manage that many controllers.

Anyways, I hope this response has helped and I am here to talk things out with you or help you if you want it :)

@danmalcolm
Copy link
Contributor Author

Taking SRP to the extreme? No way! ;) I know it's the out-of-the-box ASP.Net MVC and Rails way, but having a controller that manages listing / search and editing is a pretty bad SRP violation. If you have a lot of resources with similar list / filter, display and edit requirements you'll want to extract some common functionality somewhere, perhaps into a controller base class. This gets badly bloated if your controller is doing a lot of different things - you end up with about 7 generic type parameters and too many constructor parameters. I prefer to have a controller per logical "screen". If you were doing simple CRUD in a desktop app, you'd likely have separate screens and controllers for the list / search, details and edit screens.

Anyway, that's probably enough philosophy for now - I've got a draft blog post on the go about this exact topic. Perhaps we can have a discussion around some concrete examples when I publish it.

It was really good of you to spend some time making those detailed suggestions and providing background. I think I'd definitely be missing the point of Restful Routing (simplicity and conventions) if I insisted on setting it up that way though!

It's up to you whether you leave this open - it might be worth seeing what other users think. I might try a quick spike, just to see if it is viable to add support for separate controllers without making it too subtle and fiddly.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants