MVC 2: Electric Boogaloo - What's new in MVC 2

Posted by Joe Wilson on Sunday, January 17, 2010 3:28 PM

The MVCbreakin2 team loves their rec center, but an evil real estate developer wants to bulldoze it to build a hipster bar named Ruby's.  The team has been coding their butts off with MVC 2, but will the new features be enough to save the rec center?  Will the cynical real estate developer cackle and complain that it's still not enough? 

Will the MVC team get areas right?  Will the new templated HtmlHelpers strike the right balance of rapid development and fine control?  Will validation concerns get muddled up with UI concerns?  Will more web forms developers make the switch to MVC? 

New Areas

Areas are an organizing tool for large web sites.  If you've got lots of view and lots of controllers plus some shared content, areas can work as a top-level routing mechanism. 

Example areas might be Admin for an administrative site, Store for a ecommerce site, etc.  They can be either folders or separate web projects.  Use the AreaRegistration class to set up your routes in your Global.asax (taken from MSDN article):

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    AreaRegistration.RegisterAllAreas();

    routes.MapRoute(
        "Default",                                              // Route name
        "{controller}/{action}/{id}",                           // URL with parameters
        new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
    );
}

Then override AreaRegistration in the area's folder or in the root of the area web project (also taken from MSDN article):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace Store
{
    public class Routes : AreaRegistration
    {
        public override string AreaName
        {
            get { return "Store"; }
        }

        public override void RegisterArea(AreaRegistrationContext context)
        {
            context.MapRoute(
                "Store_Default",
                "Store/{controller}/{action}/{id}",
                new { controller = "Products", action = "List", id = "" }
            );
        }
    }
}

Sharp Architecture has had areas since its first release.  I remember hearing rumors about areas coming in MVC for version 1.0, but I guess it wasn't ready.  The biggest difference between the Microsoft version and the Sharp Architecture version is that the Microsoft version lets you register different web projects. 

Theoretically, multiple teams can work on multiple web projects, then these web projects can be rolled into the same solution and AreaRegistration can make them appear as one big web site to a browser.  I don't know how much of a need that is, but I guess if you have distributed teams that can't get to the same source code repository, it might be useful.  I prefer multiple folders in one web project over multiple web projects to keep build times down and Visual Studio responsiveness up.  I wouldn't break out each logical web site section to its own web project until the folder approach stopped working.

New HtmlHelpers

I'm not sure if Code Camp Server pushed the MVC team into this or just showed how it was possible to take HtmlHelpers to this extreme, but I'm glad to see the same concepts getting rolled into the base class libraries. 

I think the new HtmlHelpers do give a nice range of control over your markup.  You can use:

<%= Html.LabelFor(x => x.FirstName) %>
<%= Html.EditorFor(x => x.FirstName) %>
<%= Html.LabelFor(x => x.LastName) %>
<%= Html.EditorFor(x => x.LastName) %>

if you want to be fairly explicit for each form element.  Or you can save a lot of keystrokes with:

<%= Html.EditorFor(x => x) %>

And if that's not enough, you can decorate your models with some UI hint attributes and roll your own rendering.  I think this is something large web projects will take advantage of for consistent markup and control rendering.  Seems like this has the advantages of homemade server controls without some of the hassles (INamingContainer, I'm looking at you).

New Validation

I did worry for a little bit about the UI stuff bleeding into the model with these new attributes.  Seems like we've got a leaky abstraction there.  But these days I think of the MVC model as the view model, not the domain model.  The view model is married to the view it works with.  It has no other purpose than to represent the data in that view.  Well, now it also validates the data in that view, at least initially.  Oh, and it now controls some of the view rendering.  Damn.  That's three responsibilities for my little view model.

But I don't have an alternative proposal to attribute-heavy view models either.  I don't want partial classes.  I haven't seen much benefit to the buddy class approach.  And I do want to reuse some of my UI hints across view models (like a date picker for DateTime types).  Plus, I want to take advantage of the new client and server side validation of my view model before it gets into the action method.  MVC 2 has this built in.

I guess I'll grin and bear it and work on a new blog post about the Triple Responsibility Principal for View Models (as opposed to SRP). :D

Future

I've already talked about where MVC views are now and where they are going, and the view engine is definitely getting better. I still think views will continue to be the most in-flux part of the MVC framework.  I know people that are very happy with Spark as a view engine, and Louis DeJardin, the guy who wrote Spark, is now working for Microsoft on the ASP.NET team.  I don't have any inside scoop, but I wouldn't be surprised if the web forms view engine got a little."sparkier".

Views may also be the area with the most room for improvement, depending on who you talk to.  When I visit with people about MVC and explain that runat="server" is gone and you can go ahead and close your Visual Studio toolbox, most get a glazed look.  They don't want to hand code the HTML.  They don't want to see a property sheet that doesn't know anything about their current mouse selection.  They don't want to give up their current productivity.

I get that, but I think you can be faster without the designers and toolboxes and property sheets.  It takes a while to get used to using the keyboard more than the mouse, but I think it's worth pushing yourself over that learning curve.

Time to switch from Web Forms to MVC?

I push MVC on projects where I have influence on that decision.  In your world, it's your call.  You may have environment constraints, in-flight projects, etc. 

But it also doesn't have to be all or nothing.  You don't have to wait for a greenfield project to fall in your lap.  You can run MVC inside your current Web Forms project.  It's just another set of HttpHandlers living under ASP.NET.  Here is some guidance for getting your current project set up to do this.

I encourage you to give it a try and see what you think.  It will take a while to get used to the paradigm.  It's not hard - just different.  But I think once you're used to it, you'll like the separation of concerns, the easier testing, and the more natural flow for web development. 

By natural flow, I mean embracing the world of GET and POST.  I mean when you need to expose JSON, an RSS feed, or something else (XML, PDF, file, etc.), Controller Actions are ready to go.  Stop writing custom HttpHandlers or fighting WCF configuration for this stuff.  It should be simpler, and it is with Controller Actions and the right ActionResult.

Make it a goal to get some real-world MVC experience in 2010.  Think of the kids on the MVC team and their beloved rec center.  Don't let their dream die.  They've come too far.  And remember the tag line from Breakin' 2 - "If you can't beat the system.break it!".

Tags: , , , , ,
Categories: Technical


kick it on DotNetKicks.com shout it on DotNetShoutOut

Validation frameworks in ASP.NET MVC

Posted by Joe Wilson on Tuesday, September 15, 2009 9:09 PM

There are plenty of validation frameworks out there.  I've worked with NHibernate Validators, Microsoft's Enterprise Application Blocks, and now Data Annotations.  They primarily work by adding attributes to the properties in the class you want to validate. 

How are they different?

Not very.  The biggest difference between them is their syntax.  I guess the Validation Blocks from Microsoft's P&P group have a lot of configuration options, but I haven't needed that on a project.  The most prominent differences are in the attributes themselves.

You can probably make a case for Data Annotations having a slight advantage since it's going to be in the .NET base-class libraries.  Easier to deal with assemblies installed in the GAC instead of the ones you have to drag around for each deployment.

How do you integrate them with MVC?

Each of these frameworks can be integrated with ASP.NET MVC.  But the best validation call is one you don't have to explicitly make.  Huh?

It's OK to call MyClass.IsValid() in a controller action, but if you can avoid it, I think you're better off.  Otherwise, what happens if you forget to call it?

Instead, use a model binder that invokes the validation framework for you.  This is how I am using the Data Annotations model binder with the MVC framework:

ModelBinders.Binders.DefaultBinder = new Microsoft.Web.Mvc.DataAnnotations.DataAnnotationsModelBinder();

Now this guy will intercept calls to your controller actions and reject invalid incoming view models.  Here is a simple tutorial for using Data Annotations that goes into more detail.

How do you lay this out in the solution?

I have an Application Services layer that my MVC layer calls into.  My controllers have constructors with an interface to an application service injected into them.  My IoC container decides which concrete version of this application service interface to use at runtime.

Next, my Application Service layer has a DTO folder that holds all the DTOs (property-only classes) my views need in my MVC app.  These are not my domain entities.  There might be a lot of overlap with those domain entities, but these DTOs are just there for communication between the UI layer and Application Services layer.  These DTOs are where I put my validation attributes.

So now I've got views that are tightly bound to the DTOs, which are owned in the Application Services layer.  This allows strong typing of the view so I can use the DTO's properties as my view's model.  This is handy for the Html Helpers to get design-time IntelliSense and compile-time checking.

What else can you do?

I haven't spent a lot of time looking into it, but xVal looks pretty strong for client side AND server side validation using Data Annotations and a couple other validation frameworks.  It also lets you validate your business rules in your domain and throw an exception.  I need to check into this more, because that sounds like the validation holy grail for validation to me: getting UI validation and business rule validation into a common format.

Tags: , , ,
Categories: Technical


kick it on DotNetKicks.com shout it on DotNetShoutOut

Where should validation go?

Posted by Joe Wilson on Monday, September 14, 2009 10:06 PM

<groan>Not this argument again!</groan>

The short answer: I don't know.

The long answer: Yeah, I really don't know.

There is still no widely accepted answer on this one.  Reasonable people disagree.  One camp pushes it up closer to the UI, the other down lower so it shelters the domain from invalid states.  Some like it sprinkled across layers; some like it centralized.

I think Steve Sanderson is correct that validation falls on a continuum from easy UI validation, like required fields, to complex business rules that need to be checked closer to or in the domain entities.

I also think Jimmy Bogard is correct that context matters when it comes to validation.  This object is valid for what?  Saving to the database?  Emailing to sales?  Displaying on the screen?  The validation rules depend on the the behavior you are validating.

These days, I think of validation as either UI Validation (required fields, min/max length, etc.), Domain Validation (start date/time must be before end date/time, order must have at least one item, etc.), or Database Validation (is this value unique, is this ID value going to throw a foreign key violation).  This is based on when you can validate in the call chain more than what it's valid for.  I still like validation in context, but those business rules end up in my Domain Validation logic with method names like CanSendEmailToCustomer().

Sharp Architecture uses NHibernate Validators as attributes on the domain entities.  The best thing about this is your validation is centralized.  It's sitting right there in your domain, and you know where to go if there is a rule change.

The other good thing about this approach is your entity should always be valid when saved.  The built-in Repository<TEntity> calls in Sharp Architecture enforce validation before inserts and updates, so you're covered there.  If you want to call MyEntity.IsValid() in a method, you can do that as well.

The bad thing is those validation attributes can start looking like UI concerns when they have user-centric error messages in them ("Hey, user, that's not a valid format for a phone number").  And if there is a rule that doesn't lend itself to attributes (e.g., orders must have at least one order item), you are on your own.

I started with validation attributes on my domain entities, and when my attribute messages got too UI-looking, I moved to using Data Annotations on DTOs in my application service layer for UI validation.  The DTOs are made to be client facing, so I'm not bothered by user-specific messages in them. 

Then when Domain or Database Validation problems come up, a ValidationException is thrown up through the application service to the UI so the calling app can either display or handle it.  I haven't played with it yet, but I think this is what xVal is doing, too.

The more I think about it, the more I see my web app as just another client calling into my application service layer which is encapsulating my domain.  So my web app is the "user" and the message needs to be just enough for that user, not necessarily the end user.  Maybe a validation exception token is sent out from the application service layer to the UI, and the UI translates that to a string from a very UI-centric resource file?

Bu I'm still not happy with this.  I feel like I have the right kind of validation in the right places, but I would still like a more centralized approach for easier refactoring of business rules.  I've used the Specification Pattern before, and it does a great job of centralizing the rules.  But making yet another class for yet another required field and adding it to yet another Composite Specification?  Seems like your walking away from a lot of the productivity attributes can give you.

Obviously, my thoughts on validation are still not fully formed.  I'm still arguing with myself.  My dream validation would be:

  • centralized for easy refactoring and rule changes
  • automatically called for routine things so I don't forget (like saving the order to the database)
  • allow ad hoc calls for non-routine things (like validating the order confirmation email can be sent to the customer)
  • handle simple validation like attributes so I can be productive
  • handle complex validation like specifications so I'm not limited
  • UI-agnostic so the centralized validation goo isn't holding end-user strings, except when I'm too lazy to set up the resource file, in which case strings can be passed up from this layer

I told you I didn't know! :>

Tags: , ,
Categories: Technical


kick it on DotNetKicks.com shout it on DotNetShoutOut

Image Details