views:

282

answers:

2

I'm actually fine with using another validation method. It seems there aren't many options prebuilt for doing validation with ASP.NET MVC 1.0. The main thing I see people talking about is xVal. However, there is literally no documentation for it. In fact, the blog of the founder seems to only have like two posts on it.

Anyway, it's the only thing I've seen that can also provide client validation. My issue is that I cannot use attribute based stuff because I'm generating my models using LLBLGen and I don't want to modify the code.

Everything I've read about xVal talks about the possibility of implementing an IRulesProvider but no real info of how to go about doing that and using it. I've found some code that implements it but using attributes which I can't really do.

So can anyone provide some guidance on how to use xVal if I'm not hand coding my model classes or going to use DataAnnotations or something similar (I'm open to an alternative to xVal but I haven't seen anything and I need to stick with ASP.NET MVC 1.0 and I need client side validation support)?

Edit: I don't think a partial class approach will work for me because I will be generating the code a lot and they will be in different assemblies.

+4  A: 

You can use xVal with LLBLGen or any other ORM generated classes by using the MetadataType attribute on a partial class. For example if you have a LLBL generated entity called UserEntity you would create a partial class and mark it up with a MetadataType attribute like this:

[MetadataType(typeof(UserEntityMetaData))]
public partial class UserEntity
{
}

You will than create the Meta class where you can markup the properties with the appropriate attributes like this:

public class UserEntityMetaData
{
    [Required()]
    [StringLength(50)]
    [DataType(DataType.EmailAddress)]
    public object EmailAddress { get; set; }
    [Required()]
    [StringLength(32)]
    [DataType(DataType.Password)]
    public object Password { get; set; }
    [Required()]
    [StringLength(25)]
    public object FirstName { get; set; }
    [Required()]
    [StringLength(25)]
    public object LastName { get; set; }
}

This will allow you to not have to change the LLBL generated code, just your custom partial classes. The only catch is that you will want both the partial class and the Meta class in the same namespace as the generated entity classes. You do not have to do this, but it makes things easier when you call the xVal validation.

Jace Rhea
+1  A: 

In addition to what jcerhea said you also need to modify how the DataAnnotationsValidationRunner class is set up to handle the "buddy" classes in the GetErrors method, e.g.

    namespace Entities
    {
        public static class DataAnnotationsValidationRunner
        {
            public static IEnumerable<ErrorInfo> GetErrors(object instance)
            {
                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>();

                return 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(string.Empty), instance);
            }
        }
    }
Turnkey