ASP.NET MVC- Single Responsibility Principle and Tall Controllers

by Scott MIllett 11. February 2011 09:01

In order to keep my fat controllers thin I ensure that they are only concerned with a single responsibility, i.e. handling the coordination of my UI logic. To achieve this my controller delegates to other classes to actually perform tasks and retrieve data. However, even though I can keep my ActionResult methods thin and highly cohesive I can still end up with a very tall controller that is handling the coordination of too much UI logic. Let me show you what I mean.

I often see controllers like the class below:

public class CustomerController : Controller
{
    public ActionResult Details()
    {
        //....
    }

    public ActionResult Edit()
    {
        //....
    }

    [HttpPost]
    public ActionResult Edit(EditCustomerViewModel edit_customer_view_model)
    {
        //....
    }

    public ActionResult AddDeliveryAddress()
    {
        //....
    }

    [HttpPost]
    public ActionResult AddDeliveryAddress(AddCustomerAddressViewModel add_customer_address_view_model)
    {
        //....
    }


    public ActionResult EditDeliveryAddress()
    {
        //....
    }

    [HttpPost]
    public ActionResult EditDeliveryAddress(EditCustomerAddressViewModel edit_customer_address_view_model)
    {
        //....
    }
}

This controller is concerned with everything to do with managing a customer, and even though it may have thin and cohesive ActionResult methods it can quickly become large and difficult to work with as it is handling too many UI tasks.

A better way I have found to tackle this issue is to create a controller class per business UI task or concern. So in the case of the tall controller shown above I would instead split this into multiple controllers, having one for editing a customer, one for displaying a customer and so on as shown in the following listing.

The CustomerDisplayController class is concerned with UI tasks to display a customer.

public class CustomerDisplayController : Controller
{
    public ActionResult Details()
    {
        //....
    }
}

The CustomerEditController class is concerned with UI tasks to edit a customer.

public class CustomerEditController : Controller
{
    public ActionResult Edit()
    {
        //....
    }

    [HttpPost]
    public ActionResult Edit(EditCustomerViewModel edit_customer_view_model)
    {
        //....
    }
}

The AddDeliveryAddressController class is concerned with UI tasks that add an address for a customer.

public class AddDeliveryAddressController : Controller
{
    public ActionResult AddDeliveryAddress()
    {
        //....
    }

    [HttpPost]
    public ActionResult AddDeliveryAddress(AddCustomerAddressViewModel add_customer_address_view_model)
    {
        //....
    }
}

The EditDeliveryAddressController class is concerned with UI tasks that edit a customers address.

public class EditDeliveryAddressController : Controller
{
    public ActionResult EditDeliveryAddress()
    {
        //....
    }

    [HttpPost]
    public ActionResult EditDeliveryAddress(EditCustomerAddressViewModel edit_customer_address_view_model)
    {
        //....
    }
}

You probably figured this out for yourself but I thought I may as well jot it down for future reference :0)

 

Keep on rockin
Scott

Tags: ,

ASP.NET MVC | Design Patterns

Comments (3) -

5/15/2011 1:23:05 PM #

Steven

Hmmm...I'm not convinced.  For me, this is an extremely ugly example and, in my opinion, you've completely misunderstood the point of MVC.  Having so many controllers and actions is completely the wrong way to attain SRP.

Steven United Kingdom |

5/16/2011 9:47:43 AM #

DickB

@Steven: do you care to elaborate a little bit about why you consider this a "misunderstanding" about the MVC-pattern?
I consider this post as organisational advice, I don't see any patterns breaking here.

DickB Belgium |

5/18/2011 12:53:33 PM #

Steven

@DickB:  I'll admit that ASP.NET MVC isn't a true MVC framework and, therefore, this article doesn't (can't) 'break' MVC principles.  However, as you will know, it is the controller's responsibility to determine what action should be taken, based on user interaction.  Having a separate controller for viewing, adding, editing, etc means that you move this responsibility to something else, such as routing. I'm sure you would find is absurd if it was taken one step further and a controller created for each GET and POST version of the action.

Furthermore, the purpose of the post was to ensure SRP.  If you regard the controller as an 'ActionResultFactory' then the responsibility of the controller is to simply instantiate the appropriate action, which the first version of the ('tall') controller adheres to.

Steven United Kingdom |

Pingbacks and trackbacks (2)+

Comments are closed

About Me

Hello my name is Scott Millett, this is my blog designed to capture my thoughts on development. You can find out more info on me by checking out my linked in profile below.

View Scott Millett's profile on LinkedIn

Coming soon...

Awards

MVP Logo

ASP.NET MVP
2010-2011

Month List

Powered by BlogEngine.NET 2.0.0.36 - Eco Theme by n3o Web Designers