Feeds:
Posts
Comments

Last month I posted about separating actions into their own classes.  Recently, I got a chance to try this concept out on a small project.  The results, so far, have been promising.  Here is a sample action controller:

public class EmployeeIndexAction() : ActionController
{
    private readonly IRepository<Employee> m_employeeRepository;
 
    public AlbumIndex(IRepository<Employee> employeeRepository)
    {
        m_employeeRepository= employeeRepository;
    }
 
    public ActionResult Get()
    {
        var employees = m_employeeRepository.FindAll();
        return View(employees);
    }
}

The conventions that we are using for the action controllers are:

  • Create one ActionController class for each unique URL (controller and action).
  • Name the class using a combination of the controller name and action name with a suffix of “Action” or more succinctly {controller}{action}Action.
  • Create a method for each Http Verb (Get, Post, Put …) that is supported for the URL.

The next code example illustrates a typical edit scenario.  It also shows that the action controllers still have support for binding parameters.  The URL for this example is ~/employee/edit.

public class EmployeeEditAction : ActionController
{   
    public ActionResult Get(int id)
    {
        EmployeeForm form = new EmployeeForm();
        // code to load employee and map to a EmployeeForm instance
        return View(form);
    }
   
    public ActionResult Post(EmployeeForm form)
    {
        if (!ModelState.IsValid)
        {
            return View(form);
        }
       
        // code to map and save employee
       
        return RedirectToAction("Index");
    }
}

I created a sample application that uses action controllers.  You can download the application at http://mscarman.googlecode.com/files/SampleSite.zip.

Jeffrey Palermo also posted about this subject last month.  If you haven’t seen his post, check it out.  His approach is a little different. But the general idea is the same and the comments are very informative as well.

On my current project, we are applying the Open Close Principle in our architecture.  Some of inspiration for this came from Ayende’s post Composite Architecture – The Open Close Principle as applied to system architecture.  In part of his post, he writes about how each new feature was implemented with new code and didn’t require touching existing code.

Applying this principal to our project has been working out very well.  For example, we are using the specification pattern with our repositories.  As a result we no longer need to add new methods to our repositories every time a new requirement comes along where we need to apply a different criteria.  We are having similar successes in other parts of our project.

One area where we haven’t been as successful is with our controllers.  When adding new features, there were many instances where we needed to add methods to existing controllers.  At times, these new methods would also add new dependencies to the controller.  Basically, the source for our controllers is not closed for changes.

As an alternative, we started looking at mapping each URL or action to a ControllerAction class.  For example, the URL /register/form would map to the RegisterFormAction class.  By default, action classes execute the method that matches the request type (GET, POST, PUT, etc …).  So if the request is a GET request, then the Get method is executed.  If there are any parameters for the Get method, they are mapped to the values passed in the query string.  The following is code for a sample action.

// url: ~/register/form
public class RegisterFormAction : ControllerAction
{
    private readonly IRepository<Class> m_classRepository;
    public RegisterFormAction(IRepository<Class> classRepository)
    {
        m_classRepository = classRepository;
    }
    public ActionResult Get()
    {
        var model = new RegistrationForm();
        return ShowForm(model);
    }
    public ActionResult Post(RegistrationForm model)
    {
        if (!ModelState.IsValid)
        {
            return ShowForm(model);
        }
        // TODO: map and save registration 
        // redirect to ~/registration/confirmation
        return RedirectToAction("Confirmation");
    }
    private ActionResult ShowForm(RegistrationModel model)
    {
        var filter = new ActiveClassFilter();
        model.Classes = m_classRepository.FetchFor(                                      filter,                                       OrderBy<Class>(c => c.ClassName));
        return View(model);
    }
}

We are still debating whether we want to go this route in our project. The debate typically centers around these two questions: Are we going to far in applying the Open Closed principal? Or, are we just afraid to break from the ASP.NET MVC convention of having controller classes?  I’m starting to lean towards the latter.

I also noticed the other people are looking in the same direction.  Recently, Chad Myers blogged about Going Controller-less in MVC: The Way Fowler Meant It To Be.  It’s always nice to know that other people are thinking the same way you are :)

If we decide to go this route, I add more posts detailing what we implement.  Until then, I love to know what other people think.

Follow

Get every new post delivered to your Inbox.