Organizing Legacy Pages Into Controllers, Actions and Views
I've been asked to refactor a number of run-of-the-mill ASP.NET pages to use ASP.NET MVC. Here is part of the application's file structure:
~/UserAccount/
/Login.aspx
/Register.aspx
/UpdateProfle.aspx
/UserProfile.aspx
The Login.aspx page has already been done, so I decide to look at it and use it as a template for refactoring the rest of the pages. I find a UserAccountController that has a Login action method with a corresponding Login.aspx view. This doesn't smell right.
First, the controller isn't a noun that describes the resource being acted upon. UserAccountController is a noun, but the resource the login form acts on is a user's session. I would have expected a SessionController or UserSessionController.
Second, there should be two action methods: one to show the login form to the user and a second to create a new session after the user submits the form. I'm curious how this controller works, with just one action method. The first line of the existing Login action method is my answer:
if (Request.HttpMethod == "POST" && Request.Form["loginPostAction"] == "true")
The action is doing double duty; it both shows the login form (for a GET request) and creates a new session (for a POST request). This isn't really any different than the "old" days of using Page.IsPostBack, and is something we shouldn't need to do anymore with routing and MVC. In fact, it's basically putting routing inside your controller, which is definitely a bad smell.
This brief experience got me thinking about how I should organize controllers and actions in general. I ended up with the following self-guidance:
- Controllers should be plural nouns that describe the type of resource being acted upon (users, sessions, projects, etc.)
- Action methods should be verbs that describe the action that the user is taking (view, edit, update, etc.)
- The names of views should match their corresponding action methods (view.aspx, edit.aspx, update.aspx, etc)
- The conventional action methods to use (and to be deviated from when appropriate) are:
- list; show a list of the resources
- view; show an individual resource
- add; show the form to add a new resource
- create; create the resource on submission of the add form
- edit; show the form to edit a resource
- update; update the resource on submission of the edit form
- remove; show a form to remove a resource (often unnecessary)
- delete; delete the resource on submission of the remove form
- The conventional routes to use (again, to be deviated from when appropriate) are:
- For everything other than the list action: {controller}/{action}/{id} or {controller}/{action} (for example, /users/view/1 or /users/add)
- For the list action: {controller} (for example, /users)
[ Yes, my self-guidance borrows heavily from my experiences with Ruby on Rails. But I don't like a couple of their choices because they either aren't verbs (in the case of new) or they describe the controller's action and not the user's (in the case of show). I have to admit that having both add and create, both edit and update, is another smell that isn't very good. I have some thoughts on this as well, coming soon. ]
Self-guidance in hand, here's how I would take the four pages mentioned at the top of this 'blog post and organize them into controllers, actions, and views:
Controllers
UsersController
Add action
Create action
Edit action
Update action
View action
SessionsController
Add action
Create action
Views
Users
Add.aspx view
Edit.aspx view
View.aspx view
Sessions
Add.aspx view
If you happen to read this 'blog post and you have another, different preference for organizing controllers, actions, and views, please leave a comment and share it. I'm very interested in other approaches.