Validation with Asp.net MVC, xVal & IDataerrorInfo

I’ve been playing around with lots of different Validation concepts recently and I think I have come up with something that will be very useful. Hopefully you will also find it useful.

Firstly I have been looking at Steve Sanderson‘s new open source project xVal and decided that it was a good place to start. I was mainly looking at server side validation but xVal can also generate script to enable client side validation.

Firstly I’ll show you how I integrated the DataAnnotations validation pack that Dynamic data uses and is available to us in 3.5sp1 as far as I know.

public class CustomValidation : IDataErrorInfo
{
    string IDataErrorInfo.Error
    {
        get
        {
            return string.Empty;
        }
    }

    string IDataErrorInfo.this[string columnName]
    {
        get
        {
            List<ErrorInfo> errors = 
                DataAnnotations.GetErrors(this, columnName).ToList();
            return errors.Count > 0 ? errors[0].ErrorMessage : null;
        }
    }
}

So I first created a class called CustomValidation that implements the IDataErrorInfo interface. From here only two Properties need to be set, the second one being the most important. Here I use the get property accessor to check the errors for each column and if there are errors I return the error message for the first error.

From here we need our Model that we want validated to inherit from this class as follows.

    public class MyProduct : CustomValidation
    {
        [Range(0, 100, ErrorMessage="{0} must be set between {1} and {2}")]
        public double? UnitPrice { get; set; }

        [StringLength(30)]
        public string ProductName { get; set; }

        public List<MyOrder> Orders { get; set; }
    }

    public class MyOrder : CustomValidation
    {
        [Required]
        public string Name { get; set; }
    }

We can then attach Validation attributes. note: you will need to add a reference to the System.ComponentModel.DataAnnotations assembly for these attributes to show up.

Once we have these two things setup we can start using it. Actually before I start I will show you the DataAnnotations.GetErrors methods.

public static class DataAnnotations
{
    public static IEnumerable<ErrorInfo> GetErrors(object instance)
    {
        return GetErrors(instance, null);
    }

    public static IEnumerable<ErrorInfo> GetErrors(object instance, string name)
    {
        var metadataAttrib = instance.GetType()
                .GetCustomAttributes(typeof(MetadataTypeAttribute), true)
                .OfType<MetadataTypeAttribute>().FirstOrDefault();
        var buddyClassOrModelClass = metadataAttrib != null 
                ? metadataAttrib.MetadataClassType 
                : instance.GetType();
        var buddyClassProperties = TypeDescriptor.GetProperties(buddyClassOrModelClass)
            .Cast<PropertyDescriptor>();
        var modelClassProperties = TypeDescriptor.GetProperties(instance.GetType())
            .Cast<PropertyDescriptor>();

        var list = from buddyProp in buddyClassProperties
                   join modelProp in modelClassProperties on 
                            buddyProp.Name equals modelProp.Name
                   from attribute in buddyProp.Attributes.OfType<ValidationAttribute>()
                   where !attribute.IsValid(modelProp.GetValue(instance))
                   select new ErrorInfo(
                       buddyProp.Name, 
                       attribute.FormatErrorMessage(modelProp.Name), 
                       instance);

        if (name != null)
            list = list.Where(x => x.PropertyName == name);

        return list;
    }
}

note: you will need the using statement and a reference to the xVal.dll
        using xVal.ServerSide;      

Now we can start.
Here is are sample controller actions. Creating a MyProduct and sending it to the view. Then accepting a MyProduct when the form gets posted back.

public ActionResult ValidationTest()
{
    MyProduct p = new MyProduct()
    {
        ProductName = "Magazine",
        UnitPrice = 23
    };

    p.Orders = new List<MyOrder>();
    p.Orders.Add(new MyOrder { Name = "Robert King" });

    return View(p);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult ValidationTest(MyProduct product)
{
    if (ModelState.IsValid)
    {
        return RedirectToAction("ValidationTest");
    }

    return View(product);
}

In the latter action method the product argument has already been validated by the time it arrives at the if statement. All that needs to be done is to check if the Modelstate is valid and if it is redirect back to the page else display the posted data back to the user with the errors in Modelstate.

Here is what the view looks like.

<h2>Custom Validation</h2>

<%= Html.ValidationSummary() %>

<% using (Html.BeginForm()) { %>

    <div style="padding-left: 15px">
        <div>
            Unit Price: <%= Html.TextBox("product.UnitPrice", Model.UnitPrice)%>
            <%= Html.ValidationMessage("product.UnitPrice")%>
        </div>
        <div>
            Product Name: <%= Html.TextBox("product.ProductName", Model.ProductName)%>
             <%= Html.ValidationMessage("product.ProductName")%>
        </div>
        <div>
            Orders: 
            <% int j = 0; 
               foreach (MyOrder o in Model.Orders) { %>
               <div  style="padding-left: 15px">
                    <%= j + 1 %>. <%= Html.TextBox("product.Orders[" + j + "].Name", o.Name)%> 
                    <%= Html.ValidationMessage("product.Orders[" + j + "].Name")%><br />
                    <% j++; %>
               </div>
            <% } %>
        </div>
    </div>
    
    <br />
    <input type="submit" />

<% } %>

Not that this even works when complex binding lists to that have been posted. I’ll try and get a full working example for download here as well if I get enough interest.

And that’s it. In upcoming posts I’ll show you how:

  • To do the validation without using the IDataErrorInfo interface and its automatic binding.
  • Use the methods that come with xVal to implement some client side validation.
  • How to create your own validation attributes.
  • Plugging in Castle Validator or other supported validators into xVal.

Hope this helps you get started with Validation in Asp.net MVC.

Cheers,
Adam

10 Responses to Validation with Asp.net MVC, xVal & IDataerrorInfo

  1. [...] Sound interesting…? Click here to keep reading [...]

  2. [...] Validation with Asp.net MVC, xVal & IDataerrorInfo [...]

  3. [...] Validation with Asp.net MVC, xVal & IDataerrorInfo [...]

  4. Laurent Bertin says:

    Hi
    Thanks for the samples about xVal validation…

    i am a newbie to asp.net mvc and was more a scripting guy than developper so i got a small question…

    in your sample you specify an ERRORINFO object but i donĀ“t find any reference of it… I spent an hour looking on google and the only references i found are

    http://msdn.microsoft.com/en-us/library/microsoft.essentialbusinessserver.console.objectmodel.errorinfo%28WS.10%29.aspx

    Based on (bad ?) intuition, i suppose the ErrorInfo class should be something like

    public class ErrorInfo
    {
    public string PropertyName { get; set; }
    public string ErrorMessage { get; set; }
    public object Instance { get; set; }

    public ErrorInfo(string _name, string _message, object _obj)
    {
    PropertyName = _name;
    ErrorMessage = _message;
    Instance = _obj;

    }
    }


    the stone was thrown in the well, just waiting to hear it touch the water before jumping in it…

    Regards,
    Laurent

  5. fahad says:

    @Laurent Bertin: ErrorInfo is located in:

    xval.serverside

  6. Danny says:

    I have had a good experience using the Validation Application Block to validate my LINQ to SQL objects. I used this article to help me through it: http://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=46.

  7. [...] a comment » jquery validation xVal Framework DataAnnotations IDataErrorInfo Enterprise Library Validation Application Block – Integrating Enterprise Library Validation [...]

  8. [...] Validation with Asp.net MVC, xVal & IDataerrorInfo | Schotime.net. Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages. [...]

  9. Another nice comment, thanks a lot. I have read more blog posts around here and I enjoyed it. Cheers.

  10. Hello there! I know this is somewhat off topic but I was wondering which blog platform are you using for this website? I’m getting sick and tired of WordPress because I’ve had problems with hackers and I’m looking at options for another platform. I would be awesome if you could point me in the direction of a good platform.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>