ASP.NET MVC in the Real World
(
Jun 18 2008 - 09:32:09 PM by
Timothy Khouri) - [
print article]
MVC (the "model view control" pattern) isn't new, but it is new to ASP.NET. If you're like me, you may have been impressed by a demo, but you've probably thought "how does this work in the real world?" I hope to answer that question in this article.
All of the MVC demos that I have seen show how quick and easy it is to get going with ASP.NET MVC (from here on I'll just say "MVC"). They show a CSS'd up site with a navigation section, and a main content section. And in very little code, and very little time, they show how to retrieve data from your Model (the "Controller" does this), and how to display it in your page (the "View" does this). It look so simple, but there are some design questions that need to be addressed. We'll discuss them as we look into MVC.
MVC and Web Sites
The gist behind MVC is that a "View" is only responsible for displaying it's data, and nothing else. This means that if you had a View named 'UsedCars', it is only responsible for listing out used cars. There is no code for adding, deleting or updating the data in a View itself; there is no provision for displaying anything else other than "used car data".
So, MVC in a web application means that a View is not responsible for the navigation, header, footer or any other part of the site. With that being said, a few questions come to my mind. These are the items that this article will discuss as our 'real world' issues:
- How does MVC handle dynamic sections on a website that are not part of the current "View"? - For instance, on SingingEels.com, if you're logged in, the navigation section changes to include member's only links. When you're looking at an article, the "related section" on the right of the site will show you blog posts that are similar to the content you are looking at.
- How does MVC work with validating a user input, and displaying a friendly message back to the user on a screen that he expects to see? The reason I mention this is because in MVC, an HTML form on one View will be posting to an Action (a different URL) that actually does the work. This is different than in the "Web Forms" world, where the page posts-back to itself. So if the user entered some invalid data, how do you send them back to the original View, fill out the form back to how they had it, and display the error message?
Aside from these "issues" above, we'll see how to achieve common functionality (that we all do every day in the "Web Forms" world). These include things like creating paging functionality (I won't explain this in the article, but it's in the source code at the end). So, to demonstrate how to build a "full featured" MVC site that needs to solve the above issues, we're going to build a 'used cars' website. There will be a list of cars for sale (that will be paginated), displaying results from a database. We'll also have a few static pages and a "contact us" form. I'll include the entire source code and project at the end of the article. Keep in mind, this article and demo was written for ASP.NET MVC Preview 3.
Building Our MVC Layout with MVC Master Pages
The MVC design pattern was not originally for web applications, so extending this architectural pattern to the web allows for some breathing room. This is where we will answer our first question: "how do we handle dynamic sections in our web site that isn't part of a particular View?" Well, the answer is the same for how we handle our entire web site (the layout and styling of it) outside of any one particular View - with Master Pages!
So the first thing we are going to do with our MVC "Used Cars" website, is to create our basic layout and styles, and make a 'stub' for our Views to live in (basically, a ContentPlaceHolder). Here's what our site will look like:
Now, there are a few new tricks that we get with ASP.NET MVC (yes, I used the whole name here - for a purpose). The .NET team has provided a lot of powerful "helper functions" that snap right into the MVC framework. So, to make the navigation links above, I would normally have done this:
<a href="/Home">Home</a>
<a href="/ForSale">For Sale</a>
<a href="/About">About Us</a>
... But the problem here is that we are making links to "pages" instead of making links to "MVC Views". This forces our file structure to be very tied to our web design, which may not be what you're going for. Instead we'll do this:
<%= Html.ActionLink("Home", "Index")%>
<%= Html.ActionLink("For Sale", "ForSale")%>
<%= Html.ActionLink("About Us", "About")%>
This allows us to define our links in terms of pointing to a 'View', as apposed to being tied to a specific URL. You don't have to build your links this way, but it helps if you decide to change your route logic and you want your site to automatically update the links. Since we have our basic layout done, let's take a look at how these pages work.
Simple ASP.NET MVC Views
For simple Views that don't have a lot of logic around them, you don't have to do much in your controller. So for the home page and the about us page, this is basically all of the code in my controller:
public ActionResult About()
{
this.ViewData["Title"] = "About Page";
this.ViewData["PageHeading"] = "Learn All About Us";
return this.View();
}
public ActionResult Index()
{
this.ViewData["Title"] = "Home Page";
this.ViewData["PageHeading"] = "Welcome to Used Cars by Eels!";
return this.View();
}
Then, in our View, we can display the data. Normally this would go in the 'aspx' or 'ascx' files, but I'm displaying the above data in the master page (since the title of the page, and the page heading could be considered part of the standard layout). Again, you can download the source code for this project at the end of the article to see for yourself.
Real-World MVC Issue : Data Validation
So, let's get out of the boring, and talk about the other big problem that needs to be solved - form validation. When a user fills out our contact us form, we want to check for required fields and alert the user when the form is invalid. If all goes well, we'll send the user to a "Thank You" page.
Here's what our page will ultimately look like:
But the question remains: how do we do it? First, we build our HTML form using the helper methods:
<form action="<%= this.Url.Action("SendContact", "Home") %>" method="post">
First Name <%=this.Html.TextBox("FirstName", Request["FirstName"]) %>
Last Name <%=this.Html.TextBox("LastName", Request["LastName"]) %>
</form>
Update: Jun 21 2008You can also build forms by using the following helper method:
<% using (this.Html.Form("SendContact", "Home")) { %>
<% } %>
Then, in our Controller we will do the validation:
List<string> errors = new List<string>();
if (string.IsNullOrEmpty(firstName))
errors.Add("First Name is a required field.");
if (string.IsNullOrEmpty(lastName))
errors.Add("Last Name is a required field.");
if (errors.Count > 0)
{
this.TempData["ErrorMessages"] = errors.ToArray();
return this.RedirectToAction("Contact", new
{
FirstName = firstName,
LastName = lastName,
EmailAddress = emailAddress,
Message = message
});
}
The last piece of the puzzle is back in the contact us View. It's where we check the TempData field to see if there are any error messages in there, and if so, we display them. There are a few things to be concerned about here with using the TempData though. Mainly, it's important to know that behind the scenes, MVC is using the Session object to store the data between hits. Now, it is very quick to clean it up (immediately after the next request)... but if you're using a web-farm, it's important to remember that you'll need a shared session pool.
In Conclusion
MVC is a beautiful new tool that will no doubt be invaluable in the future. It does require a different approach to architecting your web sites, but it can be very worth it in the end. However, it's also important to remember that MVC is not replacing Web Forms.
I hope this article has shown that you can still achieve the functionality that you're used to having using ASP.NET MVC. Check it out for yourself and see if you don't grow to love it (or at least appreciate it) as I have. And of course, here's the source code for the above project: SingingEels_MVC Used Cars Demo.zip. Again, it was written and compiled for ASP.NET MVC Preview 3.