ASPNETMVC 2 In Action by 7uckwj2s

VIEWS: 56 PAGES: 23

									ASP.NET MVC 2 in Action
Hot on the heels of the groundbreaking release of ASP.NET MVC
1.0, the ASP.NET MVC team at Microsoft has already released the
first Community Technology Preview (CTP) of version 2.
I have already predicted that Microsoft’s MVC Framework will
become the new way to develop web applications on top of
ASP.NET. In this article, I will give a first look at the plans for
version 2 and some of the features that already work in the first
CTP.

Microsoft is targeting the second release of the
ASP.NET MVC Framework for the enterprise
customer. The main two themes that Microsoft is
focusing on are:

      Improved productivity
      Enterprise ready

Some companies are already leveraging ASP.NET
MVC 1.0 on large systems. Others are slower to
adopt. At this time, Microsoft released MVC 1.0 only
about 6-8 and some more conservative clients are
still using Visual Studio 2005 for development. With
the pace of Microsoft’s releases, I believe we will see
a large number of companies who haven’t adopted
.NET 3.5 yet jump straight to .NET 4.0.

When Visual Studio 2010 releases, many companies
will feel the strong urge to upgrade development
platforms so that they aren’t left behind. It is not a
good place to be when you are two versions behind
current. If a large number of companies jump to
Visual Studio 2010, I think we’ll see a massive
retooling of these developers. Not only will they pick
up C# 4.0, but they will also have a choice between
Web Forms and MVC.

Most of these developers who are retooling will
choose ASP.NET MVC because of its refreshing
simplicity and also because of the massive
productivity enhancements over Web Forms. While
Web Forms continues to dominate the designer
experience, ASP.NET MVC marches on toward
enhanceed productivity in code, not in the designer.
This is one of its greatest strengths, and libraries like
MvcContrib add to the benefits of adoption.

This article is an introduction of ASP.NET MVC 2
using CTP 1. It assumes knowledge of version 1,
which you can gain by reading one of the several
books on the topic such as ASP.NET MVC in Action
by Manning: http://mvcbook.jeffreypalermo.com/.

Let me first discuss some of the plans for version 2
and then run through some examples that are
possible with the CTP 1 bits.
Version 2 Release Plan

Microsoft has a detailed roadmap on the CodePlex
site    that   they   keep    up   to    date   at
http://aspnet.codeplex.com. Their published theme
is to improve productivity and make the framework
enterprise ready. What that means is up to the
reader, but some of the major areas on which they
are working are:

      Templated helpers
      Areas
      Support for data annotations
      Client validation
      Asynchronous controller actions
      Fixing known issues

The first three have some working bits in the first
CTP, and I will look at that code in this article. First,
I’d like to give some commentary on the deployment
configuration and then the implications of each of
these major features and why you should or should
not care about them.

The CTP includes pretty good implementations of
template helpers as well as the data annotation and
model binder validation.



Dependencies and Runtime

ASP.NET MVC 2 will ship in the box with Visual
Studio 2010, but it will also be available as an add-in
for Visual Studio 2008 SP1. The server will require
.NET 3.5 SP1 minimum to run a version 2 Web
application.

It will also work seamlessly with MSDeploy for
deploying apps to IIS, file locations, FTP and more. If
you aren’t familiar with MSDeploy, think of it as the
.NET WAR file (from the Java space). It will allow you
to package up your ASP.NET MVC application in a
single zip file and deliver it to your production server
administrators. Then, your server administrators will
be able to unpack your deploy package and run an
installation routine you created on the production
server. Automated deployment packages are long
overdue, and MSDeploy is the ticket to not rolling
your own installation frameworks like many of us
have.                      Check                     out
http://blogs.msdn.com/webdevtools/archive/2009/0
3/10/how-does-web-deployment-with-vs10-and-
msdeploy-work.aspx for more info on MSDeploy
from Vishal Joshi.
The GuestBook Application

The following example code and figures are from a
combined sample that uses template helpers, the
new HttpPost attribute, the new DefaultValue
attribute, and DataAnnotation validation. Because
readers of my articles and books are typically tired of
trivial examples, this application is a fully separated
app. It leverages Onion Architecture and puts a small
domain model in the center. I’m using NHibernate
for the data access and one view model per view as
my dominant presentation pattern. I’m doing manual
mapping to and from my domain model to view
models, but in larger projects, I’d pull in the
AutoMapper library in a heartbeat.

I’ll start creating an ASP.NET MVC 2 project in Visual
Studio 2010. Figure 1 shows the default start page.




Figure 1: The Visual Studio 2010 Start Page.

You can see that it looks quite different from Visual
Studio 2008. VS 2010’s UI is almost completely WPF.
You can expect the next version of WPF to have
some needed enhancements because using it for
Visual Studio’s UI uncovered some serious limitations
in the framework.

I’ll select New Project and you can see a redesigned
New Project dialog box as shown in Figure 2.
Figure 2: A New Project in Visual Studio 2010.

In VS 2010, ASP.NET MVC 2 ships in the box as the
default version, so I will select it directly. Visual
Studio still enjoys multi-targeting and so if you select
.NET 3.5, you can still create an ASP.NET MVC 1.0
application.

Because there are a few annoying bugs in VS 2010, I
will use VS 2008 with ASP.NET MVC 2 CTP1 installed.



Application Overview

Now let me should you the domain:

       using System;
       using System.Drawing;

       namespace Core
       {
          public class Guest
          {
             public virtual Guid Id { get; set; }
             public virtual string FirstName { get; set;
       }
             public virtual string LastName { get; set; }
             public virtual KnownColor FavoriteColor {
       get; set; }
          }
       }

The domain is very simple and consists of a single
aggregate root, the Guest class. Some may argue
that this simple of a model is not a domain model,
but that isn’t important to this article. I am also
using the repository pattern for persistence. The
IGuestRepository interface looks like this:

       namespace Core
       {
          public interface IGuestRepository
          {
             void Save(Guest guest);
             Guest[] GetRecentGuests(int numberOfGuests);
          }
       }
The Core project owns the repository interface, and
the Infrastructure project implements the interface.
Data access is implemented in a decoupled way with
an NHibernate mapping as follows:

       <?xml version="1.0" encoding="utf-8" ?>
       <hibernate-mapping xmlns="urn:nhibernate-mapping-
       2.2"
                                  namespace="Core"
                                  assembly="Core">

          <class name="Guest" table="Guests"
                    dynamic-update="true">
             <id name="Id" column="Id" type="Guid">
                <generator class="guid.comb"/>
             </id>
             <property name="FirstName"/>
             <property name="LastName"/>
             <property name="FavoriteColor"/>
          </class>
       </hibernate-mapping>

From this point forward, I won’t dig into data access
because ASP.NET MVC is a presentation layer
framework and is completely agnostic to the method
of persistence. If you would like to examine the
entire application in great detail, you can download
the full source code for the article.

Before jumping into UI code, I am going to give you
a quick run through of how the application behaves.
First, if you go to the home page, you will see a list
of people who have signed the guest book. Figure 3
shows the two people who have signed in so far.




Figure 3: The display screen using template helpers.

I can also click the navigation to sign in to the
guestbook as shown in Figure 4.
Figure 4: The editor screen using template helpers.

Next, I’ll show you the code necessary to make this
possible. I’ll look at both the HomeController and the
GuestBookController. Each of these controllers are
almost as you would expect to see them with version
1.0 of ASP.NET MVC. Most of the enhancements I’ll
show you are additions that you can use within a
view model class and views.



Templated Helpers

THIS FEATURE IS THE MOST GROUNDBREAKING
ONE ON THE LIST! There! I got that off my chest.
Seriously, this, above all others, is the key to
developing applications with lightly speed. On top of
that, the views become very small because the
common html markup is in templates and is used
over and over. Combine template helpers with one
view model per view page, and this approach results
and an application with very small views and very
structured and consistent markup.

       Opinionated Input
       Builders
       Eric Hexter has written a 9-part
       series on what he calls
       Opinionated Input Builders.
       Different name but same concept.
       You can read it at
       http://www.lostechies.com/blogs/h
       ex/archive/2009/06/09/opinionate
       d-input-builders-for-asp-net-mvc-
       using-partials-part-i.aspx. The
       concept was harvested from a real
       project at Headspring Systems,
       and you can see an early version in
       the CodeCampServer source code
       at http://codecampserver.org. Eric
       has put a lot of work into these,
       and they will be part of MvcContrib
       very soon. I am very happy that a
       similar concept is part of the plan
       for ASP.NET MVC 2.
       Views typically have the most
       redundant code because html is
       not a structured programming
       language. Templated helpers add
       structured programming on top of
       common display and input
       elements. This allows a common
       occurrence such as. . .
       <label for=”firstname”>First
       Name:</label>
       <input type=”text”
       name=”firstname”/>
       . . to be encapsulated into a one-
       line call. It is, therefore, consistent
       across the entire site. When using
       CSS to style the site, it is often
       desirable to add CSS classes to all
       input types, and duplicated CSS
       styles can hamper maintainability
       just as much as duplicated code. If
       you need the full-fledged
       functionality now and just cannot
       wait, check out the work of Eric
       Hexter. Once Microsoft releases
       version 2 of ASP.NET MVC, Eric will
       surely be deleting lots of code that
       will no longer be necessary
       because it is within
       System.Web.Mvc.dll.

The template helpers come with support for display
pages as well as pages for form posting. I will cover
each of these independently.



Display Enhancements

Listing 1 shows the HomeController. This controller
uses the IGuestRepository for retrieving the most N
recent guests. You can see here that we are
leveraging the new DefaultValue attribute on the
Index action. If you don’t provide this parameter, the
default will be model-bound in as 10.

The rest of the action merely maps the domain
model into a view model that can be sent to the view
for rendering. You’ll see that view models are very
special classes, and for real applications, it is seldom
appropriate to send a domain model entity directly to
the view. Our view model class is GuestDto. This
view model is just for display purposes and has two
properties as shown in Listing 2.
You can also see that we’re mapping a Guest object
to a GuestDto, and that GuestDto is performing the
mapping work inside its constructor. If this
application gains a few more entities, I would quickly
introduce the AutoMapper library to handle object-
to-object mapping. Moving between domain model
and view models requires mapping each way, and
that code can become repetitive. AutoMapper
reduces that chore to convention-based configuration
and I highly recommend it. Jimmy Bogard manages
the AutoMapper open-source project.            Jimmy
harvested AutoMapper from several of his projects at
Headspring     Systems.   You    can     find  it   at
http://www.codeplex.com/AutoMapper.

Now that you have an array of GuestDto in
ViewData, let me show you what the view looks like
for HomeController’s Index action in Listing 3.

Notice right away that you aren’t doing much
formatting in the view. In fact, the new API you’re
using from ASP.NET MVC 2 is:

       <%=Html.DisplayFor(x=>dto) %>

This examines the view model and decides how to
render the object for display. You’ll call this line once
for each object in the array.

Glance back at Figure 3 and you can see that you
have customized the view by putting a box around
each guest and floating the boxes left. The template
helpers   feature    allows   the     definition  of
DisplayTemplates based on type. Figure 5 shows
the views structure where you’ve defined a view for
GuestDto.
Figure 5: Display and Editor templates next to other views.

The DisplayTemplates go inside /Views/Shared and
the templates are reusable in an unlimited number of
views.     The     DisplayTemplates       (and     the
EditorTemplates, which you’ll explore in just a bit)
are partial views. Partial views can use either the
ASCX extension or ASPX extension. It makes no
difference which one you use and there is no
performance difference as well. The one advantage
to using ASPX for partial views is that you can create
template partials using master pages. The following
two snippets shows the sources for GuestDto.aspx
and FloatingBox.Master.
        <%@ Page Language="C#"
           Inherits="ViewPage<GuestDto>"
           MasterPageFile=
              "~/Views/Shared/FloatingBox.Master" %>
        <%@ Import Namespace="UI.Models"%>

       <asp:Content ContentPlaceHolderID="Main"
             runat="server">
          <%=Html.DisplayFor(x=>x.FirstName) %>
          <%=Html.DisplayFor(x=>x.LastName) %>
       </asp:Content>
       <%@ Master Language="C#"
          AutoEventWireup="true"
          Inherits="System.Web.Mvc.ViewMasterPage" %>

       <div
          style="float:left;border:solid 1px navy;
              margin: 2px;padding:4px;">
          <asp:ContentPlaceHolder ID="Main"
              runat="server" />
       </div>

The key to the partial for GuestDto are the lines such
as:

       <%=Html.DisplayFor(x=>x.FirstName) %>

These new html helpers are strongly typed around
view model properties. Not only does that render a
text box for string values, but they also render
labels. I have completely overridden the default
templating, which is very basic.

Now that you have seen how to display values from
a view model using template helpers, let’s examine
how this changes the data entry and validation
game.



Support for DataAnnotations

In short, support for data annotations is UI
validation. Before you jump to conclusions, this is
not a business rules engine or a comprehensive
validation framework.

Microsoft has enhanced the default model binder so
that it looks for any attributes that derive from:

       System.ComponentModel.DataAnnotations.
       ValidationAttribute

When it finds one of these, it runs the validation
code in the attribute class to determine if there is a
ModelState error to report. Along with the built-in
data annotation attributes, shown in Figure 6, you
can easily create your own, and ASP.NET MVC 2 will
run the validations just before the action method is
called but right after the GET or POST request is
model-bound into the action parameters.




Figure 6: Data annotations derived from ValidationAttribute.
The advantage of this is that you get data
consistency checks very early on and mostly for free.
Before you run any code in an action method, you
will know if the entered value is a valid DataTime.
You will know if a required field was omitted.

Many ASP.NET MVC teams are already leveraging
Castle Validators with a custom model binder to
provide this same functionality. If you need this
functionality now, you will want to read Gokhan
Altinoren’s tutorial on hooking up Castle Validators at
http://altinoren.com/PermaLink,guid,bca0aba7-
dbaa-4ccf-bcf3-4d76efab1a40.aspx, or you can
borrow the code from CodeCampServer at
http://codecampserver.org.



Data Entry Enhancements

You saw in Figure 4 the screen that is rendered by
the GuestBookController. This is a simple data entry
screen with three required fields. Listing 4 shows
the view for this page. Normally, you would have
expected to see the layout for this data entry view
here, but it is quite short. In fact, it can be distilled
down to the following four lines of code.

       <% using (Html.BeginForm()) {%>
          <%=Html.EditorFor(x=>x) %>
          <input type="submit" value="Sign In" />
       <% } %>

The new Html.EditorFor template helper is the data
entry counterpart for DisplayFor. Like the display
templates, you can leave rendering up to the
defaults or you can provide a custom template based
on the type being rendered. Glance back at Figure 5
and you will see the EditorTemplates. Before you
dive into what makes this view work as expected,
you’ll find value in examining the view models in
play. Listing 5 shows the GuestForm class and
ColorForm class. Using the suffix “Form” is a
convention you can adopt for view model types that
serve to capture data from a form post only for the
purpose of first-level validation.

       Outside Opinions on
       Templated Helpers
       Templated Helpers will deliver both
       increased developer productivity
       and simplified view markup. This
       Convention over Configuration
       (CoC) approach to generating input
       forms just makes sense. – Eric
       Hexter

       Strongly typed HTML helpers are
       very handy for quick generation of
       xhtml compliant output form
       elements. Be it scalar value types
       or your custom types, all it takes is
       Html.EditorFor(member=>member
       ) – Mahendra Mavani

Remember that you’re performing manual mapping
so you can ignore the MapToGuest() method. Now
turn your attention to the Required attributes affixed
to    each    property.   These    are    from     the
DataAnnotations namespace that come with ASP.NET
Dynamic Data. They are a good start to first-level
validation, but Castle Validators is much more
comprehensive and very easy to wire in in the same
fashion. This is only the first CTP, however, and it
will mature as the release gets closer. The default
validators include ranges and regular expressions, so
they are quite flexible. You can also derive from
System.ComponentModel.DataAnnotations.Validation
Attribute if you’d like to perform some completely
custom validation.

Let’s take a peek at the meat                  of   the
GuestBookController’s Sign action here:

       [HttpPost]
       public ActionResult Sign(GuestForm form)
       {
          if (!ModelState.IsValid)
          {
             return View(form);
          }

          _repository.Save(form.MapToGuest());
          return RedirectToAction(Constants.INDEX,
       Constants.HOME);
       }

You can see two things going on here. First, model
state validation occurs before the action method is
called. The DataAnnotations are detected and run
automatically, and any errors are added to
ModelState. You can immediately check the validity
of model state and re-render the form if necessary.

The second new item you will notice is the
HttpPostAttribute that is used on this action to
denote that it can only be run on an HTTP Post
request.

You saw in Figure 4 that the data entry form wasn’t
completely standard. There is a color select form
element on the screen. Let’s dive into what makes
that happen.

In the GuestForm class you see that the type of the
FavoriteColor property is ColorForm. ColorForm has a
single          property,          which          is
System.Drawing.KnownColor,          and       enum.
System.Web.Mvc.ViewPage<T> has a limitation
where T can only be a reference type. That will
probably be changing, but for now I have wrapped
KnownColor in a reference type so that I can provide
a partial editor template for it.

In Figure 5 you see that there is a ColorForm.aspx
view in the EditorTemplates folder. When rendering
an edit screen and encountering the type ColorForm,
this custom partial will be rendered. The view
contains the following code:

       <%@ Page Language="C#" Inherits="<ColorForm>" %>
       <%@ Import Namespace="System.Drawing"%>
       <%@ Import Namespace="UI.Models"%>
       <%=Html.DropDownList("", new SelectList(
          Enum.GetNames(typeof(KnownColor)))) %>

Five short lines of code is all it takes to instruct
ASP.NET MVC to render a select list with a list of the
known colors. The last piece that closes the loop is a
custom model binder that binds a string into a
ColorForm instance. The model binder code is
registered in the Global.asax file using a single line
of code:

       ModelBinders.Binders.Add(typeof(ColorForm),
          new ColorFormModelBinder());

You can see the source for ColorFormModelBinder in
the following code snippet. It controls how to
transform a string that comes out of the HTTP POST
into a ColorForm object.
        public class ColorFormModelBinder : IModelBinder
        {
           public object BindModel(ControllerContext
              controllerContext,
              ModelBindingContext bindingContext)
           {
              ValueProviderResult result =
                 bindingContext.ValueProvider[
                   bindingContext.ModelName];
              string value = result.AttemptedValue;
              return new ColorForm(value);
           }
        }


Validation functions of the GuestForm object require
all three fields. If you omit a value, you’ll see the
standard errors similar to Figure 7.
Figure 7: Data annotations validate required fields.

Matching a custom partial by type is just the
beginning, and I hope that by the time Microsoft
releases version 2 we can specify template helpers
by any criteria we wish, not just types. Also,
standard formatting like label positions, example text
and required field indicators are all things that will
benefit from further enhancements to the templated
helpers introduced in CTP1 of ASP.NET MVC. Figure
8 shows most of the solution expanded so that you
can see the different parts that came into play in this
example.
Figure 8: The solution layout.

Areas

Several Web frameworks support the concept of an
area. An area is a subsection of the website that is
under a top-level URL fragment. For instance,
http://jeffreypalermo.com/blog is the area for my
blog within JeffreyPalermo.com. On the server side,
ASP.NET MVC 2 will allow the necessary controllers
and views to be completely isolated so that the
whole system is easier for the team to divide and
conquer.

Some customers want to be able to put an area in its
own Web application project, so ASP.NET MVC 2 will
support that capability. Other teams that work on
very large ASP.NET MVC applications actually
collapse the number of projects because as the
solution gets large, Visual Studio and build
automation slows to a crawl. These teams want
areas all within the same project, so Microsoft’s
areas implementation in CTP 1 supports both
models.

An “areas” implementation is the key to a workable
componentization strategy for ASP.NET MVC. Once
we can pull some controllers and views into a
dedicated area, the next step is pretty simple to
package that area up for redistribution. As long as
the routes, controllers, views, and static files are all
packaged up together, control vendors should be
able to deliver some pretty compelling multi-page
components that just drop in to an application.

It remains to be seen how far Microsoft will be able
to go with this in version 2 since it is tied to the
Visual Studio 2010 release. If you need an areas
implementation now and can’t wait, you will probably
be interested in Steve Sanderson’s examples at
http://blog.codeville.net/2008/11/05/app-areas-in-
aspnet-mvc-take-2/. He takes an early concept from
Phil Haack’s blog and improves upon it.

Since Microsoft didn’t implement the areas tooling in
CTP1, I won’t show you any of the code, but take a
look at Figure 9 for an example that has controllers
and views organized into areas.
Figure 9: A solution using two additional areas.
The areas concept is rather simple. The main
application, UI, registers its own routes on startup,
and then it immediately calls into both area projects
to register their routes, hence the Routes.cs files in
each area project. For deployment, all the views and
content of the areas must be merged with the main
Web site. I have displayed excluded folders and files
to show that the views for the areas’ controllers have
been duplicated in the main web project.

This concept will also work if you prefer to put the
areas inside a single UI project. When MVC
applications start to get large, you often remove
friction by collapsing the number of projects down to
just a few. If your project uses Continuous
Integration (CI) then you are motivated to develop
with as few Visual Studio projects as possible so that
the build moves swiftly through the compile step.
The areas implementation that developers will finally
see when ASP.NET MVC 2 releases still has a ways to
go from the implementation you see here, but that is
the purpose of the CTP.



Client Validation

The template helpers and the model binding
validation provide a consistent way to do basic first-
level validation. The lion’s share of the business rules
will still have to have pre-conditions validated in
another place besides the UI. For UI validation,
many applications rely on a round trip to the server
just to find out that a required field was missing.

Microsoft didn’t include client validation in the first
CTP, but they plan to ship the jQuery validation
plugin with ASP.NET MVC 2 so that jQuery behaviors
can be automatically attached to form elements
based on the view model. This does require using
strongly typed view model objects, however. One
view model per view is a good practice anyway
because it pulls us away from the template of using
our domain model in the view. In nontrivial
applications, it is not appropriate to send a Customer
or Product object directly to the view. These objects
are not intended for use in the presentation layer,
and using them as such causes view code to increase
because of the code necessary to format them to the
screen’s specifications. ASP.NET MVC presentation
objects are call view model objects, and it is a good
practice to dedicate a view model object to a single
view and have it represent exactly the data points
necessary for that view. It may be displaying just
some of a product, or it may be accepting a form
post of a product’s name and description change.
Either way, except for trivial 3-page sites like
PartyWithPalermo.com, it is not appropriate to send
your larger domain objects directly through the
presentation layer.

With jQuery validation behaviors being automatically
attached to elements that come from annotated view
model properties, merely marking a view model
property as required will cause jQuery to quickly
mark the field and notify the user when appropriate.
In this manner, many round trips to the server can
be avoided because users will be aware of first-level
validation errors right away, even before sending the
request to the server.



Asynchronous Controller
Actions

Because Web Forms has this feature, many
customers are asking Microsoft for the same feature
in ASP.NET MVC. It is an interesting feature, but it is
one that I would advise you to not intentionally use.

An asynchronous controller would release the
ASP.NET worker thread to serve another request if
the controller was merely waiting on a Web service
call or a long-running operation. When the long-
running operation finishes, the controller would grab
another ASP.NET       worker thread       and   finish
processing.

For Web sites that call long-running processes
directly from the presentation layer, performance
often suffers when the application is put under
moderate load. This is where the asynchronous
feature comes to the rescue by stopping the blocking
of the worker threads that ASP.NET needs to serve
requests.

In my opinion, neither the async feature in Web
Forms nor the upcoming async feature in ASP.NET
MVC should be a part of your architectural plan from
the beginning. You can use the feature to fix bad
production performance quickly, but you should
design the system better from the start.

When your application callsout to any other
application, system, or resource, you have the
potential   for  bad   performance.     Building   in
asynchronicity into the architecture is a better
approach than confining it to the presentation layer.
E-commerce sites do it all the time by giving you a
confirmation number right away and then dealing
with the case of a declined credit card. They could
possibly call MasterCard’s validation Web service
immediately, but under heavy load, that breaks
down.
It is good that Microsoft is porting this Web Forms
feature to the MVC Framework. It will help many
teams get through some tough performance
problems for long enough to redesign the
problematic portion of their system.



Summary

In this article, I have covered the roadmap for
ASP.NET MVC 2 and given my opinionated view on
the significance of each of them. I have also
demonstrated a sample application that uses some
of the features that Microsoft delivered with CTP1.
The ASP.NET MVC team has plans to release many
more CTPs before the final RTM, so we will all be
able to see the release mature over time.

ASP.NET MVC 2 is aimed at being enterprise ready
and at enhancing developer productivity. In this
author’s opinion, the concept of templated helpers
does a lot to reduce duplicative code in views, and
reducing duplication is a big productivity booster.


      Listing 1: The HomeController class
      using   System.Collections.Generic;
      using   System.ComponentModel;
      using   System.Web.Mvc;
      using   Core;
      using   UI.Models;

      namespace UI.Controllers
      {
         [HandleError]
         public class HomeController : Controller
         {
            private readonly IGuestRepository _repository;

              public HomeController()
              {
                 _repository = new GuestRepositoryFactory()
                    .BuildRepository();
              }

              public ActionResult Index(
                 [DefaultValue(10)] int numberOfGuests)
              {
                 Guest[] recentGuests =
                    _repository.GetRecentGuests(numberOfGuests);
                 GuestDto[] guests = MapForDisplay(recentGuests);
                 return View(guests);
              }

              private GuestDto[] MapForDisplay(Guest[] guests)
              {
                 var dtos = new List<GuestDto>();
                 foreach (Guest guest in guests)
                 {
                    dtos.Add(new GuestDto(guest));
            }

            return dtos.ToArray();
        }
    }
}


Listing 2: GuestDto is a display-only view model
using Core;

namespace UI.Models
{
   public class GuestDto
   {
      public GuestDto()
      {
      }

        public GuestDto(Guest guest)
        {
           FirstName = guest.FirstName;
           LastName = guest.LastName;
        }

        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
}


Listing 3: The Home Index view
<%@ Page Title="" Language="C#"
MasterPageFile="~/Views/Shared/Site.Master"
Inherits="ViewPage<IEnumerable<GuestDto>>" %>
<%@ Import Namespace="UI.Models"%>

<asp:Content ID="Content1"
   ContentPlaceHolderID="TitleContent"
   runat="server">
   Index
</asp:Content>

<asp:Content ID="Content2"
   ContentPlaceHolderID="MainContent"
   runat="server">
   <div>
    <% foreach (var item in Model) { %>
          <%GuestDto dto = item;%>
          <%=Html.DisplayFor(x=>dto) %>
    <% } %>
   </div>
   <div style="clear:both;"/>
</asp:Content>




Listing 4: The Sign view
<%@ Page Title="" Language="C#"
   MasterPageFile="~/Views/Shared/Site.Master"
    Inherits="ViewPage<UI.Models.GuestForm>" %>

<asp:Content ID="Content1"
ContentPlaceHolderID="TitleContent" runat="server">
   Sign
</asp:Content>

<asp:Content ID="Content2"
ContentPlaceHolderID="MainContent" runat="server">

        <h2>Sign the GuestBook!</h2>

        <%= Html.ValidationSummary(@"Create was unsuccessful.
        Please correct the errors and try again.") %>

        <% using (Html.BeginForm()) {%>
             <%=Html.EditorFor(x=>x) %>
             <input type="submit" value="Sign In" />
        <% } %>

</asp:Content>


Listing 5. The GuestForm and ColorForm view models
using     System;
using     System.ComponentModel.DataAnnotations;
using     System.Drawing;
using     Core;

namespace UI.Models
{
   public class GuestForm
   {
      [Required]
      public string FirstName { get; set; }
      [Required]
      public string LastName { get; set; }
      [Required]
      public ColorForm FavoriteColor { get; set; }

          public Guest MapToGuest()
          {
             return new Guest
                       {
                          FirstName = FirstName,
                          LastName = LastName,
                          FavoriteColor = FavoriteColor.Color,
                       };
          }
    }

    public class ColorForm
    {
       public ColorForm(string value)
       {
          Color =
             (KnownColor) Enum.Parse(typeof (KnownColor), value);
       }

          public KnownColor Color { get; set; }
    }
}
Most of these developers who
are retooling will choose
ASP.NET MVC because of its
refreshing simplicity and also
because of the massive
productivity enhancements
over Web Forms.

Moving between domain model
and view models requires
mapping each way, and that
code can become repetitive.
AutoMapper reduces that
chore to convention-based
configuration. . .

Jeffrey Palermo
Jeffrey@Palermo.cc
512-689-2377
JEFFREY PALERMO is an author of a
recent book, ASP.NET MVC in
Action. You can obtain the book at
http://bit.ly/mvcinaction. He is the
CTO of Headspring Systems. He is
instrumental in the Austin software
community as a member of
AgileAustin and a director of the
Austin .NET User Group. Jeffrey
has been recognized by Microsoft
as a “Microsoft Most Valuable
Professional” (MVP) in Solutions
Architecture for five years and
participates in the ASPInsiders
group, which advises the ASP. NET
team on future releases. Jeffrey
has spoken and facilitated at
industry conferences such as
VSLive, DevTeach, the Microsoft
MVP Summit, various ALT.NET
conferences, and Microsoft Tech
Ed. He also speaks to user groups
around the country as part of the
INETA Speakers’ Bureau. Jeffrey is
an Iraq ware veteran and a co-
founder of the MvcContrib project.

								
To top