Not sure how many of you read my first post on my thoughts on Oxite. Well, here's my offering on trying to make things a little closer to MVC by offering my perspective on the code. Please note that I want to keep these simple refactorings as conversational as possible, so if you see something that offends or upsets you with my interpretation/implementation, PLEASE COMMENT. :)
Let's examine the SignIn action under the AccountController:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SignIn(string username, string password, bool rememberMe, string returnUrl)
{
PageTitle.AdditionalPageTitleSegments = new string[] { "Sign In" };
if (string.IsNullOrEmpty(username))
ModelState.AddModelError("username", "You must specify a username.");
if (string.IsNullOrEmpty(password))
ModelState.AddModelError("password", "You must specify a password.");
if (ViewData.ModelState.IsValid)
{
IUser user = MembershipRepository.GetUser(username, password);
if (user != null)
{
FormsAuth.SetAuthCookie(username, rememberMe);
if (!string.IsNullOrEmpty(returnUrl) && returnUrl.StartsWith("/"))
return Redirect(returnUrl);
else
return RedirectToRoute("Home");
}
else
{
ModelState.AddModelError("_FORM", "The username or password provided is incorrect.");
}
}
ViewData["rememberMe"] = rememberMe;
return View();
}
As you can see from here, there is a lot of code within this method that makes it hard to follow/maintain since everything is put jammed together in the body of the action. Here are some things that we can see immediately:
- Form Data Validation
- Model Validation
- Route Processing
Essentially, the controller is performing both control logic as well as domain/business logic, which clearly shows that it is violating the Single Responsibility Principal (SRP) and its Separation of Concerns (SoC).
The question here is How do we address these issues? Well, first by taking the a look at the pieces that make up the code and putting them in their correct "location". To not get overwhelmed, let's first focus on Form Data Validation.
Now, let me first start by saying that Views and Models can be one of the hardest things to grok if you're new to the MV* patterns. Why? Well, as developers we sometimes take things too literal which makes things even worse. So when we hear the words, View and Model we think that there's nothing in between. Sigh...
So let's start by saying that a View is a representation (or snapshot) of the data that is contained by your Model. Your Model is the representation of the real-world scenario your application is trying to capture. Now, the ViewModel is a transformation/projection of the data captured from the View that adhere's to what is expected by the Model. As you can see, each piece handles JUST one thing. It shouldn't care what other pieces are doing
Having said that, let's focus on the concept of User Sign In within your application. First, I will define that the pieces as follows:
- View - the login screen - text boxes to capture username, password, etc.
- ViewModel - a CredentialViewModel class - this represents the data from the view so it can be transformed/projected to the Model.
- Model - a User class - this represents a real-world user in the system
Pretty straight forward, right? It's about capture, projection and verification. In my next post, we'll examine how we can refactor the action method and it's parameters into something that's easier to consume and understand.
Keep coding!