Question

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:

Was it helpful?

Solution

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();
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top