If I apply attributes to a partial class via the MetadataType attribute, those attributes are not found via Attribute.IsDefined(). Anyone know why, or what I'm doing wrong?
Below is a test project I created for this, but I'm really trying to apply custom attributes to a LINQ to SQL entity class - like this answer in this question.
Thanks!
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
{
}
}
The MetadataType
attribute is used to specify help specify the additional information on the data object. To access the additional attributes you would need to do something like the following:
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<MetadataTypeAttribute>().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
{
}
}
This also includes a sample attribute to show how to extract info that was added.
I had a similar situation. I ended up writing the following extension method for it. The idea is to hide the abstraction of looking in 2 places (main class and metadata class).
static public Tattr GetSingleAttribute<Tattr>(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<MetadataTypeAttribute>();
if (mt != null)
{
var pi2 = mt.MetadataClassType.GetProperty(pi.Name);
if (pi2 != null)
return pi2.GetSingleAttribute<Tattr>(Inherit);
}
return null;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With