5

When building complex applications the controllers can start to get unwieldy and very large, which may mean that you split them out into separate controllers. This may not be suitable as it will be reflected in the users experience. Ie. They will see the controller name in the URI.

For example: The default project that ships with MVC has an AccountController, that has actions for login, logoff, register etc.. which seems to violate the Single Responsibility Principle.

So the question is how to resolve this problem and separate out the concerns? An initial response could be just to create separate controllers. Ie.

AccountLoginController

AccountRegisterController

But this would not be a great experience from a customers point of view as it would effect the URI when requesting the resource.

A solution could be to have separate folders for each controller which contains separate class files for the action, each one with a single responsibility like so.

Controllers (folder)
    Account  (folder)
        Register.cs
        Login.cs
        Logout.cs
    AnotherController (folder)
        Actionfile.cs
        Actionfile.cs

The above would separate out the functionality and be highly cohesive.

So, this is a long explanation, but my questions are..

  • Has anyone implemented this before?

  • If so how do you go about it?

  • What are your thoughts regarding this pattern?

2
  • 1
    Why the emphasis on URIs? Most (99%+) users aren't going to care about anything after the ".com". Why's it matter if it's /Account/Register or /AccountRegister? I find it hilarious that .net devs didn't give a shit about URIs until every MVC tutorial put routes as step 1. Have you ever been to ebay or Amazon? Those URIs are horrid, but they're still successful sites. You know why? Because they care about user experience. I'd spend my time worrying about the user experience on the actual site (functionality, layout, menu navigation, etc) than what the user sees in the address bar. /rant Commented Oct 11, 2010 at 15:23
  • 4
    @Ryan I don't se how your comment is meant to contribute? Stating that .net devs "...didn't give a shit about URI's until..." is only an speculative opinion and not really true. Furthermore, the question does not empasize URI's but is rather a question about separation of concerns, SRP and cohesion with regards to the conventions set by the ASP.NET framework. Commented Apr 3, 2013 at 8:25

4 Answers 4

3

Did you look at Areas?

"Areas let you organize a large project into multiple smaller sections in order to manage the complexity of a large Web application. Each section (“area”) typically represents a separate section of a large Web site and is used to group related sets of controllers and views."

In a nutshell, an area is a folder in your project that has its own subfolders for controllers, models, and views.

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

Comments

2

It depends on what you mean by single responsibility.

If you mean Authentication as a responsibility, then the out of the box controller is perfect just the way it is. Logging in, Logging out and Registering are all part of the same thing - Authentication. So it makes sense that their code is in the same controller.

If you take the single responsibility principle to the ridiculous extreme, you would never have more than single classes with a single function in a single file.

You have to find a balance between readability/maintainability vs separation of concerns. In this case, it is going too far.

Also, remember that MVC is all about Convention over Configuration, meaning that if you name your controllers and views according to the convention, then they will be discoverable and you will have fewer configuration and routing issues.

Having said that, if you are determined to have a non-conventional Controller Naming convention, so to speak, you can implement your own Controller discovery code which would allow you to use a different convention. From the article linked to above:

public class ControllerConvention : TypeRules, ITypeScanner {
  public void Process(Type type, PluginGraph graph) {
     if (CanBeCast(typeof (IController), type)) {
     string name = type.Name.Replace("Controller", "").ToLower();
      graph.AddType(typeof(IController), type, name);
    }
  }
}

1 Comment

+1 - How cohesive and single responsibility you are is pretty subjective. IMHO the questioner is chasing a dream pattern when the current way ASP.NET MVC is organized out is pretty similar to every other MVC implementation out there. When you stray far off the path your either a genius or completely insane. Your call. ;)
0

Convention over configuration is pretty nifty for getting things stood up quickly, or for back-end apps where URIs don't matter in a long term sense. But for any public facing site I've done on MVC there has been zero published convention-based routes for a few reasons:

  • Your urls are your API. You should control them and know what your are publishing where.
  • I'm a bit on the paranoid side and I don't like the possiblity of stuff leaking into my app through url skullduggery.

Custom routing also lets you do things like have /Foo go to both the FooFooController and the FooBarController depending on action. You can even take advantage of areas and not expose them to the public.

1 Comment

I understand your point of view but I have found with larger MVC projects, the opposite applies. The bigger they get, the more I appreciate the conventions as they help prevent mainatainability problems.
0

You make a good point, but I think the confusion here is what a controller really is. In a MVC pattern, your controller could be considered a namespace for a group of action methods.

Let's use .NET's "System" namespace as an example. "System.Data" and "System.Core" have two very different responsibilities, but are grouped under the "System" wrapper.

When accessing a controller's action you will typically use routing like {controller}/{action}.

The "Account" portion of "AccountController" maps to {controller}, and the methods within the "AccountController" map to {action}.

I would recommend that you build a class library to handle your business logic, and route your actions to this library. You could build your classes exactly as you've stated above, passing the routed values of your actions to the library and returning a model for your views.

Register.cs could be a static class that you would call from your action method in the AccountController.

For instance:

"/account/register" ->

Controller:

public class AccountController : Controller
{
     public ActionResult Register()
     {
         return View("Register", Register.RegisterUser());
     }
}

Controller Logic:

public static class Register
{
     public static RegisterModel RegisterUser()
     {
         // Handle application logic here and build your model
         return new RegisterModel() { PasswordLength = 12 };
     }
}

Model:

public class RegisterModel
{
    public int PasswordLength { get; set; }
}

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.