5 Reasons You Should Take a Closer Look at ASP.NET MVC

I’m an ASP.NET Web Forms fan…always have been since ASP.NET was first released.  But, I like to keep an open mind when it comes to new technologies and I decided to experiment with the new ASP.NET MVC framework that Microsoft just released so I knew how it could be used with consulting projects and for training my company provides.  I was so impressed with some of the things I could do that I’m now using ASP.NET MVC on a customer project and thought I’d share some of the things I really like about the framework.

Before moving on, I know what some of you are already thinking because I thought the same things: “I don’t need all that testing stuff promoted by MVC people!” or “That’s an overly complex framework for ‘letter of the law’ developers!” or “I can’t use all my familiar ASP.NET server controls!” or “I don’t care about absolute control over the HTML that’s output!”.  I can tell you that while I do believe in unit testing and use it in my ASP.NET Web Forms consulting projects (see my previous post on the subject), I’m far from a letter of the law type developer (opinionated for sure….but not annoyingly opinionated :-)) and don’t really need absolute control over HTML output in many cases.  However, there are several other reasons why I personally think you should look at ASP.NET MVC and see if it can benefit your projects at all. 

In this post I’m going to outline 5 things I really like about ASP.NET MVC and separation of concerns, unit testing, complete control over HTML, etc. aren’t going to be covered.  If you want those things you get them too so keep that in mind before yelling, “You didn’t mention testing Dan!”.  It’s up to you to create test projects or not and ASP.NET MVC provides a very testable framework if you want to leverage it.  Having said that, let’s get started with a few terms before jumping into the details:

  • Model: Represents data used in the application that's ultimately retrieved and manipulated using business rule and data access classes (you could/should have these classes in ASP.NET Web Forms as well)
  • View: Handles presenting data to the end user (Similar to an .aspx page in ASP.NET Web Forms)
  • Controller: Retrieves data from the Model and passes it to a View (somewhat analogous to a code-behind page in ASP.NET Web Forms…but quite a bit different in functionality)

Reason #1 – Automatic Mapping of Control Values to Object Properties

I don’t enjoy writing tedious code and am always coming up with ways to minimize and refactor where possible. One of the nicest features in the ASP.NET MVC framework is the built-in ability to automatically map control values to objects.  With ASP.NET Web Forms you find yourself doing the following quite often (although some controls when used with the <%# Bind %> expression can do some mapping too):

protected void btnSubmit_Click(object sender, EventArgs e)
{
    Person p = new Person();
    p.FirstName = FirstName.Text;
    p.LastName = LastName.Text;
    UpdatePerson(p);
}

This is a simple example that can quickly get more complex depending upon the number of controls in your forms.  ASP.NET MVC uses specialized objects called Controllers to serve up pages (called Views) and within a controller class you can write methods (called Actions).  Actions can capture the form data submitted by an end user and automatically map it to custom object properties without you having to write any mapping code as shown above.  For example, consider the following ASP.NET MVC controls defined with a View named EditCustomerProfile (only a portion of the view is shown for the sake of brevity).  To prove I’m not a letter of the law person you’ll see I went with a table here (yeah I know, divs would work too..wasn’t in a div mood today):

<table width="640" cellspacing="5">
    <tr>
        <td style="width:30%"><label for="Customer.FirstName">First Name:</label></td>
        <td style="width:70%">
            <%= Html.TextBox("Customer.FirstName", Model.Customer.FirstName)%>
            <%= Html.ValidationMessage("FirstName", "*")%>
        </td>
    </tr>
    <tr>
        <td><label for="Customer.LastName">Last Name:</label></td>
        <td>
            <%= Html.TextBox("Customer.LastName", Model.Customer.LastName) %>
            <%= Html.ValidationMessage("LastName", "*")%>
        </td>
    </tr>
    <tr>
        <td><label for="Customer.Company">Company:</label></td>
        <td>
            <%= Html.TextBox("Customer.Company", Model.Customer.Company)%>
            <%= Html.ValidationMessage("Company", "*")%>
        </td>
    </tr>
    <tr>
        <td><label for="Customer.Phone">Phone:</label></td>
        <td>
            <%= Html.TextBox("Customer.Phone", Model.Customer.Phone)%>
            <%= Html.ValidationMessage("Phone", "*")%>
        </td>
    </tr>
    <tr>
        <td colspan="2">
            <input type="submit" value="Update Profile" />&nbsp;&nbsp;                
            <span class="StatusMessage" style='color:<%= Model.StatusColor %>'><%=Model.StatusMessage %></span>
        </td>
    </tr>
</table>


The first thing you’ll notice is that controls are defined differently in ASP.NET MVC then they are in ASP.NET Web Forms.  That’s a topic for a later post so I’m not going to focus on controls here.  The “classic ASP” style <% tags gave me heartache at first but having built many Views now I actually like the simple syntax for defining controls (no more runat=”server”!).  But…I digress.  Take a look at the ID for each control and notice that they all have “Customer” prefixing the name (Customer.FirstName, Customer.LastName, Customer.Company, etc.).  This is all the mapping code you need.  The method (Action) that handles the posted data simply needs to define a type that has properties that map with the form fields and the mapping happens “automagically”.  You can even customize the mapping if desired or perform mapping using built-in controller methods such as UpdateModel(). 

Here’s what the EditCustomerProfile() method (Action) looks like that handles the posted data.  You can see that it accepts a Customer parameter named customer that will automatically receive the posted control values and update the appropriate values.  The parameter name is key here since that’s what makes the auto-mapping possible (recall that each control was prefixed with “Customer”…case doesn’t matter here).  There’s a lot more that could be said about this particular topic, but this should give you an idea of how the auto-mapping works.  A nice discussion of the different mapping options available in ASP.NET MVC (referred to as ModelBinders) can be found here. Potential issues that you should know about with regard to auto-mapping are also covered here.

[Authorize]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult EditCustomerProfile(Customer customer)
{
    try
    {
        if (customer.IsCustomerValid)
        {
            OperationStatus opStatus =_CustomerRepository.Update(customer);
if (opStatus.Status) { ViewData["Status"] = "true"; return View("EditCustomerForm", new CustomerViewModel(customer,"Navy","Your profile information was saved.")); } } } catch {
//Log } ViewData["Status"] = "false"; ModelState.AddModelErrors(customer.GetRuleViolations()); return View("EditCustomerForm", new CustomerViewModel(customer, "Red", "There was a problem updating your profile.")); }

Reason #2: Automatic Generation of Views

Views display the data given to them by Controllers as mentioned earlier.  If you have a strongly-typed object (such as Customer above) that you will be passing to a View, Visual Studio can automatically generate the View for you and even add the controls that map to the respective object properties that will be bound as well as validation controls (although you’ll have to write the code to actually do the validation).  When creating Views using the IDE you can use the following Add View window:

image

This saves a tremendous amount of time defining controls.  It also save times in mapping control IDs to object properties.  If you don’t like the default code that’s output you can change the templates or add new custom templates.  They’re located at C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\ItemTemplates\CSharp\Web\MVC\CodeTemplates by default.  For example, if you prefer tables for your forms you could tweak one of the template files such as Edit.tt as shown next:

        <fieldset>
            <legend>Fields</legend>
               <table style='width:100%;'>
<#
    foreach(KeyValuePair<string, string> property in properties) {
#>        
                    <tr>
                        <td style='width:30%'>
                            <label for='<#= property.Key #>"><#= property.Key #>:</label>
                        </td>
                        <td style='width:70%'>
                            <%= Html.TextBox('<#= property.Key #>", <#= property.Value #>) %>
                            <%= Html.ValidationMessage("<#= property.Key #>", "*") %>
                        </td>
                    </tr>
<#
    }
#>
                
                    <tr>
                        <td colspan="2">
                            <input type="submit" value="Save" />
                        </td>
                    </tr>
                </table>
        </fieldset>

    <% } %>

    <div>
        <%=Html.ActionLink("Back to List", "Index") %>
    </div>

Reason #3: UpdatePanel-Like AJAX Support - But on a Serious Diet

If you use AJAX in your applications and are fond of the UpdatePanel control in ASP.NET Web Forms (some like it…some hate it) you may be aware that it can transmit a lot of data during an asynchronous postback (ViewState, ControlState, etc.) if you’re not careful.  ASP.NET MVC has built-in AJAX support as well and is just as easy to use.  You can create forms that perform partial-page updates and you don’t even have to work hard to do it.  Here’s an example of using the AjaxHelper to do the equivalent of an UpdatePanel.
 

<% using (Ajax.BeginForm("EditCreditProfile", new AjaxOptions { UpdateTargetId = "CreditForm", OnSuccess = "onEditOfficeProfileSuccess" }))
   {
%>
    <div id="CreditForm">
        <% Html.RenderPartial("EditCreditForm",Model.CreditProfileViewModel); %>
    </div>
<% } %>


The Ajax.BeginForm() call says that when the form is submitted (the form controls are defined in an EditCreditForm View User Control) a Controller Action named EditCreditProfile should be called asynchronously.  When the call returns the div with an id of CreditForm will be updated automatically with the resulting data.  This sends significantly smaller payloads as compared to the UpdatePanel which is nice when you need that type of functionality. 

Built-in support for adding AJAX functionality to links is also available in ASP.NET MVC through the AjaxHelper.  Check out the ActionLink() method if you’re interested in hooking a link to an Action using AJAX techniques.

Reason #4: Integration with Other JavaScript Libraries such as jQuery

image I mentioned earlier that I don’t always care about having complete control over the exact HTML that is output as long as it’s valid.  However, I do care about the ID of the controls that are output because with ASP.NET Web Forms IDs are auto-generated depending upon the container control that they live in (ASP.NET 4.0 will give you more control over IDs though).  While there are certainly workarounds for this, it can be a bit painful at times especially working with controls nested in a GridView or User Control.  ASP.NET MVC gives you 100% control over the IDs that are output so using script libraries such as Prototype or jQuery are that much easier.  And, like ASP.NET Web Forms, you get jQuery intellisense if the proper documented script files are available.

Here’s a simple example of handling the AjaxHelper (shown earlier) object’s OnSuccess event to load and process JSON data using jQuery:

function onEditOfficeProfileSuccess()
{
    GetOfficeProfiles();
}

function GetOfficeProfiles()
{
    CallService('/Account/GetOfficeProfiles', { customerID: $('#CustomerID').val() }, GetOfficeProfilesComplete);
}

function GetOfficeProfilesComplete(json)
{
    var s = $().parseTemplate($('#OfficeProfilesTemplate').html(), json);
    $('#OfficeProfilesOutput').html(s);
}

function CallService(url, data, callback)
{
    $.ajax({
        url: url,
        cache: false,
        dataType: "json",
        data: data,
        success: callback
    });
}

Reason #5: Promotes Better Coding Practices and a Solid Application Architecture

I’ll admit that this final reason isn’t as sexy as the others, but it’s definitely a benefit especially to larger enterprises with a lot of applications to build and maintain.  ASP.NET MVC helps guide developers down the path of designing architecturally sound applications from the start.  Now, don’t get me wrong, you can build solid applications using Web Forms as well and I’ve built many that had Presentation, Business, Data and Model layers.  However, a lot of developers (at least based on what I hear in some of the training classes we run) still put a lot of code in the code-behind file of a Web Form.  That works, but isn’t very re-useable and definitely isn’t very testable.  ASP.NET MVC forces gently guides developers to build architecturally sound applications that separate presentation, business and data logic so that it’s more reusable (and testable).  That doesn’t mean that the code is good as every developer has different skills of course, but it helps when people start things off on the right foot. If you’ve tried both frameworks (WebForms and MVC) I’d love to hear your thoughts on this final reason. 

To Sum Up….

Microsoft is going to support both ASP.NET Web Forms and ASP.NET MVC so you can go with either framework and be fine down the road (until some new technology is invented of course).  Having had a chance to use both frameworks I can tell you that each has its own set of pros and cons.  Hopefully, this post has given you a few reasons to research the ASP.NET MVC framework more and take a closer look at what it offers.  I’ll still be using Web Forms on some projects but it’ll be harder for me to choose between the two frameworks now….I’m really liking the control that ASP.NET MVC gives you.

 

 

Logo

For more information about onsite, online and video training, mentoring and consulting solutions for .NET, SharePoint or Silverlight please visit http://www.thewahlingroup.com/.

comments powered by Disqus

16 Comments

  • Technically, the model is the view model, not the business model. MVC is a presentation layer pattern. Business rules should be in the business layer of a multi-tiered application architecture. For example, your repositories, or data access layer.

  • Here, here.

  • MatthewD,
    Agreed...when being "technical" about it. &nbsp;The target audience will likely be coming from Web Forms though and I wanted to boil it down to something that was quick to grasp.&nbsp;&nbsp;I'd argue a lot of people using Web Forms now aren't going to be famliar with the concept of View Model and throwing that in (along with controller, action, model and view)&nbsp;just makes it sound like ASP.NET MVC is overly complex especially since many of the samples out there rely on ViewData and don't have a true View Model.&nbsp; The goal of the post is to break people into MVC gently...they can decide how they want to treat the model.&nbsp; But, I'll update that particular line to be a little more specific about the model. :-)&nbsp; Thanks for commenting.

  • Very informative. Been meaning to try MVC for a while. You present compelling reasons to give it a try.

  • irocon,

    Thanks...glad you enjoyed it and found it useful. I won't pretend that there's no learning curve since there is, but I think you'll actually enjoy trying it out.

  • Why only 5? :-)

  • Dan,

    Could you comment on the following - I come from a webform background?

    Web forms has the concept of user controls. A page has multiple user controls. These user controls are also reusable. So I can have a page with multiple "parts" (user controls) that perform different functions. When working with MVC how should one approach this design?

    MVC, AFAIK, does not have the concept of ASP.Net state. How do I track information about the user for a given session? A simple example would be a user comes to a page to search for something. They visit another page. When they come back to the search page, the term they searched for previously is pre-populated. Since session is not available, would I store something like this in the database or use the Profile provider?

    Thanks,

    Andy

  • Very well written. Hope to try out few samples this week.

  • Koistya,

    I initially planned to make it a "top 10" type of thing but after 5 decided I'd had enough writing for the day. :-) If you have some cool ideas for another 5 I could potentially do a follow-up article..."5 More Reasons You Should Take a Closer Look at ASP.NET MVC".

  • Andy,

    Great questions. As far as user controls, you still have that option...View User Controls. I use them a lot and recommend them in much the same way as you're currently used to. They're especially handy with ASP.NET MVC when it comes to using the AjaxHelper to do partial-page postbacks. With MVC you can easily have multiple forms on a page each doing a partial-page postback of a View User Control if desired.

    As far as state, similar techniques can be used. For simple state such as IDs I rely on hiddens or cookies but for more complex stuff I rely on storing state in a Session object (also available in MVC) or a DB as you mention. ASP.NET MVC also has a way to pass data around between actions called TempData. Hope that helps.

    Dan

  • Hi Dan,

    Thanks for this. I have been looking into MVC, and these are some good reasons to take it up based on the view/controller side of things, I was wondering if you have any compelling reasons on the model/controller side?

    Cheers,
    Max.

  • Max,

    If you're already writing layered code with Web Forms then I think you'll find that the model/controller side of things is along the lines of what you're doing now. The controller will call out to business and data classes that return a model of the data and then pass it to the views. There's really nothing built-in there for doing that so it's more along the lines of Web Forms in my opinion. The one thing that I like (although it does mean writing more classes) it that you can make things very strongly-typed with regards to the controller/model if you're willing to write classes with simple properties. Otherwise, you can always return data using the ViewData["NameOfData"] option...I don't find myself using that as much though. But, if you're already doing that in Web Forms then it won't be something new. :-)

  • Great post, I would add testability to the reasons. unit testing web logic can significantly improve the quality of the code.

    Mo
    Typemock - http://www.typemock.com/

  • Thanks a lot for the info Justin and great post on automatic binding and security. I updated my post to mention that people should be aware of potential issues and added a link to your post.

  • Thanks, Dan, a very lucid article. I'm looking forward to reading more of your work.

    Undoubtedly a naive question : exactly where in your example is the public method :

    ActionResult EditCustomerProfile

    called from : a generic mapping facility inside the Model ?

    thanks, Bill

  • Bill W.,

    Glad you asked since I probably should've made that more clear. EditCustomerProfile is called when the form data is posted back to the server. When the form is generated the action attribute of the form tag specifies to call EditCustomerProfile and the posted data is then automatically mapped to the Customer object. Hope that helps.

Comments have been disabled for this content.