Attribute.IsDefined no ve atributos aplicados con la clase MetadataType

Si aplico atributos a una clase parcial a través del atributo MetadataType , esos atributos no se encuentran a través de Attribute.IsDefined () . ¿Alguien sabe por qué, o qué estoy haciendo mal?

A continuación se muestra un proyecto de prueba que creé para esto, pero realmente estoy tratando de aplicar atributos personalizados a una clase de entidad LINQ to SQL – como esta respuesta en esta pregunta

¡Gracias!

using System; using System.ComponentModel.DataAnnotations; using System.Reflection; namespace MetaDataTest { class Program { static void Main(string[] args) { PropertyInfo[] properties = typeof(MyTestClass).GetProperties(); foreach (PropertyInfo propertyInfo in properties) { Console.WriteLine(Attribute.IsDefined(propertyInfo, typeof(MyAttribute))); Console.WriteLine(propertyInfo.IsDefined(typeof(MyAttribute), true)); Console.WriteLine(propertyInfo.GetCustomAttributes(true).Length); // Displays: // False // False // 0 } Console.ReadLine(); } } [MetadataType(typeof(MyMeta))] public partial class MyTestClass { public string MyField { get; set; } } public class MyMeta { [MyAttribute()] public string MyField { get; set; } } [AttributeUsage(AttributeTargets.All)] public class MyAttribute : System.Attribute { } } 

El atributo MetadataType se utiliza para especificar la ayuda para especificar la información adicional sobre el objeto de datos. Para acceder a los atributos adicionales, tendría que hacer algo como lo siguiente:

 using System; using System.Linq; using System.ComponentModel.DataAnnotations; using System.Reflection; namespace MetaDataTest { class Program { static void Main(string[] args) { MetadataTypeAttribute[] metadataTypes = typeof(MyTestClass).GetCustomAttributes(typeof(MetadataTypeAttribute), true).OfType().ToArray(); MetadataTypeAttribute metadata = metadataTypes.FirstOrDefault(); if (metadata != null) { PropertyInfo[] properties = metadata.MetadataClassType.GetProperties(); foreach (PropertyInfo propertyInfo in properties) { Console.WriteLine(Attribute.IsDefined(propertyInfo, typeof(MyAttribute))); Console.WriteLine(propertyInfo.IsDefined(typeof(MyAttribute), true)); Console.WriteLine(propertyInfo.GetCustomAttributes(true).Length); RequiredAttribute attrib = (RequiredAttribute)propertyInfo.GetCustomAttributes(typeof(RequiredAttribute), true)[0]; Console.WriteLine(attrib.ErrorMessage); } // Results: // True // True // 2 // MyField is Required } Console.ReadLine(); } } [MetadataType(typeof(MyMeta))] public partial class MyTestClass { public string MyField { get; set; } } public class MyMeta { [MyAttribute()] [Required(ErrorMessage="MyField is Required")] public string MyField { get; set; } } [AttributeUsage(AttributeTargets.All)] public class MyAttribute : System.Attribute { } } 

Esto también incluye un atributo de muestra para mostrar cómo extraer la información que se agregó.

Tuve una situación similar. Terminé escribiendo el siguiente método de extensión para ello. La idea es ocultar la abstracción de buscar en 2 lugares (clase principal y clase de metadatos).

  static public Tattr GetSingleAttribute(this PropertyInfo pi, bool Inherit = true) where Tattr : Attribute { var attrs = pi.GetCustomAttributes(typeof(Tattr), Inherit); if (attrs.Length > 0) return (Tattr)attrs[0]; var mt = pi.DeclaringType.GetSingleAttribute(); if (mt != null) { var pi2 = mt.MetadataClassType.GetProperty(pi.Name); if (pi2 != null) return pi2.GetSingleAttribute(Inherit); } return null; } 

Mi solución para uso genérico. Obtenga el atributo de la propiedad que busca. Devuelve nulo si no se encuentra.

Si se encuentra, devuelve el atributo en sí. Por lo tanto, puede tener acceso a las propiedades dentro del atributo si lo desea.

Espera esta ayuda.

 public static Attribute GetAttribute(this PropertyInfo PI, T t) where T: Type { var Attrs = PI.DeclaringType.GetCustomAttributes(typeof(MetadataTypeAttribute), true); if (Attrs.Length < 1) return null; var metaAttr = Attrs[0] as MetadataTypeAttribute; var metaProp = metaAttr.MetadataClassType.GetProperty(PI.Name); if (metaProp == null) return null; Attrs = metaProp.GetCustomAttributes(t, true); if (Attrs.Length < 1) return null; return Attrs[0] as Attribute; } 

Dadas las siguientes clases:

 public partial class Person { public int PersonId { get; set; } } [MetadataType(typeof(PersonMetadata))] public partial class Person { public partial class PersonMetadata { [Key] public int PersonId { get; set; } } } 

Necesitaba ver si la Key se ha definido en una propiedad para la clase Person . Entonces necesitaba obtener el valor de la propiedad. Usando la respuesta de @AdamGrid, modifiqué el código así para obtenerlo:

 private static object GetPrimaryKeyValue(TEntity entity) { MetadataTypeAttribute[] metadataTypes = typeof(TEntity).GetCustomAttributes(typeof(MetadataTypeAttribute), true).OfType().ToArray(); MetadataTypeAttribute metadata = metadataTypes.FirstOrDefault(); if (metadata == null) { ThrowNotFound(); } PropertyInfo[] properties = metadata.MetadataClassType.GetProperties(); PropertyInfo primaryKeyProperty = properties.SingleOrDefault(x => Attribute.GetCustomAttribute(x, typeof(KeyAttribute)) as KeyAttribute != null); if (primaryKeyProperty == null) { ThrowNotFound(); } object primaryKeyValue = typeof(TEntity).GetProperties().Single(x => x.Name == primaryKeyProperty.Name).GetValue(entity); return primaryKeyValue; } private static void ThrowNotFound() { throw new InvalidOperationException ($"The type {typeof(TEntity)} does not have a property with attribute KeyAttribute to indicate the primary key. You must add that attribute to one property of the class."); }