36

Is there any way to validate using DataAnnotations in WPF & Entity Framework?

7 Answers 7

48

You can use the DataAnnotations.Validator class, as described here:

http://johan.driessen.se/archive/2009/11/18/testing-dataannotation-based-validation-in-asp.net-mvc.aspx

But if you're using a "buddy" class for the metadata, you need to register that fact before you validate, as described here:

http://forums.silverlight.net/forums/p/149264/377212.aspx

TypeDescriptor.AddProviderTransparent(
  new AssociatedMetadataTypeTypeDescriptionProvider(typeof(myEntity), 
    typeof(myEntityMetadataClass)), 
  typeof(myEntity));

List<ValidationResult> results = new List<ValidationResult>();
ValidationContext context = new ValidationContext(myEntity, null, null)
bool valid = Validator.TryValidateObject(myEntity, context, results, true);

[Added the following to respond to Shimmy's comment]

I wrote a generic method to implement the logic above, so that any object can call it:

// If the class to be validated does not have a separate metadata class, pass
// the same type for both typeparams.
public static bool IsValid<T, U>(this T obj, ref Dictionary<string, string> errors)
{
    //If metadata class type has been passed in that's different from the class to be validated, register the association
    if (typeof(T) != typeof(U))
    {
        TypeDescriptor.AddProviderTransparent(new AssociatedMetadataTypeTypeDescriptionProvider(typeof(T), typeof(U)), typeof(T));
    }

    var validationContext = new ValidationContext(obj, null, null);
    var validationResults = new List<ValidationResult>();
    Validator.TryValidateObject(obj, validationContext, validationResults, true);

    if (validationResults.Count > 0 && errors == null)
        errors = new Dictionary<string, string>(validationResults.Count);

    foreach (var validationResult in validationResults)
    {
        errors.Add(validationResult.MemberNames.First(), validationResult.ErrorMessage);
    }

    if (validationResults.Count > 0)
        return false;
    else
        return true;
}

In each object that needs to be validated, I add a call to this method:

[MetadataType(typeof(Employee.Metadata))]
public partial class Employee
{
    private sealed class Metadata
    {
        [DisplayName("Email")]
        [Email(ErrorMessage = "Please enter a valid email address.")]
        public string EmailAddress { get; set; }
    }

    public bool IsValid(ref Dictionary<string, string> errors)
    {
        return this.IsValid<Employee, Metadata>(ref errors);
        //If the Employee class didn't have a buddy class,
        //I'd just pass Employee twice:
        //return this.IsValid<Employee, Employee>(ref errors);
    }
}
Sign up to request clarification or add additional context in comments.

6 Comments

I have a gazillion classes related with MD, do you have any good idea for how to associate it with the MD dynamically, but I want to do it on demand, i.e. only when im going to use this class (or it's validation) and only once.
thank you! BTW, no need to mark the dictionary as 'ref', since you're not going to change the reference anyway, just access its properties.
@Shimmy - I pass the error dictionary as 'ref' because the IsValid function adds errors to it (initializing first if necessary), and I want to get the results back along with the bool return value.
I know this is a bit old, but this is pure gold! +1
Dictionary is a reference type (not a value type) and is always passed by reference.
|
4

I think that what is missing from Craigs answer is how to actually check if there are validation errors. This is DataAnnotation validation runner written by Steve Sanderson for those who want to run validation check in deferent layer then presentation (http://blog.codeville.net/category/xval/ , the code is in example project):

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);
}

I'm not familiar with WPF (not sure if there is some out-of-the-box solution for you question), but maybe you can use it.

Also, there are some comments on his blog that in some cases it fails to evaluate validation rule properly but it never failed for me.

2 Comments

In WPF, it has to be triggered per property change.
This is an interesting way of accomplishing it - I may revise my version (above) with some of these ideas.
3

You might be interested in the BookLibrary sample application of the WPF Application Framework (WAF). It does exactly what you are asking for: using DataAnnotations in WPF & Entity Framework.

Comments

1

I had the same question and found the following ideas:

Comments

0

Use a "buddy class". Number 4 in this how-to.

1 Comment

The link u provided is not applicaple in WPF, I think I mentioned that in my post.
0

I have written a Contributor based validator which includes a DataAnnotation validation contributor and also checks against broken bindings (where the user has entered incorrect type)

http://adammills.wordpress.com/2010/07/21/mvvm-validation-and-type-checking/

1 Comment

You forget that I was talking about edm designer generated entity objects.
0

In .NET 4, there is validation support in Entity-Framework using this extension, check out: http://blogs.msdn.com/adonet/archive/2010/01/13/introducing-the-portable-extensible-metadata.aspx

I am not sure if it does use DataAnnotations tho.

UPDATE
I tried it with VB.NET and it didn't work, I think it only supports C# projects.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.