views:

2064

answers:

6

Hello is thee any way to validate using Data Using DataAnnotations in WPF & Entity Framework?

A: 

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

Craig Stuntz
The link u provided is not applicaple in WPF, I think I mentioned that in my post.
Shimmy
+1  A: 

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.

Misha N.
In WPF, it has to be triggered per property change.
Shimmy
This is an interesting way of accomplishing it - I may revise my version (above) with some of these ideas.
Jeremy Gruenwald
+1  A: 

I had the same question and found the following ideas:

Guillaume Gros
A: 

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.

Shimmy
+2  A: 

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);
    }
}
Jeremy Gruenwald
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.
Shimmy
@Shimmy - see above.
Jeremy Gruenwald
@Jeremy, 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
@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.
Jeremy Gruenwald
A: 

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/

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