I tried to assign a custom Attribute to class that comes from a dynamic proxy
System.Data.Entity.DynamicProxies.Login_A2947F53...
Example class Login
public partial class Login
{
[CustomAttribute]
public virtual int Id
{
get;
set;
}
}
Now I try to access the Attribute using Generics and Reflection
public static void Process(TSource source)
{
foreach (PropertyInfo p in target.GetType().GetProperties(flags))
{
object[] attr = p.GetCustomAttributes(true); // <- empty
}
}
But there is no Attribute. Is that due to the DynmaicProxy or what did I do wrong here?
When I use a concrete class without dynamic proxy like this one, then I get the attributes.
public class TestObject
{
[CustomAttribute]
public virtual string Name { get; set; }
[CustomAttribute]
public virtual string Street { get; set; }
public virtual int Age { get; set; }
public virtual string Something { get; set; }
}
OK, this one was obvious after a closer look;
System.Data.Entity.DynamicProxies.Login_A2947F53...
is a dynamicProxy type and know nothing about any Attributes. So I have to use the something like:
foreach (PropertyInfo p in typeof(Login).GetProperties(flags))
instead of the dynamicProxy instance to get the type from. And finaly there are my Attributes.
Use BaseType.
public static void Process(TSource source)
{
foreach (PropertyInfo p in target.GetType().BaseType.GetProperties(flags))
{
object[] attr = p.GetCustomAttributes(true);
}
}
Related
I have a method which takes an object as a parameter. Within that method I walk through that objects properties with reflection. Some properties are of a generic class type. I like to read a property of that generic class property, but I cannot cast it to a generic class.
public abstract class BaseClass
{
public int Id { get; set; }
}
public abstract class GenericClass<T>: BaseClass
{
public string Description { get; set; }
}
public class DerivedClassA: GenericClass<DerivedClassA>
{
public string A { get; set; }
}
public class DerivedClassB: GenericClass<DerivedClassB>
{
public string B { get; set; }
}
public class ReflectingClass: BaseClass
{
public string Code { get; set; }
public DerivedClassA DerA { get; set; }
public DerivedClassB DerB { get; set; }
}
public static void Reflecting(object obj)
{
var t = GetType(obj)
foreach (var pi in t.GetProperties())
{
if (obj.GetType().BaseType.GetGenericTypeDefinition() == typeof(GenericClass<>)
{
var genClassObjProperty = ((GenericClass<T>)obj).Description; // Error, cannot do this at all !!!
}
}
}
What I want is for the code to walk to the properties and whatever the derived class actually is get the Description property of the GenericClass it is derived from.
I am using a generic class, because elsewhere in the code I call methods by their derived class and get the proper class type without resorting to all kinds of cast and passing types. I.e:
DerivedClassA.DoSomething()
instead of
BaseClass.DoSomething<DerivedClassA>()
or
BaseClass.DoSomething(type derivedClassType)
Take a look at this:
public static void Reflecting(object obj)
{
foreach (var pi in obj.GetType().GetProperties())
{
if (pi.PropertyType.BaseType.IsGenericType
&& pi.PropertyType.BaseType.GetGenericTypeDefinition()
== typeof(GenericClass<>))
{
var propValue = pi.GetValue(obj);
if (propValue != null)
{
var description = propValue.GetType()
.GetProperty("Description").GetValue(propValue);
Console.WriteLine(description);
}
}
}
Console.ReadKey();
}
I think this is what you need.
My situation is the following:
I'm coding a MVC website on Visual Studio 2013 using database-first approach with Entity Framework.
EF automatically generates the models. But I need to add custom attributes (~NOT~ necessarily for data validation but also for internal processes) and, via reflection, access those custom attributes.
Let's say I have
public partial class Application {
public int AppID {get; set;}
public string Name {get; set;}
//etc...
}
I've tried the following approaches:
• On a different file I continue the partial class:
public partial class Application {
[MyAttributeOne]
public int AppID { get; set; }
[DataType(DataType.Text)]
[MyAttributeTwo]
public string Name { get; set; }
}
• Use the MetaData class
public class ApplicationMetadata {
[MyAttributeOne]
public int SolutionID { get; set; }
[DataType(DataType.Text)]
[MyAttributeTwo]
public string Name { get; set; }
}
[MetadataType(typeof(ApplicationMetadata))]
public partial class Application { }
• Inherit the class with attributes:
public class ApplicationMetadata {
[MyAttributeOne]
public int SolutionID { get; set; }
[DataType(DataType.Text)]
[MyAttributeTwo]
public string Name { get; set; }
}
public partial class Application : ApplicationMetadata { }
• And the 'Buddy class' approach where I do basically the previous 2 approaches but instead I define the class with the attributes inside the 'Application' class.
Am I doing something wrong? Or is this simply impossible?
I need to be able to make the following code work:
foreach (PropertyInfo propertyInfo in currentObject.GetType().GetProperties())
{
foreach (CustomAttributeData attrData in propertyInfo.GetCustomAttributesData())
{
if (typeof(attrData) == typeof(MyAttributeOne))
//stuff
else if (typeof(attrData) == typeof(MyAttributeTwo))
//different stuff
else
//yet more stuff
}
}
Thank you very much for the attention!
Regards.
OK, this is a little involved but it's fairly simple. This is also really a bit of a brain dump but it does work and gives you enough to work with. Lets set up with some basics:
//A couple of custom attributes
public class MyAttributeOne : Attribute { }
public class MyAttributeTwo : Attribute { }
//A metadata class where we can use the custom attributes
public sealed class MyEntityMetadata
{
//This property has the same name as the class it is referring to
[MyAttributeOne]
public int SomeProperty { get; set; }
}
//And an entity class where we use System.ComponentModel.DataAnnotations.MetadataType
//to tell our function where the metadata is stored
[MetadataType(typeof(MyEntityMetadata))]
public class MyEntity
{
public int SomeProperty { get; set; }
}
OK, still with me? Now we need a function to process the properties in the same way you did earlier:
public void DoStuff(object currentObject)
{
//Lets see if our entity class has associated metadata
var metaDataAttribute = currentObject.GetType()
.GetCustomAttributes()
.SingleOrDefault(a => a is MetadataTypeAttribute) as MetadataTypeAttribute;
PropertyInfo[] metaProperties = null;
//Cache the metadata properties here
if (metaDataAttribute != null)
{
metaProperties = metaDataAttribute.MetadataClassType.GetProperties();
}
//As before loop through each property...
foreach (PropertyInfo propertyInfo in currentObject.GetType().GetProperties())
{
//Refactored this out as it's called again later
ProcessAttributes(propertyInfo.GetCustomAttributes());
//Now check the metadata class
if (metaProperties != null)
{
//Look for a matching property in the metadata class
var metaPropertyInfo = metaProperties
.SingleOrDefault(p => p.Name == propertyInfo.Name);
if (metaPropertyInfo != null)
{
ProcessAttributes(metaPropertyInfo.GetCustomAttributes());
}
}
}
}
And of course, here is the refactored method to process the attributes:
private void ProcessAttributes(IEnumerable<Attribute> attributes)
{
foreach (var attr in attributes)
{
if (attr is MyAttributeOne)
{
Console.WriteLine("MyAttributeOne found");
}
else if (attr is MyAttributeTwo)
{
Console.WriteLine("MyAttributeTwo found");
}
else
{
}
}
}
Note: I'm asking about subclasses, not derived classes.
Basically, what I need to do is check properties of an object and look for those that have a specific attribute set.
The problem I have is that a lot of the properties are from subclasses
public class ExampleAttribute : Attribute
{
public object Whatever { get; set; }
}
public class MiddleEarth
{
[Example]
public Type EntityType { get; set; }
}
public class Elf : MiddleEarth
{
[Example]
public SubClass ItsLateAndImTired { get; set; }
public IList<Arg> Args { get; set; }
//Need to check properties of this object as well
public class SubClass
{
public object SubProperty { get; set; }
[Example]
public object SubPropertyWithAttribute { get; set; }
}
public class Arg
{
[Example]
public string Something { get; set; }
}
}
Now, I'm trying to do it as follows...but for reasons noted in the comments it won't work
public List<string> IterateProperties(object _o)
{
List<string> problems = new List<string>();
foreach (PropertyInfo info in _o.GetType().GetProperties())
{
//All 3 of these will return the exact same thing
Type thisType = this.GetType();
Type oType = _o.GetType();
Type infoType = info.ReflectedType;
//IsSubClassOf only checks for derived classes,
//so it's not the method I'm looking for
if (info.ReflectedType.IsSubclassOf(this.GetType()))
{
object sub = info.GetValue(_o, null);
if (sub != null)
{
problems.AddRange(this.IterateProperties(sub));
}
}
object[] attributes = info.GetCustomAttributes(typeof(ExampleAttribute), true);
foreach (object o in attributes)
{
if (info.GetValue(_o, null) == null)
{
problems.Add(String.Format("Attribute {0} in class {1} cannot be null", info.Name, info.ReflectedType.ToString()));
}
}
}
return problems;
}
Any ideas?
I believe what you're looking for is Type.GetNestedTypes()
http://msdn.microsoft.com/en-GB/library/493t6h7t.aspx
I'm not sure, but think that GetProperties method got some flags that can help...
This is in the Immediate console:
prop.GetCustomAttributes(typeof(RequiredParameterAttribute),true)
{BridgeStack.DataContracts.RequiredParameterAttribute[0]}
prop.GetCustomAttributes(typeof(RequiredParameterAttribute),true).Cast<RequiredParameterAttribute>()
{BridgeStack.DataContracts.RequiredParameterAttribute[0]}
[BridgeStack.DataContracts.RequiredParameterAttribute[]]: {BridgeStack.DataContracts.RequiredParameterAttribute[0]}
prop.GetCustomAttributes(typeof(RequiredParameterAttribute),true).Cast<RequiredParameterAttribute>().Any()
false
I get the same results in the application.
prop is Site in:
public class AnswerCollectionQuery : IPagedQuery, ISiteQuery, ISortableQuery, IOrderableQuery, IFilteredQuery
{
public int? Page { get; set; }
public int? PageSize { get; set; }
public string Site { get; set; }
[AllowedSortValues(QuerySortEnum.Activity, QuerySortEnum.Creation, QuerySortEnum.Votes)]
public QuerySortEnum? Sort { get; set; }
public object Min { get; set; }
public object Max { get; set; }
public DateTime? FromDate { get; set; }
public DateTime? ToDate { get; set; }
public QueryOrderEnum? Order { get; set; }
public string Filter { get; set; }
}
Site in turn comes from ISiteQuery
public interface ISiteQuery : IQuery
{
[RequiredParameter]
string Site { get; set; }
}
The awkward part is that the console shows the attribute, allows me to cast it, but I can't retrieve it at all, I get zero as the enumeration's length, which is why .Any() fails, too, .FirstOrDefault() returns null, .First() throws, etc.
Any explanation for this type of behavior?
PD: this works though if I decorate Site with [RequiredAttribute] in the concrete class. But I wanted to make this part of the interface.
Update for clarity:
prop comes exactly from here:
public static IEnumerable<PropertyInfo> GetAllProperiesOfObject(object o)
{
const BindingFlags flags = BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Instance;
PropertyInfo[] list = o.GetType().GetProperties(flags);
return list;
}
foreach (PropertyInfo prop in Utility.GetAllProperiesOfObject(entity))
This is the case for when prop becomes Site
The zero is because it is returning you a zero-length typed array, meaning: it doesn't have the attribute. You can also see this with Attribute.IsDefined (which will return false).
When using implicit interface implementation, the public property on the class does not automatically gain attributes from the interface that it satisfies. To see the attributes on the interface you would need to use
typeof(ITheInterface).GetProperties()
The Site property on the interface is unrelated to the Site property on the class. If the property on the class must have attributes: add the attributes explicitly.
I'm trying to validate a class using Data Annotations but with a metadata class.
[MetadataType(typeof(TestMetaData))]
public class Test
{
public string Prop { get; set; }
internal class TestMetaData
{
[Required]
public string Prop { get; set; }
}
}
[Test]
[ExpectedException(typeof(ValidationException))]
public void TestIt()
{
var invalidObject = new Test();
var context = new ValidationContext(invalidObject, null, null);
context.MemberName = "Prop";
Validator.ValidateProperty(invalidObject.Prop, context);
}
The test fails. If I ditch the metadata class and just decorated the property on the actual class it works fine. WTH am I doing wrong? This is putting me on the verge of insanity. Please help.
Answer
Here is a link to the post that helped me solve this issue. Apparently you have to register the matadata class first.
The metadata class must be public for the external validation to work.
[MetadataType(typeof(TestMetaData))]
public class Test
{
public string Prop { get; set; }
public class TestMetaData
{
[Required]
public string Prop { get; set; }
}
}
I believe defining the metadata class inside of your model class, like you did in your example, should work. Haven't tested it.