Last week I gave a presentations to the 2011 UC Davis IT Security Symposium that covered input validation features in HTML5.  I mostly discussed the following three topics:

  1. New Html5 Input Types (like <input type=”email” />)
  2. Html5 Constraints (like <input type=”text” required maxlength=”8” />)
  3. Polyfills

The slides only cover part of the story since there are a few “live demos.”  You can find all of the demo code on my github repository https://github.com/srkirkland/ITSecuritySymposium.  You’ll need ASP.NET Mvc 3 installed to run them.

The slides are also available in my GitHub repository, but I’ve also added them to slideshare as well because that’s what the cool kids do: http://www.slideshare.net/srkirkland/data-validation-in-web-applications.

I believe the presentation was well received and most people learned something, so I just wanted to share.  When loading up the Html5 demo just click on the Html5 tab and go through each example. Enjoy!

 

[Examples from the Slides and Demos]

 

image

image

image

One great benefit of having a Continuous Integration server like TeamCity (http://www.jetbrains.com/teamcity/) building your code is that you can hook into the build process to have it also handle tedious or time-consuming tasks for you, such as running all of your unit tests, code coverage analyses, etc.

Now that NuGet (http://nuget.org/) has arrived and simplified package management in .NET, wouldn’t it be nice to have your CI server build an updated NuGet package for you along with every build?  An why not go one step further and have your build process automatically push the newest version of your package to the central NuGet server (or even your own hosted NuGet server)?

It turns out this is actually very easy to do – let’s see how.

Super-Quick NuGet Package Introduction

If you would like to familiarize yourself with what NuGet is and how to use it, take a look at the project homepage at http://nuget.codeplex.com/

For this post it’s really only necessary to know that a NuGet package starts out as a specification file (*.nupec) and usually some deliverable content (Dlls, script files, etc).  Once you have a specification file, you use the NuGet.exe command line utility to turn it into a package (*.nupkg) that can then be uploaded to the masses via http://nuget.org/.  [Full details are available at http://nuget.codeplex.com/documentation?title=Creating%20a%20Package].

Building and Deploying Your Package

You’ll need to have your *.nuspec file checked into source control, and I also find it useful to check in the nuget.exe command-line utility as well (although this is not necessary as long as it is on your build server).  I tend to put my specifications in a /Build/NuGet folder, so it’s outside of the main /src/ folder.

Note: The following steps are TeamCity specific, but any build process with the ability to run a batch file should be able to do the same thing.

1. Open up your project’s build configuration and select #3, “Build Steps.”

image

2. Click “Add Build Step.”

3. Under Runner Type choose “Command Line,” and then under Run choose “Custom Script.”  You can optionally specify a working directory to have your script run in that directory, which I find to be quite helpful.

image

4.  Now you are ready to write your custom script, which should be able to perform the following steps: (1) cleanup old *.nupack files, (2) create your newest package with the correct version number, and (3) push that package up to nuget.org or another nuget server.

My script is as follows:

del *.nupkg
 
NuGet.exe pack Project\Project.nuspec -Version %system.build.number%
 
forfiles /m *.nupkg /c "cmd /c NuGet.exe push @FILE <your-key>"

5. That’s all there is to it, just replace <your-key> with your access key from nuget.org (look under MyAccount)

image

Script Breakdown:

On line two notice how I use TeamCity’s %system.build.number% to inject the build number into the generated package.  This is very important because NuGet pays close attention to your package version number (as David Ebbo describes in detail in his NuGet versioning blog series http://blog.davidebbo.com/2011/01/nuget-versioning-part-3-unification-via.html).

The third line is pretty fun—basically it is saying for every file that ends in *.nupkg, call ‘NuGet.exe push <filename> <your-key>’.  I really like this approach, and it could even be adapted to build and push multiple NuGet packages during every build run.

Wrap Up

Overall there wasn’t too much work to do, we just created a command line script build runner and added a few lines of code to automatically build and push versioned NuGet packages.

Now that I’m using NuGet a lot more, with one OSS project on nuget.org (http://dataannotationsextensions.org/) and several hosted on my own internal company NuGet server, I find this automatic build and deploy process the perfect way to keep my packages up to date. 

Enjoy!

I was writing conventions for FluentNHibernate the other day and I ran into the need to pluralize a given string and immediately thought of the ruby on rails Inflector.  It turns out there is a .NET library out there also capable of doing word inflection, originally written (I believe) by Andrew Peters, though the link I had no longer works.  The entire Inflector class is only a little over 200 lines long and can be easily included into any project, and contains the Pluralize() method along with a few other helpful methods (like Singularize(), Camelize(), Capitalize(), etc).

The Inflector class is available in its entirety from my github repository https://github.com/srkirkland/Inflector.  In addition to the Inflector.cs class I added tests for every single method available so you can gain an understanding of what each method does.  Also, if you are wondering about a specific test case feel free to fork my project and add your own test cases to ensure Inflector does what you expect.

Here is an example of some test cases for pluralize:

TestData.Add("quiz", "quizzes");
TestData.Add("perspective", "perspectives");
TestData.Add("ox", "oxen");
TestData.Add("buffalo", "buffaloes");
TestData.Add("tomato", "tomatoes");
TestData.Add("dwarf", "dwarves");
TestData.Add("elf", "elves");
TestData.Add("mouse", "mice");
 
TestData.Add("octopus", "octopi");
TestData.Add("vertex", "vertices");
TestData.Add("matrix", "matrices");
 
TestData.Add("rice", "rice");
TestData.Add("shoe", "shoes");

Pretty smart stuff.

ASP.NET MVC 3 includes a new unobtrusive validation strategy that utilizes HTML5 data-* attributes to decorate form elements.  Using a combination of jQuery validation and an unobtrusive validation adapter script that comes with MVC 3, those attributes are then turned into client side validation rules.

A Quick Introduction to Unobtrusive Validation

To quickly show how this works in practice, assume you have the following Order.cs class (think Northwind) [If you are familiar with unobtrusive validation in MVC 3 you can skip to the next section]:

public class Order : DomainObject
{
    [DataType(DataType.Date)]
    public virtual DateTime OrderDate { get; set; }
 
    [Required]
    [StringLength(12)]
    public virtual string ShipAddress { get; set; }
 
    [Required]
    public virtual Customer OrderedBy { get; set; }
}

Note the System.ComponentModel.DataAnnotations attributes, which provide the validation and metadata information used by ASP.NET MVC 3 to determine how to render out these properties.  Now let’s assume we have a form which can edit this Order class, specifically let’s look at the ShipAddress property:

@Html.LabelFor(x => x.Order.ShipAddress)
@Html.EditorFor(x => x.Order.ShipAddress)
@Html.ValidationMessageFor(x => x.Order.ShipAddress)

Now the Html.EditorFor() method is smart enough to look at the ShipAddress attributes and write out the necessary unobtrusive validation html attributes.  Note we could have used Html.TextBoxFor() or even Html.TextBox() and still retained the same results.

If we view source on the input box generated by the Html.EditorFor() call, we get the following:

<input type="text" value="Rua do Paço, 67" name="Order.ShipAddress" id="Order_ShipAddress" 
data-val-required="The ShipAddress field is required." data-val-length-max="12" 
data-val-length="The field ShipAddress must be a string with a maximum length of 12." 
data-val="true" class="text-box single-line input-validation-error">

As you can see, we have data-val-* attributes for both required and length, along with the proper error messages and additional data as necessary (in this case, we have the length-max=”12”).

And of course, if we try to submit the form with an invalid value, we get an error on the client:

image

Working with MvcContrib’s Fluent Html

The MvcContrib project offers a fluent interface for creating Html elements which I find very expressive and useful, especially when it comes to creating select lists.  Let’s look at a few quick examples:

@this.TextBox(x => x.FirstName).Class("required").Label("First Name:")
@this.MultiSelect(x => x.UserId).Options(ViewModel.Users)
@this.CheckBox("enabled").LabelAfter("Enabled").Title("Click to enable.").Styles(vertical_align => "middle")
 
@(this.Select("Order.OrderedBy").Options(Model.Customers, x => x.Id, x => x.CompanyName)
                    .Selected(Model.Order.OrderedBy != null ? Model.Order.OrderedBy.Id : "")
                    .FirstOption(null, "--Select A Company--")
                    .HideFirstOptionWhen(Model.Order.OrderedBy != null)
                    .Label("Ordered By:"))

These fluent html helpers create the normal html you would expect, and I think they make life a lot easier and more readable when dealing with complex markup or select list data models (look ma: no anonymous objects for creating class names!).

Of course, the problem we have now is that MvcContrib’s fluent html helpers don’t know about ASP.NET MVC 3’s unobtrusive validation attributes and thus don’t take part in client validation on your page.  This is not ideal, so I wrote a quick helper method to extend fluent html with the knowledge of what unobtrusive validation attributes to include when they are rendered.

Extending MvcContrib’s Fluent Html

Before posting the code, there are just a few things you need to know.  The first is that all Fluent Html elements implement the IElement interface (MvcContrib.FluentHtml.Elements.IElement), and the second is that the base System.Web.Mvc.HtmlHelper has been extended with a method called GetUnobtrusiveValidationAttributes which we can use to determine the necessary attributes to include.  With this knowledge we can make quick work of extending fluent html:

public static class FluentHtmlExtensions
{
    public static T IncludeUnobtrusiveValidationAttributes<T>(this T element, HtmlHelper htmlHelper) 
        where T : MvcContrib.FluentHtml.Elements.IElement
    {
        IDictionary<string, object> validationAttributes = htmlHelper
            .GetUnobtrusiveValidationAttributes(element.GetAttr("name"));
 
        foreach (var validationAttribute in validationAttributes)
        {
            element.SetAttr(validationAttribute.Key, validationAttribute.Value);
        }
 
        return element;
    }
}

The code is pretty straight forward – basically we use a passed HtmlHelper to get a list of validation attributes for the current element and then add each of the returned attributes to the element to be rendered.

The Extension In Action

Now let’s get back to the earlier ShipAddress example and see what we’ve accomplished.  First we will use a fluent html helper to render out the ship address text input (this is the ‘before’ case):

@this.TextBox("Order.ShipAddress").Label("Ship Address:").Class("class-name")

And the resulting HTML:

<label id="Order_ShipAddress_Label" for="Order_ShipAddress">Ship Address:</label>
<input type="text" value="Rua do Paço, 67" name="Order.ShipAddress"
 id="Order_ShipAddress" class="class-name">

Now let’s do the same thing except here we’ll use the newly written extension method:

@this.TextBox("Order.ShipAddress").Label("Ship Address:")
.Class("class-name").IncludeUnobtrusiveValidationAttributes(Html)

And the resulting HTML:

<label id="Order_ShipAddress_Label" for="Order_ShipAddress">Ship Address:</label>
<input type="text" value="Rua do Paço, 67" name="Order.ShipAddress"
 id="Order_ShipAddress" data-val-required="The ShipAddress field is required."
 data-val-length-max="12"
 data-val-length="The field ShipAddress must be a string with a maximum length of 12."
 data-val="true" class="class-name">

Excellent!  Now we can continue to use unobtrusive validation and have the flexibility to use ASP.NET MVC’s Html helpers or MvcContrib’s fluent html helpers interchangeably, and every element will participate in client side validation.

image

Wrap Up

Overall I’m happy with this solution, although in the best case scenario MvcContrib would know about unobtrusive validation attributes and include them automatically (of course if it is enabled in the web.config file).  I know that MvcContrib allows you to author global behaviors, but that requires changing the base class of your views, which I am not willing to do.

Enjoy!

Validation of user input is integral to building a modern web application, and ASP.NET MVC offers us a way to enforce business rules on both the client and server using Model Validation.  The recent release of ASP.NET MVC 3 has improved these offerings on the client side by introducing an unobtrusive validation library built on top of jquery.validation.  Out of the box MVC comes with support for Data Annotations (that is, System.ComponentModel.DataAnnotations) and can be extended to support other frameworks.  Data Annotations Validation is becoming more popular and is being baked in to many other Microsoft offerings, including Entity Framework, though with MVC it only contains four validators: Range, Required, StringLength and Regular Expression.  The Data Annotations Extensions project attempts to augment these validators with additional attributes while maintaining the clean integration Data Annotations provides.

A Quick Word About Data Annotations Extensions

The Data Annotations Extensions project can be found at http://dataannotationsextensions.org/, and currently provides 11 additional validation attributes (ex: Email, EqualTo, Min/Max) on top of Data Annotations’ original 4.  You can find a current list of the validation attributes on the afore mentioned website.

The core library provides server-side validation attributes that can be used in any .NET 4.0 project (no MVC dependency). There is also an easily pluggable client-side validation library which can be used in ASP.NET MVC 3 projects using unobtrusive jquery validation (only MVC3 included javascript files are required).

On to the Preview

Let’s say you had the following “Customer” domain model (or view model, depending on your project structure) in an MVC 3 project:

public class Customer
{
    public string  Email { get; set; }
    public int Age { get; set; }
    public string ProfilePictureLocation { get; set; }
}

When it comes time to create/edit this Customer, you will probably have a CustomerController and a simple form that just uses one of the Html.EditorFor() methods that the ASP.NET MVC tooling generates for you (or you can write yourself).  It should look something like this:

image

With no validation, the customer can enter nonsense for an email address, and then can even report their age as a negative number!  With the built-in Data Annotations validation, I could do a bit better by adding a Range to the age, adding a RegularExpression for email (yuck!), and adding some required attributes.  However, I’d still be able to report my age as 10.75 years old, and my profile picture could still be any string.  Let’s use Data Annotations along with this project, Data Annotations Extensions, and see what we can get:

public class Customer
{
    [Email]
    [Required]
    public string  Email { get; set; }
 
    [Integer]
    [Min(1, ErrorMessage="Unless you are benjamin button you are lying.")]
    [Required]
    public int Age { get; set; }
 
    [FileExtensions("png|jpg|jpeg|gif")]
    public string ProfilePictureLocation { get; set; }
}

Now let’s try to put in some invalid values and see what happens:

image

That is very nice validation, all done on the client side (will also be validated on the server).  Also, the Customer class validation attributes are very easy to read and understand.

Another bonus: Since Data Annotations Extensions can integrate with MVC 3’s unobtrusive validation, no additional scripts are required!

Now that we’ve seen our target, let’s take a look at how to get there within a new MVC 3 project.

Adding Data Annotations Extensions To Your Project

First we will File->New Project and create an ASP.NET MVC 3 project.  I am going to use Razor for these examples, but any view engine can be used in practice. 

Now go into the NuGet Extension Manager (right click on references and select add Library Package Reference) and search for “DataAnnotationsExtensions.”  You should see the following two packages:

image

The first package is for server-side validation scenarios, but since we are using MVC 3 and would like comprehensive sever and client validation support, click on the DataAnnotationsExtensions.MVC3 project and then click Install.  This will install the Data Annotations Extensions server and client validation DLLs along with David Ebbo’s web activator (which enables the validation attributes to be registered with MVC 3).

Now that Data Annotations Extensions is installed you have all you need to start doing advanced model validation.  If you are already using Data Annotations in your project, just making use of the additional validation attributes will provide client and server validation automatically.  However, assuming you are starting with a blank project I’ll walk you through setting up a controller and model to test with.

Creating Your Model

In the Models folder, create a new User.cs file with a User class that you can use as a model.  To start with, I’ll use the following class:

public class User
{
    public string Email { get; set; }
    public string Password { get; set; }
    public string PasswordConfirm { get; set; }
    public string HomePage { get; set; }
    public int Age { get; set; }
}

Next, create a simple controller with at least a Create method, and then a matching Create view (note, you can do all of this via the MVC built-in tooling).  Your files will look something like this:

UserController.cs:

public class UserController : Controller
{
    public ActionResult Create()
    {
        return View(new User());
    }
 
    [HttpPost]
    public ActionResult Create(User user)
    {
        if (!ModelState.IsValid)
        {
            return View(user);
        }
 
        return Content("User valid!");
    }
}

Create.cshtml:

@model NuGetValidationTester.Models.User
 
@{
    ViewBag.Title = "Create";
}
 
<h2>Create</h2>
 
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
 
@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>User</legend>
        
        @Html.EditorForModel()
        
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
}

In the Create.cshtml view, note that we are referencing jquery validation and jquery unobtrusive (jquery is referenced in the layout page).  These MVC 3 included scripts are the only ones you need to enjoy both the basic Data Annotations validation as well as the validation additions available in Data Annotations Extensions.  These references are added by default when you use the MVC 3 “Add View” dialog on a modification template type.

Now when we go to /User/Create we should see a form for editing a User

image

Since we haven’t yet added any validation attributes, this form is valid as shown (including no password, email and an age of 0).  With the built-in Data Annotations attributes we can make some of the fields required, and we could use a range validator of maybe 1 to 110 on Age (of course we don’t want to leave out supercentenarians) but let’s go further and validate our input comprehensively using Data Annotations Extensions.  The new and improved User.cs model class.

{
    [Required]
    [Email]
    public string Email { get; set; }
 
    [Required]
    public string Password { get; set; }
 
    [Required]
    [EqualTo("Password")]
    public string PasswordConfirm { get; set; }
 
    [Url]
    public string HomePage { get; set; }
 
    [Integer]
    [Min(1)]
    public int Age { get; set; }
}

Now let’s re-run our form and try to use some invalid values:

image

All of the validation errors you see above occurred on the client, without ever even hitting submit.  The validation is also checked on the server, which is a good practice since client validation is easily bypassed.

That’s all you need to do to start a new project and include Data Annotations Extensions, and of course you can integrate it into an existing project just as easily.

Nitpickers Corner

ASP.NET MVC 3 futures defines four new data annotations attributes which this project has as well: CreditCard, Email, Url and EqualTo.  Unfortunately referencing MVC 3 futures necessitates taking an dependency on MVC 3 in your model layer, which may be unadvisable in a multi-tiered project.  Data Annotations Extensions keeps the server and client side libraries separate so using the project’s validation attributes don’t require you to take any additional dependencies in your model layer which still allowing for the rich client validation experience if you are using MVC 3.

Custom Error Message and Globalization: Since the Data Annotations Extensions are build on top of Data Annotations, you have the ability to define your own static error messages and even to use resource files for very customizable error messages.

Available Validators: Please see the project site at http://dataannotationsextensions.org/ for an up-to-date list of the new validators included in this project.  As of this post, the following validators are available:

  • CreditCard
  • Date
  • Digits
  • Email
  • EqualTo
  • FileExtensions
  • Integer
  • Max
  • Min
  • Numeric
  • Url

Conclusion

Hopefully I’ve illustrated how easy it is to add server and client validation to your MVC 3 projects, and how to easily you can extend the available validation options to meet real world needs.

The Data Annotations Extensions project is fully open source under the BSD license.  Any feedback would be greatly appreciated.  More information than you require, along with links to the source code, is available at http://dataannotationsextensions.org/.

Enjoy!

The System.ComponentModel.DataAnnotations namespace contains a validation attribute called DataTypeAttribute, which takes an enum specifying what data type the given property conforms to.  Here are a few quick examples:

public class DataTypeEntity
{
    [DataType(DataType.Date)]
    public DateTime DateTime { get; set; }
 
    [DataType(DataType.EmailAddress)]
    public string EmailAddress { get; set; }
}

This attribute comes in handy when using ASP.NET MVC, because the type you specify will determine what “template” MVC uses.  Thus, for the DateTime property if you create a partial in Views/[loc]/EditorTemplates/Date.ascx (or cshtml for razor), that view will be used to render the property when using any of the Html.EditorFor() methods.

One thing that the DataType() validation attribute does not do is any actual validation.  To see this, let’s take a look at the EmailAddress property above.  It turns out that regardless of the value you provide, the entity will be considered valid:

//valid
new DataTypeEntity {EmailAddress = "Foo"};

image

Hmmm.  Since DataType() doesn’t validate, that leaves us with two options: (1) Create our own attributes for each datatype to validate, like [Date], or (2) add validation into the DataType attribute directly. 

In this post, I will show you how to hookup client-side validation to the existing DataType() attribute for a desired type.  From there adding server-side validation would be a breeze and even writing a custom validation attribute would be simple (more on that in future posts).

Validation All The Way Down

Our goal will be to leave our DataTypeEntity class (from above) untouched, requiring no reference to System.Web.Mvc.  Then we will make an ASP.NET MVC project that allows us to create a new DataTypeEntity and hookup automatic client-side date validation using the suggested “out-of-the-box” jquery.validate bits that are included with ASP.NET MVC 3.  For simplicity I’m going to focus on the only DateTime field, but the concept is generally the same for any other DataType.

image

Building a DataTypeAttribute Adapter

To start we will need to build a new validation adapter that we can register using ASP.NET MVC’s DataAnnotationsModelValidatorProvider.RegisterAdapter() method.  This method takes two Type parameters; The first is the attribute we are looking to validate with and the second is an adapter that should subclass System.Web.Mvc.ModelValidator.

Since we are extending DataAnnotations we can use the subclass of ModelValidator called DataAnnotationsModelValidator<>.  This takes a generic argument of type DataAnnotations.ValidationAttribute, which lucky for us means the DataTypeAttribute will fit in nicely.

So starting from there and implementing the required constructor, we get:

public class DataTypeAttributeAdapter : DataAnnotationsModelValidator<DataTypeAttribute>
{
    public DataTypeAttributeAdapter(ModelMetadata metadata, ControllerContext context, DataTypeAttribute attribute)
        : base(metadata, context, attribute) { }
}

Now you have a full-fledged validation adapter, although it doesn’t do anything yet.  There are two methods you can override to add functionality, IEnumerable<ModelValidationResult> Validate(object container) and IEnumerable<ModelClientValidationRule> GetClientValidationRules().  Adding logic to the server-side Validate() method is pretty straightforward, and for this post I’m going to focus on GetClientValidationRules().

Adding a Client Validation Rule

Adding client validation is now incredibly easy because jquery.validate is very powerful and already comes with a ton of validators (including date and regular expressions for our email example).  Teamed with the new unobtrusive validation javascript support we can make short work of our ModelClientValidationDateRule:

public class ModelClientValidationDateRule : ModelClientValidationRule
{
    public ModelClientValidationDateRule(string errorMessage)
    {
        ErrorMessage = errorMessage;
        ValidationType = "date";
    }
}

If your validation has additional parameters you can the ValidationParameters IDictionary<string,object> to include them.  There is a little bit of conventions magic going on here, but the distilled version is that we are defining a “date” validation type, which will be included as html5 data-* attributes (specifically data-val-date).  Then jquery.validate.unobtrusive takes this attribute and basically passes it along to jquery.validate, which knows how to handle date validation.

Finishing our DataTypeAttribute Adapter

Now that we have a model client validation rule, we can return it in the GetClientValidationRules() method of our DataTypeAttributeAdapter created above.  Basically I want to say if DataType.Date was provided, then return the date rule with a given error message (using ValidationAttribute.FormatErrorMessage()).  The entire adapter is below:

public class DataTypeAttributeAdapter : DataAnnotationsModelValidator<DataTypeAttribute>
{
    public DataTypeAttributeAdapter(ModelMetadata metadata, ControllerContext context, DataTypeAttribute attribute)
        : base(metadata, context, attribute) { }
 
    public override System.Collections.Generic.IEnumerable<ModelClientValidationRule> GetClientValidationRules()
    {
        if (Attribute.DataType == DataType.Date)
        {
            return new[] { new ModelClientValidationDateRule(Attribute.FormatErrorMessage(Metadata.GetDisplayName())) };
        }
 
        return base.GetClientValidationRules();
    }
}

Putting it all together

Now that we have an adapter for the DataTypeAttribute, we just need to tell ASP.NET MVC to use it.  The easiest way to do this is to use the built in DataAnnotationsModelValidatorProvider by calling RegisterAdapter() in your global.asax startup method.

DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(DataTypeAttribute), typeof(DataTypeAttributeAdapter));

Show and Tell

Let’s see this in action using a clean ASP.NET MVC 3 project.  First make sure to reference the jquery, jquery.vaidate and jquery.validate.unobtrusive scripts that you will need for client validation.

Next, let’s make a model class (note we are using the same built-in DataType() attribute that comes with System.ComponentModel.DataAnnotations).

public class DataTypeEntity
{
    [DataType(DataType.Date, ErrorMessage = "Please enter a valid date (ex: 2/14/2011)")]
    public DateTime DateTime { get; set; }
}

Then we make a create page with a strongly-typed DataTypeEntity model, the form section is shown below (notice we are just using EditorForModel):

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>Fields</legend>
 
        @Html.EditorForModel()
 
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
}

The final step is to register the adapter in our global.asax file:

DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(DataTypeAttribute), typeof(DataTypeAttributeAdapter));

Now we are ready to run the page:

image

Looking at the datetime field’s html, we see that our adapter added some data-* validation attributes:

<input type="text" value="1/1/0001" name="DateTime" id="DateTime" 
   data-val-required="The DateTime field is required." 
   data-val-date="Please enter a valid date (ex: 2/14/2011)" data-val="true" 
   class="text-box single-line valid">

Here data-val-required was added automatically because DateTime is non-nullable, and data-val-date was added by our validation adapter.  Now if we try to add an invalid date:

image

Our custom error message is displayed via client-side validation as soon as we tab out of the box.  If we didn’t include a custom validation message, the default DataTypeAttribute “The field {0} is invalid” would have been shown (of course we can change the default as well).  Note we did not specify server-side validation, but in this case we don’t have to because an invalid date will cause a server-side error during model binding.

Conclusion

I really like how easy it is to register new data annotations model validators, whether they are your own or, as in this post, supplements to existing validation attributes.  I’m still debating about whether adding the validation directly in the DataType attribute is the correct place to put it versus creating a dedicated “Date” validation attribute, but it’s nice to know either option is available and, as we’ve seen, simple to implement.

I’m also working through the nascent stages of an open source project that will create validation attribute extensions to the existing data annotations providers using similar techniques as seen above (examples: Email, Url, EqualTo, Min, Max, CreditCard, etc).  Keep an eye on this blog and subscribe to my twitter feed (@srkirkland) if you are interested for announcements.

When distributing a library you often run up against versioning problems, once facet of which is simply determining which version of that library your client is running.  Of course, each project in your solution has an AssemblyInfo.cs file which provides, among other things, the ability to set the Assembly name and version number.  Unfortunately, setting the assembly version here would require not only changing the version manually for each build (depending on your schedule), but keeping it in sync across all projects. 

There are many ways to solve this versioning problem, and in this blog post I’m going to try to explain what I think is the easiest and most flexible solution.  I will walk you through using MSBuild to create a simple build script, and I’ll even show how to (optionally) integrate with a Team City build server.  All of the code from this post can be found at https://github.com/srkirkland/BuildVersion.

Create CommonAssemblyInfo.cs

The first step is to create a common location for the repeated assembly info that is spread across all of your projects.  Create a new solution-level file (I usually create a Build/ folder in the solution root, but anywhere reachable by all your projects will do) called CommonAssemblyInfo.cs.  In here you can put any information common to all your assemblies, including the version number.  An example CommonAssemblyInfo.cs is as follows:

using System.Reflection;
using System.Resources;
using System.Runtime.InteropServices;
 
[assembly: AssemblyCompany("University of California, Davis")]
[assembly: AssemblyProduct("BuildVersionTest")]
[assembly: AssemblyCopyright("Scott Kirkland & UC Regents")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyTrademark("")]
 
[assembly: ComVisible(false)]
 
[assembly: AssemblyVersion("1.2.3.4")] //Will be replaced
 
[assembly: NeutralResourcesLanguage("en-US")]

 

Cleanup AssemblyInfo.cs & Link CommonAssemblyInfo.cs

For each of your projects, you’ll want to clean up your assembly info to contain only information that is unique to that assembly – everything else will go in the CommonAssemblyInfo.cs file.  For most of my projects, that just means setting the AssemblyTitle, though you may feel AssemblyDescription is warranted.  An example AssemblyInfo.cs file is as follows:

using System.Reflection;
 
[assembly: AssemblyTitle("BuildVersionTest")]

Next, you need to “link” the CommonAssemblyinfo.cs file into your projects right beside your newly lean AssemblyInfo.cs file.  To do this, right click on your project and choose Add | Existing Item from the context menu.  Navigate to your CommonAssemblyinfo.cs file but instead of clicking Add, click the little down-arrow next to add and choose “Add as Link.”  You should see a little link graphic similar to this:

image

We’ve actually reduced complexity a lot already, because if you build all of your assemblies will have the same common info, including the product name and our static (fake) assembly version.  Let’s take this one step further and introduce a build script.

Create an MSBuild file

What we want from the build script (for now) is basically just to have the common assembly version number changed via a parameter (eventually to be passed in by the build server) and then for the project to build.  Also we’d like to have a flexibility to define what build configuration to use (debug, release, etc).

In order to find/replace the version number, we are going to use a Regular Expression to find and replace the text within your CommonAssemblyInfo.cs file.  There are many other ways to do this using community build task add-ins, but since we want to keep it simple let’s just define the Regular Expression task manually in a new file, Build.tasks (this example taken from the NuGet build.tasks file).

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Go" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <UsingTask TaskName="RegexTransform" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
        <ParameterGroup>
            <Items ParameterType="Microsoft.Build.Framework.ITaskItem[]" />
        </ParameterGroup>
        <Task>
            <Using Namespace="System.IO" />
            <Using Namespace="System.Text.RegularExpressions" />
            <Using Namespace="Microsoft.Build.Framework" />
            <Code Type="Fragment" Language="cs">
                <![CDATA[
            foreach(ITaskItem item in Items) {
              string fileName = item.GetMetadata("FullPath");
              string find = item.GetMetadata("Find");
              string replaceWith = item.GetMetadata("ReplaceWith");
              
              if(!File.Exists(fileName)) {
                Log.LogError(null, null, null, null, 0, 0, 0, 0, String.Format("Could not find version file: {0}", fileName), new object[0]);
              }
              string content = File.ReadAllText(fileName);
              File.WriteAllText(
                fileName,
                Regex.Replace(
                  content,
                  find,
                  replaceWith
                )
              );
            }
          ]]>
            </Code>
        </Task>
    </UsingTask>
</Project>

If you glance at the code, you’ll see it’s really just going a Regex.Replace() on a given file, which is exactly what we need.

Now we are ready to write our build file, called (by convention) Build.proj.

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Go" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <Import Project="$(MSBuildProjectDirectory)\Build.tasks" />
    <PropertyGroup>
        <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
        <SolutionRoot>$(MSBuildProjectDirectory)</SolutionRoot>
    </PropertyGroup>
 
    <ItemGroup>
        <RegexTransform Include="$(SolutionRoot)\CommonAssemblyInfo.cs">
            <Find>(?&lt;major&gt;\d+)\.(?&lt;minor&gt;\d+)\.\d+\.(?&lt;revision&gt;\d+)</Find>
            <ReplaceWith>$(BUILD_NUMBER)</ReplaceWith>
        </RegexTransform>
    </ItemGroup>
 
    <Target Name="Go" DependsOnTargets="UpdateAssemblyVersion; Build">
    </Target>
 
    <Target Name="UpdateAssemblyVersion" Condition="'$(BUILD_NUMBER)' != ''">
        <RegexTransform Items="@(RegexTransform)" />
    </Target>
 
    <Target Name="Build">
        <MSBuild Projects="$(SolutionRoot)\BuildVersionTest.sln" Targets="Build" />
    </Target>
 
</Project>

Reviewing this MSBuild file, we see that by default the “Go” target will be called, which in turn depends on “UpdateAssemblyVersion” and then “Build.”  We go ahead and import the Bulid.tasks file and then setup some handy properties for setting the build configuration and solution root (in this case, my build files are in the solution root, but we might want to create a Build/ directory later).  The rest of the file flows logically, we setup the RegexTransform to match version numbers such as <major>.<minor>.1.<revision> (1.2.3.4 in our example) and replace it with a $(BUILD_NUMBER) parameter which will be supplied externally.  The first target, “UpdateAssemblyVersion” just runs the RegexTransform, and the second target, “Build” just runs the default MSBuild on our solution.

Testing the MSBuild file locally

Now we have a build file which can replace assembly version numbers and build, so let’s setup a quick batch file to be able to build locally.  To do this you simply create a file called Build.cmd and have it call MSBuild on your Build.proj file.  I’ve added a bit more flexibility so you can specify build configuration and version number, which makes your Build.cmd look as follows:

set config=%1
if "%config%" == "" (
   set config=debug
)
set version=%2
if "%version%" == "" (
   set version=2.3.4.5
)
%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild Build.proj /p:Configuration="%config%" /p:build_number="%version%"

Now if you click on the Build.cmd file, you will get a default debug build using the version 2.3.4.5.  Let’s run it in a command window with the parameters set for a release build version 2.0.1.453.

image

image 

Excellent!  We can now run one simple command and govern the build configuration and version number of our entire solution.  Each DLL produced will have the same version number, making determining which version of a library you are running very simple and accurate.

Configure the build server (TeamCity)

Of course you are not really going to want to run a build command manually every time, and typing in incrementing version numbers will also not be ideal.  A good solution is to have a computer (or set of computers) act as a build server and build your code for you, providing you a consistent environment, excellent reporting, and much more.  One of the most popular Build Servers is JetBrains’ TeamCity, and this last section will show you the few configuration parameters to use when setting up a build using your MSBuild file created earlier.  If you are using a different build server, the same principals should apply.

First, when setting up the project you want to specify the “Build Number Format,” often given in the form <major>.<minor>.<revision>.<build>.  In this case you will set major/minor manually, and optionally revision (or you can use your VCS revision number with %build.vcs.number%), and then build using the {0} wildcard.  Thus your build number format might look like this: 2.0.1.{0}.  During each build, this value will be created and passed into the $BUILD_NUMBER variable of our Build.proj file, which then uses it to decorate your assemblies with the proper version.

After setting up the build number, you must choose MSBuild as the Build Runner, then provide a path to your build file (Build.proj).  After specifying your MSBuild Version (equivalent to your .NET Framework Version), you have the option to specify targets (the default being “Go”) and additional MSBuild parameters.  The one parameter that is often useful is manually setting the configuration property (/p:Configuration="Release") if you want something other than the default (which is Debug in our example). 

Your resulting configuration will look something like this:

[Under General Settings]

image

[Build Runner Settings]

image 

Now every time your build is run, a newly incremented build version number will be generated and passed to MSBuild, which will then version your assemblies and build your solution.

 

A Quick Review

Our goal was to version our output assemblies in an automated way, and we accomplished it by performing a few quick steps:

  1. Move the common assembly information, including version, into a linked CommonAssemblyInfo.cs file
  2. Create a simple MSBuild script to replace the common assembly version number and build your solution
  3. Direct your build server to use the created MSBuild script

That’s really all there is to it.  You can find all of the code from this post at https://github.com/srkirkland/BuildVersion.

Enjoy!

Last week I gave a presentation to the UC.NET User Group which provided an overview/introduction to jQuery.  Instead of using PowerPoint I created an ASP.NET MVC website and used a jQuery presentation plugin (http://www.viget.com/inspire/jquery-presentation-plugin/) to provide slide navigation and animation, which allowed me to make the presentation very interactive.

The presentation was well received so I thought I’d make the full source code, as well as a live version of the final presentation, publicly available for anyone who is interested.

Full Source Code: http://github.com/srkirkland/jQueryPresentation

Live Presentation: https://test.caes.ucdavis.edu/jQueryPresentation

Enjoy!

 

[Example Slides]

image

 image

image

ASP.NET MVC 2 improves Model Validation in a number of ways, including the addition of client side validation (ala xVal).  If you would like more information on Model Validation in ASP.NET MVC 2, see Scott Gu’s detailed post on this subject.  Out of the box ASP.NET MVC 2 includes support for DataAnnotations, and there are some extensibility points available for plugging in your own framework.

In post series I am creating my own implementations of Model Validation using NHibernate Validator (aka NHV, part of NHibernate Contrib).  This post will focus on the client-side model validation – you can find the previous post covering server-side validation here.

Note:  If you just want to see the final code, including a sample project, go to http://github.com/srkirkland/NHValModelValidators.

The Setup – Validating Customers

Below is the simple Customer class which we will use for validation.

public class Customer : BaseObject
{
    [NotNullNotEmpty]
    [Length(10)]
    public virtual string CompanyName { get; set; }
 
    [NotNullNotEmpty(Message = "Don't forget the contact name")]
    public virtual string ContactName { get; set; }
 
    [NotNullNotEmpty]
    public virtual string Country { get; set; }
 
    [NotNullNotEmpty]
    [Pattern("^[0-9]{6}")]
    public virtual string Fax { get; set; }
 
    [Range(1, 200)]
    public virtual int Age { get; set; }
}

So we are using some NotNullNotEmpty validators, a String Length validator, a Range and a Regular Expression Pattern validator for testing.

More Setup – Getting the Validator Engine

Eventually we will need to get the validation engine in order to interact with the NHibernate Validator library, and everyone probably has a different way of getting their configured engine.  For these examples (and simplicity’s sake) I’m going to use the following engine factory:

public class ValidatorEngineFactory
{
    public static ValidatorEngine ValidatorEngine
    {
        get
        {
            if (NHibernate.Validator.Cfg.Environment.SharedEngineProvider == null)
            {
                NHibernate.Validator.Cfg.Environment.SharedEngineProvider = new NHibernateSharedEngineProvider();
            }
 
            return NHibernate.Validator.Cfg.Environment.SharedEngineProvider.GetEngine();
        }
    }
}

 

Setting up the ModelValidatorProvider

The first step towards hooking up Model Validation is to create a class which inherits from System.Web.Mvc.ModelValidatorProvider.  For added convenience and utility I am going to inherit from  System.Web.Mvc.AssociatedValidatorProvider, which is a helper class provided by MVC to find associated information from your validatable fields (in our case, we want the associated validation attributes).  This class has one method you need to override, which is: 

protected override IEnumerable<ModelValidator> GetValidators(
            ModelMetadata metadata, 
            ControllerContext context, 
            IEnumerable<Attribute> attributes
        )

What we want to do with this provider is to return a list of ModelValidators that know which ModelClientValidationRule instances are associated with the given property.  Hopefully this will all become clear over the reminder of this article.

Since we are doing client-side validation and want to utilize the exiting ASP.NET MVC2 client-size validation rules then we need a way to map the NHibernate Validator constraints to MVC2 System.Web.Mvc.ModelClientValidationRule instances.  First we will create a class to help us with the mapping:

public class RuleEmitterList<TInputBase>
{
    public delegate IEnumerable<ModelClientValidationRule> RuleEmitter(TInputBase item);
 
    private readonly List<RuleEmitter> _ruleEmitters = new List<RuleEmitter>();
 
    public void AddSingle<TSource>(Func<TSource, ModelClientValidationRule> emitter) where TSource : TInputBase
    {
        _ruleEmitters.Add(x =>
                              {
 
                                  if (x is TSource)
                                  {
                                      ModelClientValidationRule rule = emitter((TSource)x);
                                      return rule == null ? null : new[] { rule };
                                  }
                                  else
                                  {
                                      return null;
                                  }
                              });
    }
 
    public IEnumerable<ModelClientValidationRule> EmitRules(TInputBase item)
    {
        foreach (var emitter in _ruleEmitters)
        {
            var emitterResult = emitter(item);
            if (emitterResult != null)
            {
                return emitterResult;
            }
        }
 
        return new ModelClientValidationRule[] { }; //No matching emitter, so return an empty set of rules
    }
}

This RuleEmitterList will take a type and “convert” that type into ModelClientValidationRules.  This technique is similar to how xVal solved a related problem.  You will see how this is used in just a minute.

In the constructor (which is run only once) we do the mapping:

public class NHibernateValidatorClientProvider : AssociatedValidatorProvider
{
    private readonly RuleEmitterList<IRuleArgs> _ruleEmitters;
 
    /// <summary>
    /// ctor: Hook up the mappings between your attributes and model client validation rules
    /// </summary>
    public NHibernateValidatorClientProvider()
    {
        _ruleEmitters = new RuleEmitterList<IRuleArgs>();
 
        _ruleEmitters.AddSingle<NotNullNotEmptyAttribute>(x => new ModelClientValidationRequiredRule(x.Message));
        _ruleEmitters.AddSingle<NotEmptyAttribute>(x => new ModelClientValidationRequiredRule(x.Message));
        _ruleEmitters.AddSingle<NotNullAttribute>(x => new ModelClientValidationRequiredRule(x.Message));
 
        _ruleEmitters.AddSingle<LengthAttribute>(
            x => new ModelClientValidationStringLengthRule(x.Message, x.Min, x.Max));
 
        _ruleEmitters.AddSingle<MinAttribute>(x => new ModelClientValidationRangeRule(x.Message, x.Value, null));
        _ruleEmitters.AddSingle<MaxAttribute>(x => new ModelClientValidationRangeRule(x.Message, null, x.Value));
 
        _ruleEmitters.AddSingle<NHibernate.Validator.Constraints.RangeAttribute>(
            x => new ModelClientValidationRangeRule(x.Message, x.Min, x.Max));
        
        _ruleEmitters.AddSingle<PatternAttribute>(x => new ModelClientValidationRegexRule(x.Message, x.Regex));
    }

So here we decided to map IRuleArgs (an NHibernate Validator interface) to their related MVC2 ModelClientValidator*Rule instances.  NonNullNotEmptyAttribute, for instance, is really a RequiredRule. Getting slightly more complex, a MaxAttribute is really a MVC2 RangeRule with the min value set to null.  All NHibernate Validator attributes that are not mapped will be ignored.

 

Implementing the ModelValidatorProvider

So now that we have our rules mapped, we have to do the actual work of inspecting our properties and emitting rules.  To do this we will basically use the NHibernate Validator library to get the constraints for every “property” and then convert our constraints to the desired rules.

/// <summary>
/// Returns the validators for the given class metadata.  This gets called for each property.
/// </summary>
/// <returns>Yield returns client validator instances with a list of rules for the current property</returns>
protected override IEnumerable<ModelValidator> GetValidators(
    ModelMetadata metadata, 
    ControllerContext context, 
    IEnumerable<Attribute> attributes
)
{
    if (metadata.ContainerType == null) yield break; //Break if there is no metadata container
 
    var engine = ValidatorEngineFactory.ValidatorEngine;
 
    var validator = engine.GetClassValidator(metadata.ContainerType);
    var constraints = validator.GetMemberConstraints(metadata.PropertyName).OfType<IRuleArgs>();
 
    var rules = new List<ModelClientValidationRule>();
 
    foreach (var constraint in constraints) //for each constraint, emit the rules for that constraint
    {
        foreach (var validationRule in _ruleEmitters.EmitRules(constraint))
        {
            validationRule.ErrorMessage = constraint.Message; //Temporarily give validation rule the error message provided by the validator
 
            validationRule.ErrorMessage = MessageOrDefault(validationRule, metadata.PropertyName); //Get a true error message if not provided
 
            rules.Add(validationRule);
        }
    }
 
    yield return new NHibernateValidatorClientValidator(metadata, context, rules);
}

There is nothing too crazy here, but we do have to be aware that one property can have many constraints, and for each constraint we must emit the proper rule (using our ruleEmitters mapping).  Then for each validation rule we must get the proper error message (described later) and add it to our list of rules for that property.  Then we yield return a simple ModelValidator instance (called NHibernateValidatorClientValidator) which just a dumb container for presenting the rules we provided.  Let’s take a look at it:

 

Implementing The Simple ModelValidator

As mentioned above, our model validator is pretty simple since our provider did all of the work.  We store the list of ModelClientValidationRule classes that was passed in to the constructor and override the GetClientValidationRules method to return this list.  We are forced to override the Validate method as well, but here we just return an empty list since we aren’t concerned about server-size validation here.

/// <summary>
/// Simple validator class which overrides GetClientValidationRules to return a list of ModelClientValidationRules, which cause client side validation
/// </summary>
public class NHibernateValidatorClientValidator : ModelValidator
{
    public NHibernateValidatorClientValidator(ModelMetadata metadata, ControllerContext controllerContext, List<ModelClientValidationRule> rules)
        : base(metadata, controllerContext)
    {
        Rules = rules;
    }
 
    protected List<ModelClientValidationRule> Rules { get; set; }
 
    /// <summary>
    /// Simply returns the supplied list of ModelClientValidationRule instances.
    /// </summary>
    /// <returns></returns>
    public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
    {
        return Rules;
    }
 
    /// <summary>
    /// Returns an empty enumeration since this is not a server-side validator
    /// </summary>
    public override IEnumerable<ModelValidationResult> Validate(object container)
    {
        return Enumerable.Empty<ModelValidationResult>();
    }
}

 

Getting Good Error Messages

One tricky aspect of client validation is that NHV creates messages at runtime, so there isn’t a static message that can be displayed in advance.  If you provide NHibernate with a static message using the Message = ‘msg’ parameter then we can display that easily, but if no message is provided then we have to go another route.  So what I decided to do was workaround this by having the built-in System.ComponentModel.DataAnnotations validators provide the messages for me (of course, they rely on a static resource file under the covers, but it is internal and not directly accessible).

Our strategy will be to inspect the rule we have to see if the error message was provided.  If is was not provided, we will inspect the validation rule to and determine its type.  Using this type we will create a new instance of the corresponding DataAnnotations validator and use the message it provides.

protected string MessageOrDefault(ModelClientValidationRule rule, string propertyName)
{
    // We don't want to display the default {validator.*} messages
    if ((rule.ErrorMessage != null) && !rule.ErrorMessage.StartsWith("{validator."))
        return rule.ErrorMessage;
 
    switch (rule.ValidationType)
    {
        case "stringLength" :
            var maxLength = (int) rule.ValidationParameters["maximumLength"];
            return
                new StringLengthAttribute(maxLength).FormatErrorMessage(propertyName);
        case "required" :
            return new RequiredAttribute().FormatErrorMessage(propertyName);
        case "range" :
            var min = Convert.ToDouble(rule.ValidationParameters["minimum"]);
            var max = Convert.ToDouble(rule.ValidationParameters["maximum"]);
            return
                new System.ComponentModel.DataAnnotations.RangeAttribute(min, max).FormatErrorMessage(propertyName);
        case "regularExpression":
            var pattern = (string)rule.ValidationParameters["pattern"];
            return new RegularExpressionAttribute(pattern).FormatErrorMessage(propertyName);
        default:
            throw new NotSupportedException(
                "Only stringLength, Required, Range and RegularExpression validators are supported for generic error messages.  Add a custom error message or choose another validator type");
    }   

 

Hooking up the Client-Side ModelValidatorProvider

Now we have our new ModelValidationProvider but we still have to register it in the global.asax file:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
 
    RegisterRoutes(RouteTable.Routes);
 
    ModelValidatorProviders.Providers.Clear(); //Optional: Remove the default data annotations validations
 
    ModelValidatorProviders.Providers.Add(new NHibernateValidatorProvider()); //Server side validation provider
    ModelValidatorProviders.Providers.Add(new NHibernateValidatorClientProvider()); //Client side validation provider
}

The last line here is where we add our new client side NHibernateValidatorClientProvider.

 

Results – Validation In Action

Here is a quick action/view which should test many of the validators we configured above:

image

image

To show there is no magic here I used the awesome Html.EditorForModel() helper to create the form (the model was our Customer class shown at the top of this post).  The other important line is <% Html.EnableClientValidation(); %>, which tells ASP.NET MVC 2 to emit its client validation scripts (note: you’ll have to reference the proper javascript files – I used MicrosoftAjax.js and MicrosoftMvcValidaton.js).

Now let’s try to create the Customer and see what happens:

image

As expected, we fail validation and get pretty good error messages.  Note the “Don’t forget the contact name” custom message got through properly.

Let’s try typing into the company name box without hitting submit and see what happens:

image

Excellent!  So now we have fully integrated client and server side validation with ASP.NET MVC.

 

Show Me Code Or It Didn’t Happen

All of the code needed to get server and client side validation integrated with ASP.NET MVC 2, along with a sample project, can be found at http://github.com/srkirkland/NHValModelValidators.

Enjoy!

Alongside XSS (Cross Site Scripting) and SQL Injection, Cross-site Request Forgery (CSRF) attacks represent the three most common and dangerous vulnerabilities to common web applications today. CSRF attacks are probably the least well known but they are relatively easy to exploit and extremely and increasingly dangerous. For more information on CSRF attacks, see these posts by external link: Phil Haack and external link: Steve Sanderson.

The recognized solution for preventing CSRF attacks is to put a user-specific token as a hidden field inside your forms, then check that the right value was submitted. It's best to use a random value which you’ve stored in the visitor’s Session collection or into a Cookie (so an attacker can't guess the value).

ASP.NET MVC to the rescue

ASP.NET MVC provides an HTMLHelper called AntiForgeryToken(). When you call <%= Html.AntiForgeryToken() %> in a form on your page you will get a hidden input and a Cookie with a random string assigned.

Next, on your target Action you need to include [ValidateAntiForgeryToken], which handles the verification that the correct token was supplied.

Good, but we can do better

Using the AntiForgeryToken is actually quite an elegant solution, but adding [ValidateAntiForgeryToken] on all of your POST methods is not very DRY, and worse can be easily forgotten.

Let's see if we can make this easier on the program but moving from an "Opt-In" model of protection to an "Opt-Out" model.

Using AntiForgeryToken by default

In order to mandate the use of the AntiForgeryToken, we're going to create an ActionFilterAttribute which will do the anti-forgery validation on every POST request.

First, we need to create a way to Opt-Out of this behavior, so let's create a quick action filter called BypassAntiForgeryToken:

[AttributeUsage(AttributeTargets.Method, AllowMultiple=false)]
public class BypassAntiForgeryTokenAttribute : ActionFilterAttribute { }

Now we are ready to implement the main action filter which will force anti forgery validation on all post actions within any class it is defined on:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class UseAntiForgeryTokenOnPostByDefault : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (ShouldValidateAntiForgeryTokenManually(filterContext))
        {
            var authorizationContext = new AuthorizationContext(filterContext.Controller.ControllerContext);
 
            //Use the authorization of the anti forgery token, 
            //which can't be inhereted from because it is sealed
            new ValidateAntiForgeryTokenAttribute().OnAuthorization(authorizationContext);
        }
 
        base.OnActionExecuting(filterContext);
    }
 
    /// <summary>
    /// We should validate the anti forgery token manually if the following criteria are met:
    /// 1. The http method must be POST
    /// 2. There is not an existing [ValidateAntiForgeryToken] attribute on the action
    /// 3. There is no [BypassAntiForgeryToken] attribute on the action
    /// </summary>
    private static bool ShouldValidateAntiForgeryTokenManually(ActionExecutingContext filterContext)
    {
        var httpMethod = filterContext.HttpContext.Request.HttpMethod;
 
        //1. The http method must be POST
        if (httpMethod != "POST") return false;
 
        // 2. There is not an existing anti forgery token attribute on the action
        var antiForgeryAttributes = filterContext.ActionDescriptor.GetCustomAttributes(typeof(ValidateAntiForgeryTokenAttribute), false);
 
        if (antiForgeryAttributes.Length > 0) return false;
 
        // 3. There is no [BypassAntiForgeryToken] attribute on the action
        var ignoreAntiForgeryAttributes = filterContext.ActionDescriptor.GetCustomAttributes(typeof(BypassAntiForgeryTokenAttribute), false);
 
        if (ignoreAntiForgeryAttributes.Length > 0) return false;
 
        return true;
    }
}

The code above is pretty straight forward -- first we check to make sure this is a POST request, then we make sure there aren't any overriding *AntiForgeryTokenAttributes on the action being executed. If we have a candidate then we call the ValidateAntiForgeryTokenAttribute class directly and execute OnAuthorization() on the current authorization context.

Now on our base controller, you could use this new attribute to start protecting your site from CSRF vulnerabilities.

[UseAntiForgeryTokenOnPostByDefault]
public class ApplicationController : System.Web.Mvc.Controller { }
 
//Then for all of your controllers
public class HomeController : ApplicationController {}

What we accomplished

If your base controller has the new default anti-forgery token attribute on it, when you don't use <%= Html.AntiForgeryToken() %> in a form (or of course when an attacker doesn't supply one), the POST action will throw the descriptive error message "A required anti-forgery token was not supplied or was invalid". Attack foiled!

In summary, I think having an anti-CSRF policy by default is an effective way to protect your websites, and it turns out it is pretty easy to accomplish as well.

Enjoy!

More Posts Next page »