views:

477

answers:

3

Hi,

I have been evaluating xVal as framework for validating Entities in the ASP.Net MVC Framework. I have recently discovered that each time a validation rule is broken, xVal cause an excpetion to be thrown. To me is seems incorrect. For example, when a user fills in a form, and forgets to fill three required fields , three exceptions will be thrown. Is this good practice? ( Edit: I also read this, so I guess its not good practice)

What are your experiences of using xVal? Is there good alternative validation framework that does not throw exceptions?

Thanks

(PS: I notice that lots of people are reading this, just to let you know I am using Fluent Validation now)

+3  A: 

No it's not a good practice to show exceptions instead of some simple messages because nothing seriously has been going wrong... You should instead populate ModelState with these errors and display them on the form using

Html.ValidationMessage("EntityPropertyName");

xVal supports all these. As well as validating on the client side before the form gets posted back.

Some code

When you set DataAnnotations attributes to your entity classes (or their Metadata companion classes) you will most likely also implement Validate() method. the best way would be to use T4 that will auto generate those for you, so you don't have to repeate the same code over and over...

public IEnumerable<ErrorInfo> Validate()
{
    IList<ErrorInfo> errors = DataAnnotationsValidationRunner.GetErrors(this).ToList<ErrorInfo>();
    return errors.AsEnumerable();
}

All you have to do then is to call this:

IEnumerable<ErrorInfo> errors = entityObjectInstance.Validate();
if (errors.Any())
{
    new RulesException(errors).AddModelStateErrors(filterContext.Controller.ViewData.ModelState, entityPropertyName);
}

And to automate this even further, you can implement this in an action filter, so validation will be automatic for your entity objects that get passed into controller action. Controller actions would only need to check whether ModelState.IsValid() then.

One more class you'll need here is (and is taken from the web somewhere):

public static class DataAnnotationsValidationRunner
{
 public static IEnumerable<ErrorInfo> GetErrors(object instance)
 {
  var metadataAttribute = instance.GetType().GetCustomAttributes(typeof(MetadataTypeAttribute), true).OfType<MetadataTypeAttribute>().FirstOrDefault();
  var metaClass = metadataAttribute != null ? metadataAttribute.MetadataClassType : instance.GetType();
  var metaClassProperties = TypeDescriptor.GetProperties(metaClass).Cast<PropertyDescriptor>();
  var modelClassProperties = TypeDescriptor.GetProperties(instance.GetType()).Cast<PropertyDescriptor>();

  return from metaProp in metaClassProperties
      join modelProp in modelClassProperties on metaProp.Name equals modelProp.Name
      from attribute in metaProp.Attributes.OfType<ValidationAttribute>()
      where !attribute.IsValid(modelProp.GetValue(instance))
      select new ErrorInfo(metaProp.Name, attribute.FormatErrorMessage(string.Empty), instance);
 }
}

MVC 2

Validation in Asp.net MVC 2 Beta 2 is similar to what xVal does. So if you're not too far into the project and you can consider using code in development progress as your foundation, maybe that is the way to go for you.

Robert Koritnik
thank you for your tips Robert. A good answer, but no real not for the sample code. I have marked you up, but I did not know that about the new features in MVC 2 Beta.
Dai Bok
MVC2 features are very similar to xVal's, so there will still be some parts you'll have to do on your own to make it as automated as possible and to avoid code duplication.
Robert Koritnik
+5  A: 

Have you looked at validation in Beta 2?

http://blogs.msdn.com/rickandy/archive/2009/10/03/client-side-validation-for-mvc-2-p2.aspx

Pino
No I have not, but after a quick look, I think this will be very useful. Thank you
Dai Bok
Wen Q.
+2  A: 

I think xVal is great, I've been using it with Castle Validators and it works perfectly. Just catch the RulesException whenever you're running validation and add the errors to your ModelState, e.g.

try
{
  // execute validation runner
}
catch (RulesException ex)
{
   ex.AddModelStateErrors(ModelState, "prefix");
}

ASP.NET MVC v2 will introduce its own validation framework.

cxfx
Wen Q.