Extension Method for Custom Attributes - c#

I am working an ASP.net MVC4 website and have model & view model layer. Because of certain reasons I have different names for few properties in Model and ViewModel
Model
public partial class Project
{
public string Desc {get; set;}
}
View Model
public class ProjectViewModel
{
public string Description { get; set; }
}
Now at model layer, I need to use ViewModel name of a property if it is different. I was thinking of creating a custom attribute so that I can have something like this in models:
public partial class Project
{
[ViewModelPropertyName("Description")]
public string Desc {get;set;}
}
and use it at model layer as
string.Format("ViewModel Property Name is {0}", this.Desc.ViewModelPropertyName())
I want this to generic so that if there is no ViewModelPropertyName attribute on a property then it should return the same property name i.e. if Desc property has no attribute then it should return "Desc" only.
Here is what I tried
public class ViewModelPropertyNameAttribute : System.Attribute
{
#region Fields
string viewModelPropertyName;
#endregion
#region Properties
public string GetViewModelPropertyName()
{
return viewModelPropertyName;
}
#endregion
#region Constructor
public ViewModelPropertyNameAttribute(string propertyName)
{
this.viewModelPropertyName = propertyName;
}
#endregion
}
Need help for how to access custom attribute
Current state
public static class ModelExtensionMethods
{
public static string ViewModelPropertyName(this Object obj)
{
// ERROR: Cannot convert from 'object' to 'System.Reflect.Assembly'
System.Attribute[] attrs = System.Attribute.GetCustomAttributes(obj);
foreach (System.Attribute attr in attrs)
{
if (attr is ViewModelPropertyNameAttribute)
{
return ((ViewModelPropertyNameAttribute)attr).GetViewModelPropertyName();
}
}
return string.Empty;
}
}
But this has compile time error:

Unfortunately you can not get the attributes you used to decorate the properties by reflecting on the type of the property itself. I have therefore modified your ViewModelPropertyName(this object) Extension method slightly to take in the name of your desired property.
This method will now take in the name of the property whose attribute you wish to get. If the attribute exists it will return the value passed to its constructor, if it on the other hand, does not exist it will simply return the name of the property you passed in.
public static class ModelExtensionMethods
{
public static string ViewModelPropertyName(this object obj, string name)
{
var attributes = obj.GetType()
.GetCustomAttributes(true)
.OfType<MetadataTypeAttribute>()
.First()
.MetadataClassType
.GetProperty(name)
.GetCustomAttributes(true);
if (attributes.OfType<ViewModelPropertyNameAttribute>().Any())
{
return attributes.OfType<ViewModelPropertyNameAttribute>()
.First()
.GetViewModelPropertyName();
}
else
{
return name;
}
}
}
You can also define the following classes to test this new approach.
[MetadataType(typeof(TestClassMeta))]
class TestClass { }
class TestClassMeta
{
[ViewModelPropertyName("TheName")]
public string FirstName { get; set; }
public string LastName { get; set; }
}
Also, as you can see from the following lines of code, your ViewModelPropertyName(this object, string) Extension method will now be called on the instance of your TestClass, instead of calling it on the property itself.
class Program
{
static void Main()
{
Console.WriteLine(new TestClass().ViewModelPropertyName("FirstName"));
Console.WriteLine(new TestClass().ViewModelPropertyName("LastName"));
Console.Read();
}
}

Related

Accessing ParseFieldName Property from outside

I have a parse subclass like:
[ParseClassName("_User")]
public class RFUser : ParseUser
{
[ParseFieldName("firstname")]
public string Firstname
{
get { return GetProperty<string>(); }
set { SetProperty(value); }
}
}
Is it possible to read the ParseFieldName ("firstname") from other parts of the program?
Something like:
typeof(RFUser).ParseFieldNames.Firstname ?
You are close. The ParseClassName and ParseFieldName attributes appear to be custom attributes. If so, you can access them if you get the name of the property that is set by the attribute's constructor.
Because I do not have (or don't know I have) the DLL that defines the ParseFieldName attribute's class, I created it as follows:
public class ParseFieldName: Attribute
{
public string Name { get; set; }
public ParseFieldName(string name)
{
this.Name = name;
}
}
For reference, my RFUser class is defined as:
[ParseClassName("_User")]
public class RFUser
{
[ParseFieldName("fieldfirstname")]
public string Firstname { get; set; }
}
Elsewhere in the program, I have a class with a using System.Reflection statement and that has a method containing the following code snippet:
RFUser user = new RFUser();
var attribute = (ParseFieldName)user.GetType().GetProperty("Firstname").GetCustomAttribute(typeof(ParseFieldName));
Console.WriteLine(attribute.Name);
The value displayed in the console is fieldfirstname.
You can also access regular attributes if you substitute Attributes for GetCustomAttributes().

Sort the list in a class that is requested from the database

I have a class that contains a list of parameters. For example:
public class Container
{
public List<Parameter> Parameters { get; set; }
}
public class Parameter
{
puplic string Name {get; set;}
}
Class Сontainer obtained from the database through Entity Framework. Many classes contain Container. I need to ensure that all classes that contain Сontainer and also retrieved from the database containing the sorted list of Parameters. That is, the Container must sort Parameters or request step or immediately thereafter.
How this can be achieved?
Maybe write to the configuration
internal class ContainerConfiguration : EntityTypeConfiguration<Container>
{
public ContainerConfiguration()
{
ToTable("Container");
HasKey(p => p.Id);
... ???
}
}
Or wright in dataSet
protected override IQueryable<Container> DataSet(DbContext db)
{
return db.Set<ProcessMeasurer>()
.Include(it => it.Parameters.Select(p => p.Parameter));
}
Another option for solving the problem:
Create your attribute and specify which field to use for sorting by default:
public class DefaultOrderFieldAttribute : Attribute
{
public DefaultOrderFieldAttribute()
{
}
public string FieldName { get; set; }
}
[DefaultOrderField(FieldName = "ParameterName")]
public partial class Parameter
{
}
Write a Visitor, which in the case of detection of our attribute modifies select:
public class DefaultOrderVisitor : DefaultExpressionVisitor
{
public override DbExpression Visit(DbScanExpression expression)
{
const string NAMESPACE = "OrderTest";
var type =
Assembly.GetExecutingAssembly().GetType(string.Format("{0}.{1}", NAMESPACE, expression.Target.Name));
var attribute =
type.GetCustomAttributes(typeof (DefaultOrderFieldAttribute)).SingleOrDefault() as
DefaultOrderFieldAttribute;
if (attribute != null)
return expression.OrderBy(ex => ex.Property(attribute.FieldName));
return expression;
}
}
Put in our Visitor Interceptor:
public class DefaultOrderInterceptor : IDbCommandTreeInterceptor
{
public void TreeCreated(DbCommandTreeInterceptionContext interceptionContext)
{
if (interceptionContext.OriginalResult.DataSpace == DataSpace.SSpace)
{
var queryCommand = interceptionContext.Result as DbQueryCommandTree;
if (queryCommand != null)
{
var newQuery = queryCommand.Query.Accept(new DefaultOrderVisitor());
interceptionContext.Result = new DbQueryCommandTree(queryCommand.MetadataWorkspace,
queryCommand.DataSpace, newQuery);
}
}
}
}
and register it in the configuration (this class just has to be in the same assembly as the model):
public class EntityFrameworkConfiguration : DbConfiguration
{
public EntityFrameworkConfiguration()
{
AddInterceptor(new DefaultOrderInterceptor());
}
}
Need to work with the entity class.
If we want to sort the collection was in all the elements that comprise it, we have to change the appropriate property.
Obvious variant - creating property setter.
private List<Parameter> _parameters;
public List<Parameter> Parameters
{
get { return _parameters; }
set { _parameters = value.OrderBy(...).ToList();
}
But the behavior of the compiler (call the setter once, and the multiple callin to the getter) gave me a reason to assume that the target collection is not put in a property all at once. The items in the query is gradually added to the collection. Therefore, sorting in setter does not always work.
Therefore, we must carry out sorting the return value
get
{
if(_parameters == null) return null;
_parameters = _parameters.OrderBy(...).ToList();
return _parameters;
}
It works. But the problem is that an appeal to the getter, and hence sorting, will be carried out when EntityFramework inserts each value. This affects the performance.
The best variant that I know at the moment is to inherit all entities from the interface with the function Prepare
public interface IEntity
{
void Prepare();
}
and implement it in each class model. Models that comprise other models cause a method to prepare, for each desired properties.
public class SomeModel : IEntity
{
public CustomType SomeProperty { get; set; }
public OneMoreCustomType AnotherProrerty { get; set; }
public void Prepare()
{
SomeProperty.Prepare();
AnotherProperty.Prepare();
}
}
For the respective classes it will take appropriate action. Including sorting.
Сall a method to prepare the Сontainer (in this case) you before using.
For example, in the Business Logic (MVPVM).

Accessing a property from its attribute

Is it possible to access the type of a property from an attribute that has been implemented on to that property?
public class FooAttribute : Attribute
{
public string GetPropertyName()
{
// return ??
}
}
public class Bar
{
[FooAttribute]
public int Baz { get; set; }
}
I would like GetPropertyName() to return "Baz".
Sriram Sakthivel is correct that this is not possible but if you are using .net 4.5 you can create a workaround using the CallerMemberNameAttribute to pass the caller into the constructor of your attribute, store it and then return it from your GetPropertyName method:
public class FooAttribute : Attribute
{
public string PropertyName { get; set; }
public FooAttribute([CallerMemberName] string propertyName = null)
{
PropertyName = propertyName;
}
public string GetPropertyName()
{
return PropertyName;
}
}
This will pass the caller (the property) to the constructor of your attribute.
More details on the CallerMemberNameAttribute are available on MSDN.
What you're asking is not possible. Because Attributes and properties doesn't have "One to One" relationship. You can apply FooAttribute to any number of Properties, In such case which property you need to return from GetPropertyName method?
As I said in comments you can loop through all the types and its properties to see which are all the properties have FooAttribute but obviously that's not what you want.

Giving parameters a metatag for reflection

I would like to flag a parameter in such a way that I can read the tag via reflection. The reason I want to do this is because I am creating business layer objects that map to a database and I want to flag certain parameters as 'read-only', such as uniqueidentifier fields that are being generated in the database.
I am already iterating through the properties for filling the parameters. This is a snippet of how I'm assigning values...
foreach (var prop in this.GetType().GetProperties())
{
switch (prop.PropertyType.Name)
{
case "Int32":
int tmpInt = -1;
if (!DBNull.Value.Equals(rowFromDatabase[prop.Name]) && int.TryParse(rowFromDatabase[prop.Name].ToString(), out tmpInt))
{
prop.SetValue(sender, tmpInt);
}
break;
case "Boolean":
bool tmpBool = false;
if (!DBNull.Value.Equals(rowFromDatabase[prop.Name]) && bool.TryParse(rowFromDatabase[prop.Name].ToString(), out tmpBool))
{
prop.SetValue(sender, tmpBool);
}
break;
..............
continued...
..............
}
}
I want to be able to access some kind of metadata on a parameter that is accessible via the prop variable shown above where I can specify some kind of extra information. How can I do this?
EDIT: I'd like to set the metadata like this
[CustomTag]
public Guid ID { get; set; }
Extend the class System.Attribute then decorate your properties with your custom attributes.
For example:
public class ReadOnlyAttribute : System.Attribute
{
}
or
public class DbColumnInfoAttribute : System.Attribute
{
public string ColumnName {get; set; }
public bool Required { get; set; }
public DbColumnInfoAttribute( string name, bool req){
ColumnName = name;
Required = req;
}
}
Then use them:
public class YourClass
{
[ReadOnly]
[DbColumnInfo( "User_Name", true)]
public string UserName { get; set; }
}
To read them via Reflection:
var listOfAttrib = prop.GetCustomAttributes(typeof(MyAttribute), true);
I would recommend that ALL of your attribute classes extend a common class so you can get all custom properties without having to know the exact attribute you're looking for otherwise you'll end up having to fire multiple GetCustomAttributes

Strongly-typed Search functionality for class?

I am trying to figure out something with c# code, and I'm not 100% sure if it is possible, but I am trying to implement search functionality for several classes which is streamlined and overall easy to develop for. Right now I have the following code:
[DataContract(IsReference = true), Serializable]
public class ClassSearch
{
[DataMember]
public string Name { get; set; }
[DataMember]
public object Value { get; set; }
public override string ToString()
{
return String.Format("{0} = {1}", Name, Value);
}
... // additional logic
}
However, I would like to include strong typing for the object value so that it only can be set to the property that is passed in, I guess like similar (hypothetical, not sure if this would work)
[DataContract(IsReference = true), Serializable]
public class ClassSearch<TProperty>
{
[DataMember]
public TProperty Property {get; set; }
public override string ToString()
{
return String.Format("{0} = '{1}'", Property.Name, Property);
}
... // additional logic
}
public class MainClass
{
public void Execute()
{
SomeClass someClass = new Class{
Property = "Value";
};
ClassSearch search = new ClassSearch<SomeClass.Property>{
Property = someClass.Property
};
var retString = search.ToString(); // Returns "Property = 'Value'"
}
}
It seems you are trying to create a WCF service to be able to pass any type you like.
First of all, this is not WSDL-friendly. All WCF services needs to be able to be exposed in WSDL. WSDL is all about well-defined contracts hence the types need be all defined. So that generic approach would not work - mainly because of WSDL. Having said that, you still can use generics but then you have to use KnownType and actually define all the types possible - which for me defeats the object.
Yet, one thing you can do is to serialize the object yourself and pass around with its type name across the wire. On the other side, you can pick it up deserialize.
So something along the line of:
// NOTE: Not meant for production!
[DataContract]
public class GenericWcfPayload
{
[DataMember]
public byte[] Payload {get; set;}
[DataMember]
public string TypeName {get; set;}
}
If there are no easier answers I would try it with this one.
You could use expressions like so:
// Sample object with a property.
SomeClass someClass = new SomeClass{Property = "Value"};
// Create the member expression.
Expression<Func<object /*prop owner object*/, object/*prop value*/>> e =
owner => ((SomeClass)owner).Property;
// Get property name by analyzing expression.
string propName = ((MemberExpression)e.Body).Member.Name;
// Get property value by compiling and running expression.
object propValue = e.Compile().Invoke(someClass);
You hand over your property by the member expression owner => ((SomeClass)owner).Property. This expression contains both information you need: property name and property value. The last two lines show you how to get name and value.
Following a larger example:
class MainClass
{
public static void Execute()
{
SomeClass someClass = new SomeClass{
Property = "Value"
};
var search = new ClassSearch(s => ((SomeClass)s).Property);
Console.Out.WriteLine("{0} = '{1}'", search.Property.Name, search.Property.GetValue(someClass));
}
}
class Reflector
{
public static string GetPropertyName(Expression<Func<object, object>> e)
{
if (e.Body.NodeType != ExpressionType.MemberAccess)
{
throw new ArgumentException("Wrong expression!");
}
MemberExpression me = ((MemberExpression) e.Body);
return me.Member.Name;
}
}
class ClassSearch
{
public ClassSearch(Expression<Func<object, object>> e)
{
Property = new PropertyNameAndValue(e);
}
public PropertyNameAndValue Property { get; private set; }
public override string ToString()
{
return String.Format("{0} = '{1}'", Property.Name, Property);
}
}
class PropertyNameAndValue
{
private readonly Func<object, object> _func;
public PropertyNameAndValue(Expression<Func<object, object>> e)
{
_func = e.Compile();
Name = Reflector.GetPropertyName(e);
}
public object GetValue(object propOwner)
{
return _func.Invoke(propOwner);
}
public string Name { get; private set; }
}
class SomeClass
{
public string Property { get; set; }
}
The main part of that example is the method Reflector.GetPropertyName(...) that returns the name of a property within an expression. I.e. Reflector.GetPropertyName(s => ((SomeClass)s).Property) would return "Property".
The advantage is: This is type-safe because in new ClassSearch(s => s.Property) compiling would end with an error if SomeClass would not have a property 'Property'.
The disadvantage is: This is not type-safe because if you write e.g. new ClassSearch(s => s.Method()) and there would be a method 'Method' then there would be no compile error but a runtime error.

Categories