This project has moved. For the latest updates, please go here.

Issue related to the Attribute Metadata Import

Dec 22, 2011 at 2:01 AM
Edited Dec 22, 2011 at 10:51 AM

I stumbled uppon a strange Validation or MetadataType related issue. I changed the MockEntity in the WpfApplicationFramework.Test.DataErrorInfoSupportTest to match your BookLibrary.Domain.Book example.

 


 

private interface MockInterface
        {
            [Required, StringLength(30)]
            string Firstname { get; set; }

            [Required, StringLength(30)]
            string Lastname { get; set; }

            [RegularExpression(@"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$")]
            string Email { get; set; }
        }

        [MetadataType(typeof(MockInterface))]
        private class MockEntity:MockInterface
        {
            public string Firstname { get; set; }

            public string Lastname { get; set; }

            public string Email { get; set; }
        }



After the changed - test ValidateTest() Failed. Problem persists even if I am using and
importing from a MockEntityMetaData class (like in the MSDN example). I am looking into it
the whole day still no clue. Really confusing thing is that the BookLibrary.Domain.Test.BookTest
BookTitleValidationTest()
(and other tests) doesn`t fail.

What this could be related to, could someone generate it also on his computer ?
Coordinator
Dec 23, 2011 at 6:57 PM
Edited Dec 23, 2011 at 6:59 PM

When you are using the Validation attributes together with a separate MetadataType then you need some special initialization code. This initialization code can be found in the BookLibrary but not in the WpfApplicationFramework.Test project.

See: BookLibrary.Domain.Test.TestController.cs

    [TestClass]
    public class TestController
    {
        [AssemblyInitialize]
        public static void AssemblyInitialize(TestContext testContext)
        {
            TypeDescriptor.AddProviderTransparent(new AssociatedMetadataTypeTypeDescriptionProvider(typeof(EntityObject)),
                typeof(EntityObject));
        }
    }

Please note that the code above registers the needed TypeDescriptionProvider only for Types that derive from EntityObject. You might need to use another type.

Dec 23, 2011 at 11:07 PM
Edited Dec 23, 2011 at 11:12 PM

Yes, indeed. After spending the whole day I was pretty sure that it is not a Validator static class issue.
I realised that the MockEntity type itself acts strangely after I added this test: 


        
        [TestMethod]
        public void MockAttributesAreApplied()
        {
            MockEntity entity = new MockEntity();

            var query = from property in entity.GetType().GetProperties()
                        from attribute in property.GetCustomAttributes(true)
                        where (attribute.GetType() == typeof(RequiredAttribute) ||
                            attribute.GetType() == typeof(StringLengthAttribute) || 
                            attribute.GetType() == typeof(RegularExpressionAttribute)) 
                        select new { P = property, A = attribute };

            Assert.AreEqual(5, query.Count());
        }

 

It was really confusing. But now I get it. Thanks.

I find very practical the way you extended DataContext, the BookLibraryEntities. Registering the EntityObject in the constructor and the neat thing with SavingChangesHandler.

I did read the documentation to the samples but is very superficial and mostly it doesn`t offer insight on how to apply the framework. Rather it`s about how it was applied. This definitely needs to be worked on. I got a hang of it from the tests and the Call Stack, but some things are still pretty confusing.

Coordinator
Dec 27, 2011 at 11:14 AM

Thank you for the feedback about the documentation.

A comment about the “MockAttributesAreApplied” method you have posted. This won’t work with the MetadataType attribute.
You are using reflection ‘GetType()’ to retrieve the attributes attached to the properties. Reflection is the low level object introspection technique provided by the .NET Framework.

TypeDescriptor is similar to reflection but it is the high level technique for introspection. The TypeDescriptor allows introducing new virtual metadata which doesn’t exist on the real .NET object. This feature is used for the MetadataType attribute.

Here is an example which should show the difference:

public interface IPerson
{
    [Required]
    string Name { get; set; }
}
    
[MetadataType(typeof(IPerson))]
public class Person : Model, IPerson
{
    public string Name { get; set; }
}


protected override void OnStartup(StartupEventArgs e)
{
    base.OnStartup(e);

    TypeDescriptor.AddProviderTransparent(new AssociatedMetadataTypeTypeDescriptionProvider(typeof(Model)),
        typeof(Model));

    Person person = new Person() { Name = "Bill" };

    // This returns null
    var attribute1 = typeof(Person).GetProperty("Name").GetCustomAttributes(typeof(RequiredAttribute), true).Cast<Attribute>().FirstOrDefault();

    // This returns the Required attribute attached to the IPerson.Name interface member
    var attribute2 = TypeDescriptor.GetProperties(person)["Name"].Attributes[typeof(RequiredAttribute)];
}