Link here

Link here

xVal - a validation framework for ASP.NET MVC

ASP.NET, MVC, Validation, xVal 128 Comments »
Update: The version of xVal presented in this post (and in its downloadable demo project) has been superseded by a newer version with extra features. This post is still a good introduction to the concept, but to download the latest version of xVal please go to http://xval.codeplex.com. Thanks!

logo100pxI’ve written about validation in ASP.NET MVC more than once already. So have others (Stephen Walther, Emad Ibrahim). It’s an ongoing subject of discussion because the MVC Framework comes with great support for server-side validation (though it isn’t obvious if you come from a WebForms background), but at least as of version 1.0, it won’t ship with any built-in support for client-side validation.

I managed to get a few spare days this last week, so I decided to try and formalize lots of these ideas into something solid that you can actually use in real production code - something more than just another throwaway blog post. So here it is: xVal, an open-source project hosted on CodePlex.

What does it do?

xVal lets you link up your choice of server-side validation mechanism with your choice of client-side validation library. It guides you to fit them both into ASP.NET MVC conventions, so everything plays nicely with model binding and errors registered in ModelState.

image

The design goals are as follows:

  • Fit in with ASP.NET MVC conventions
  • Promotes a clear validation pattern that works whether or not the visitor has JavaScript enabled (graceful degradation)
  • Lets you plug in your choice of server-side validation framework or custom code. The current version includes rules providers for .NET 3.5’s built-in DataAnnotations attributes as well as Castle Validator attributes, but you can also write your own IRulesProvider to attach rules programmatically or using any other .NET validation framework.
  • Lets you plug in your choice of client-side validation library. The current version includes plugins for jQuery Validation as well as the native ASP.NET validation code (as used in WebForms), but you can use the standard JSON-based rules description format to write plugins for any other client-side validation library.
  • Supports internationalization, so you can vary the display of error messages by the current thread UI culture.
  • To be a high-quality product. xVal is built using TDD and comes with a solid set of unit tests. It uses xUnit and Moq for testing the server-side code, and Selenium RC for testing the client-side code.

The current version on Codeplex - version 0.5 – works with ASP.NET MVC Beta. It’s mostly solid and usable, though there are a few rough spots (e.g., a couple of inconsistencies to do with date formatting) that I’ll iron out soon. I also have plans to improve the internationalization somewhat to let you get error messages in other languages without having to specify them explicitly. Also, I’ll be adding support for DataAnnotations’ notion of “buddy classes” so that it works much better with the LINQ to SQL designer’s generated entity classes.

Quick tutorial

I don’t have time to document everything in xVal just yet. The basic usage pattern is supposed to be straightforward so hopefully the following tutorial won’t seem too clever or weird.

Let’s say you’ve got a model class defined as follows. Notice that we’re using attributes such as [Required], so you need to reference the System.ComponentModel.DataAnnotations.dll assembly:

public class Booking
{
    [Required] [StringLength(15)]
    public string ClientName { get; set; }
 
    [Range(1, 20)]
    public int NumberOfGuests { get; set; }
 
    [Required] [DataType(DataType.Date)]
    public DateTime ArrivalDate { get; set; }
}

You might add code to an ASP.NET MVC controller to create instances of this class:

public class HomeController : Controller
{
    [AcceptVerbs(HttpVerbs.Get)]
    public ViewResult CreateBooking()
    {
        return View();
    }
 
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult CreateBooking(Booking booking)
    {
        BookingManager.PlaceBooking(booking);
        return RedirectToAction("Completed");
    }
 
    public ViewResult Completed()
    {
        return View(); // Displays "Thanks for booking"
    }
}

This controller references some code in the domain tier that actually places bookings:

public static class BookingManager
{
    public static void PlaceBooking(Booking booking)
    {
        // Todo: save to database or whatever
    }
}

Of course, you’d also need a view for CreateBooking, containing the following markup:

<h1>Place a booking</h1>
<% using(Html.BeginForm()) { %>
    <div>
        Your name: <%= Html.TextBox("booking.ClientName") %>
        <%= Html.ValidationMessage("booking.ClientName") %>
    </div>
    <div>
        Number of guests: <%= Html.TextBox("booking.NumberOfGuests")%>
        <%= Html.ValidationMessage("booking.NumberOfGuests")%>
    </div>
    <div>
        Expected arrival date: <%= Html.TextBox("booking.ArrivalDate")%>
        <%= Html.ValidationMessage("booking.ArrivalDate")%>
    </div>                
 
    <input type="submit" />
<% } %>

This is all fine, but so far, no validation is enforced.

Enforcing server-side validation

As I’ve discussed before, validation rules should go in your domain model, because the role of your model is to represent the workings of your business. It ensures that the rules will be enforced consistently, regardless of whether the UI coder remembers them or not.

At this point, reference xVal in both your domain model project and in your ASP.NET MVC project.

Let’s update BookingManager.PlaceBooking():

public static class BookingManager
{
    public static void PlaceBooking(Booking booking)
    {
        var errors = DataAnnotationsValidationRunner.GetErrors(booking);
        if (errors.Any())
            throw new RulesException(errors);
 
        // Business rule: Can't place bookings on Sundays
        if(booking.ArrivalDate.DayOfWeek == DayOfWeek.Sunday)
            throw new RulesException("ArrivalDate", "Bookings are not permitted on Sundays", booking);
 
        // Todo: save to database or whatever
    }
}

Now, the model tier enforces its own validity by refusing to place bookings that don’t meet all validation and business rules. It throws a special type of exception, RulesException (defined in the xVal assembly) that passes structured error information back to the caller.

Aside: The best way of thinking about business rules, in my opinion, is that you’re validating an operation (i.e., a unit of work). For example, “documents can only be published when they have been approved by someone in the Moderator role” – this is an act of validation on the operation of publishing.

The DataAnnotations attributes don’t come with a validation runner. Here’s a very simple (and slightly naive one) referenced by the previous code block:

internal static class DataAnnotationsValidationRunner
{
    public static IEnumerable<ErrorInfo> GetErrors(object instance)
    {
        return from prop in TypeDescriptor.GetProperties(instance).Cast<PropertyDescriptor>()
               from attribute in prop.Attributes.OfType<ValidationAttribute>()
               where !attribute.IsValid(prop.GetValue(instance))
               select new ErrorInfo(prop.Name, attribute.FormatErrorMessage(string.Empty), instance);
    }
}

Finally, let’s fit in with ASP.NET MVC conventions by transferring any detected errors to ModelState:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreateBooking(Booking booking)
{
    try {
        BookingManager.PlaceBooking(booking);                
    }
    catch(RulesException ex) {
        ex.AddModelStateErrors(ModelState, "booking");
    }
 
    return ModelState.IsValid ? RedirectToAction("Completed")
                              : (ActionResult) View();
}

Now, because we already have Html.ValidationMessage() helpers in the view, our error messages will appear:

image

This is the essence of server-side validation. You validate requested operations, both in terms of model properties and arbitrary business rules expressed in C# code, and if anything is bad, you put the error information into ModelState and then re-render the view.

So far, we’ve only used xVal as a way of transferring error information from the model tier to the UI tier. The clever bit happens when we want to add client-side validation.

Applying client-side validation

xVal comes with support for native ASP.NET client-side validation and jQuery Validation. Let’s use jQuery Validation. Add jquery.validate.js (which you can download here) and xVal.jquery.validate.js (included in xVal) to your /Scripts folder, then add references in your master page:

<head>
    <script type="text/javascript" src="<%= ResolveUrl("~/Scripts/jquery-1.2.6.js")%>"></script>
    <script type="text/javascript" src="<%= ResolveUrl("~/Scripts/jquery.validate.js")%>"></script>
    <script type="text/javascript" src="<%= ResolveUrl("~/Scripts/xVal.jquery.validate.js")%>"></script>
</head>

Also, import xVal’s HTML helpers by adding the following line to your web.config’s <namespaces> node:

<system.web>
  <pages>
     <namespaces>
        <!-- leave rest as-is -->
        <add namespace="xVal.Html"/>
    </namespaces>
  </pages>
</system.web>

Now, all you have to do is tell xVal that you want to apply client-side validation to the controls with IDs prefixed by “booking.”. Add the following line to your view:

<%= Html.ClientSideValidation<Booking>("booking") %>

That’s it! jQuery Validation will now receive and enforce the rules defined by attributes.

image

Of course, if someone has JavaScript turned off, they’ll still be subject to the server-side validation enforced in the model tier. Also, the business rule about not allowing bookings on Sundays will still be enforced on the server either way.

Changing client-side validation libraries

If you decide you don’t like jQuery Validation, it’s trivial to switch to a different client-side library as long as you have an xVal plugin for it. For example, to switch to native ASP.NET validation, just remove the reference to xVal.jquery.validate.js (and the other jQuery references if you want), and reference the following instead:

<script type="text/javascript" src="<%= Page.ClientScript.GetWebResourceUrl(typeof(System.Web.UI.Page), "WebForms.js") %>"></script>
<script type="text/javascript" src="<%= Page.ClientScript.GetWebResourceUrl(typeof(System.Web.UI.Page), "WebUIValidation.js") %>"></script>    
<script type="text/javascript" src="<%= ResolveUrl("~/Scripts/xVal.AspNetNative.js")%>"></script>

Job done! You’re now using the native ASP.NET client-side validation libraries (as used by WebForms) and don’t need to use jQuery.

Download the finished demo project

What next

Over the next few weeks, I’ll try to find time to document the following features:

  • How to add custom validation logic that works both on the server and on the client
  • How to supply validation rules programatically or explicitly (i.e., if attributes on properties don’t meet your needs, or if you don’t like model-based validation)
  • How to internationalize your validation messages
  • How to write an IRulesProvider or a plugin for a client-side validation library
  • How to control the placement of validation messages
  • How to reuse a single rules configuration across multiple groups of form controls (e.g., when editing a list)

Comments and questions are appreciated, as well as offers to contribute to the xVal project! (For example, you could write a provider or plugin for a different server-side or client-side validation toolkit.)

In case it wasn’t obvious, xVal is hosted on CodePlex at http://xval.codeplex.com/. It’s open source, under the MS-PL license.

Thoughts on validation in ASP.NET MVC applications

ASP.NET, MVC, Validation 45 Comments »

A couple of months back, I supplied some code for doing model-based validation in an ASP.NET MVC application in a way that automatically generates client-side validation JavaScript. That was pretty popular. Lots of people are enthusiastic about expressing validation rules as attributes on model properties. However, ASP.NET MVC has been enhanced since then, and so have my views on what constitutes tidy and effective validation.

So, let’s start with the new technology. MVC Preview 5 comes with two new API pieces that seem relevant to validation:

  • ModelState. Controllers now have an official way to pass validation error information to views. Populate ViewData.ModelState, then you can use the built-in HTML helpers to render error message summaries, and to highlight input fields that correspond to errors.
  • Model binders. Controllers are expected to populate model objects from form posts using the IModelBinder API. You can create custom binders - the framework calls your binder to obtain a value for each model property. (If you don’t understand this, don’t worry - it turns out not to be relevant.)

The obvious thing to do (and I’ve seen several forum posts and blog comments suggest this) is to make a custom model binder that applies validation rules (maybe ones expressed as attributes on model properties, such as [IsRequired]) and populates ModelState with any errors it finds. However, there are technical issues that make such a design unworkable in Preview 5 (model binders don’t get told what type of model object they’re providing values for). And more importantly than the current technical issues, that sort of design would be totally undesirable anyway. Validation has nothing to do with controllers binding form posts to model objects, as I’ll explain.

In the last week, Scott Guthrie posted about handling form posting/validation scenarios in ASP.NET MVC, and so did Stephen Walther. The following design has some things in common with each of their designs, but some important differences too.

Basic principles

So, how do you design a pattern for validation? Like any design, start by deciding what characteristics are really important to you, and build from there. Here’s what I consider to be important truths of validation:

  1. Model objects should perform and enforce validation at the appropriate time.
  2. Validation rules should be expressible in plain old C#.
  3. Validation rules and business rules are at opposite ends of the same spectrum.
  4. Errors should bubble up to the UI automatically (no code needed).
  5. Client-side validation is optional - it’s purely for convenience.

And what does that mean?

[1] says that model objects don’t merely hold validation rules (e.g., as attributes on their properties), but model objects also actually enforce those rules. So, it’s not acceptable for a controller class to make the decision to validate (as they do in many other examples) - that would undermine the model’s encapsulation, and would mean that a badly-behaved controller could choose to skip validation. It’s the model that enforces validation, and it does so at a time of its own choosing - usually when something is being committed (e.g., when the model object is being saved to the database), but it might also choose to validate simple property formatting rules during property setters.

Now, if the model is capable of enforcing validation at a time of its own choosing, then it needs a general-purpose mechanism to forcibly abort certain controller operations when validation rules are violated. Fortunately, C# comes with the perfect mechanism: exceptions. There’s nothing clever about this (simplicity is the goal) - when the model decides it won’t allow an operation, it throws an exception. The operation is forcibly aborted. The controller must obey.

Also, bear in mind that certain validation rules can only be enforced at the point of committing data or finalizing actions. For example, “usernames must be unique” will probably be enforced in your database (with a UNIQUE constraint). You therefore can’t rely on a single “validation” moment - the model has to be free to issue rule exceptions at any point during its processing, and the controller shouldn’t need any special-case logic to deal with this. This requirement fits quite easily into the following design.

[2] just says that I don’t want to rely on any kind of rules engine. Now I’m perfectly happy to have reusable attributes to represent certain simple property formatting rules (e.g., [IsRequired], [DataFormat(Formats.EmailAddress)]), and you could even build a custom rules engine, but these are built on the fact that arbitrary C# is allowed.

[3] tries to clarify that simple property formatting rules (e.g., must be valid SSN) are a good start, but not adequate on their own. Certain business rules describe whether or not an operation is allowed (e.g., usernames must be unique), might relate to interactions of multiple properties, might involve arbitrarily complex logic, and these ought to fit into the validation framework too. See the diagram below.

image_thumb2

[4] is about making the system easy to maintain. When I add a new validation rule to my model, I want all controllers/views that work on that model type to render suitable error messages automatically, without changing any controller/view code.

Now, remember that when the model decides some rule has been violated, it throws an exception. If that exception is of some special type (let’s call it BusinessRuleException), then that exception can describe in some strongly-typed way which rule was validated and how. In fact, it can describe multiple rule validations simultaneously. All we need now is for controllers to catch BusinessRuleExceptions, use them to populate ViewData.ModelState, then ASP.NET MVC’s built-in helpers will take care of displaying the messages. We can do localization in this step too, for multilingual error messages.

[5] says that it’s nice to have a helper to generate client-side validation code automatically, but the helper doesn’t have to replicate every rule on the client. Obviously, since we’re allowing arbitrary C# rules, there’s no automatic translation of arbitrary rules to JavaScript. Sometimes client-side validation is impossible anyway (e.g., “usernames must be unique”). However, if some simple property formatting rules are implemented as attributes (e.g., [IsRequired]), then we can generate client-side code from these attributes. It won’t cover all rules, but it will cover many of them, and that’s good enough.

Time for some code plz

Yes I know - reading English is hard work. Far easier if I show you some C# code. Here’s how a model class might look:

public class Person
{
    [Required] [StringLength(20)] 
    public string Name { get; set; }
 
    [Required] [Range(1, 200)] 
    public int? Age { get; set; }
 
    public void EnsureValid()
    {
        // If any of this object's property values conflicts with a validation [Attribute],
        // it will add an entry to the violations collection
        RuleViolations violations = ValidationHelpers.RunValidationAttributes(this);
 
        // Now we can run any other custom C# validation logic
        if(Age.HasValue && ((DateTime.Now.Year - Age.Value) % 4 == 0))
            violations.Add(new ArbitraryViolation("Age", "Sorry, you were probably born on a leap year, so we won't let you register."));
 
        if (!violations.IsEmpty)
            throw new BusinessRuleException(violations);
    }
}
 
public static class PersonRepository
{
    public static void SavePerson(Person person)
    {
        // The model is reponsible for deciding when to validation.
        // It chooses to validate now. If there's a violation, it will
        // throw an exception
        person.EnsureValid();
 
        // Good - it was valid. Todo: now save to database
    }
}

As you can see, there are some simple property format rules implemented using attributes (these are the standard ones shipped in System.ComponentModel.DataAnnotations), but these are just a special case. You can of course use arbitrary C# logic when enforcing validation.

I don’t need to have a special method marked as the validation method (or an IValidatable interface or anything like that), because the model layer makes its own decision when to validate, and chooses how to do that. It just has to throw a BusinessRuleException if there’s a problem. In this example, it chooses to enforce validation before writing to the database, but you could choose to validate certain properties during their setter methods if you wanted.

Next, how does a controller look? It follows a general pattern like the following. The critical bit is that model operations are wrapped in a try…catch so that it can recover from errors and display suitable UI feedback.

public class RegistrationController : Controller
{
    [AcceptVerbs("GET")]
    public ViewResult Edit() { return View(new Person()); }
 
    [AcceptVerbs("POST")]
    public ActionResult Edit(string unused)
    {
        Person model = new Person();
        try
        {
            if (!TryUpdateModel(model, new[] { "Name", "Age" })) // At some point it may be possible to have a custom binder that throws a BusinessRuleException if there were setter exceptions, but as of Preview 5, have to use the slightly hacky TryUpdateModel()
                throw new BusinessRuleException();
 
            // The real validation happens to be enforced by the model here, but that's no concern for the controller
            PersonRepository.SavePerson(model);
 
            // The operation completed successfully (so validation must have passed)
            return RedirectToAction("Completed");
        }
        catch (BusinessRuleException ex)
        {
            // Generate suitable localized UI feedback based on exception that was thrown
            ex.AddToModelState(ViewData.ModelState);
            // Re-render edit screen
            return View(model);
        }
    }
}

Notice the call to ex.AddToModelState(ViewData.ModelState);. I’ve implemented that as an extension method on BusinessRuleException (so as not to mix ASP.NET MVC concerns with the core BusinessRuleException class) - it simply iterates through the list of RuleViolations objects, and generates/adds some localized UI feedback to ViewData.ModelState for each violation.

I haven’t included the full source code here because it’s still all a bit proof-of-concept, but it’s not too hard to fill in the gaps and get a working implementation.

image

And what of client-side validation?

As we discussed earlier, not all rules can be translated to client-side validation code. However, since some of the simpler rules (those on the green end of the validation-businessrule spectrum) are often implemented as System.ComponentModel.DataAnnotations attributes, it would be a straightforward job to make a Html.ClientSideValidation(object model) helper that dynamically generates suitable validation JavaScript. This bit is essentially the same as what I implemented in my previous MVC validation post.

Of course, you could have a pluggable system to generate a JS validation configuration suitable for multiple client-side validation frameworks.

About setter exceptions

As mentioned earlier, sometimes it’s desirable to enforce validation rules in property setters. This gives you solid assurance that your model object can’t have invalid property values, because when *any* code (an MVC controller or model binder, or some other domain or service code) tries to manipulate the model object, they’ll never get away with setting invalid property values. This strategy applies only to simple individual property formatting rules (the green end of the spectrum).

When setters throw exceptions, MVC Preview 5’s DefaultModelBinder is clever enough to capture them one property at a time, building up a ModelState structure. Unfortunately, at present, it disregards the exception type, so you can’t use it to generate suitable UI feedback later. I’ve asked for this to be fixed - let’s be optimistic that the MVC team will give tighter support for setter exceptions in the next update.

Now, here’s an interesting twist. If we want some validation rules to be enforced in setters, and those rules are expressed as [Attributes], then wouldn’t it be cool if that logic was automatically injected into the setter by the attribute? This gets us into aspect-oriented programming territory (AOP). Unfortunately the .NET CLR doesn’t have much support for AOP. PostSharp is the best option we’ve got, but it does require a special code compilation process.

If instead of using the System.ComponentModel.DataAnnotations attributes we used custom attributes, then they could implement PostSharp’s special interfaces. Then, when you compile with PostSharp, the attribute’s simple validation logic can automatically get injected into the property setter. However, if you don’t compile with PostSharp, then the logic wouldn’t automatically get injected into the setter, and you’d cleanly fall back on the behavior I showed earlier in this post.

Of course, this would only be useful if ASP.NET MVC gets better support for setter exceptions.

So, would you do validation like this?

Long post… sorry! Dear readers, I’d be very pleased to hear of any feedback on this design. If there’s any consensus on how it should work, then I or someone else could work it up into a downloadable reusable set of components and classes. This would include:

  • The BusinessRuleException class that you can throw from your model layer to signal and describe arbitrary invalid user actions. It would hold a set of strongly-typed RuleViolation classes (e.g., RequiredFieldViolation, StringLengthViolation) that your controller or view can use to generate localized UI feedback
  • Support for running System.ComponentModel.DataAnnotations attributes against a model object, to produce a collection of RuleViolation objects if there were problems
  • A custom model binder that knows how to generate and throw a suitable BusinessRuleException if there were setter exceptions
  • A helper for generating client-side validation code based on System.ComponentModel.DataAnnotations attributes (perhaps supporting multiple JS validation libraries)
Site Meter