Jay Sun
Jay Sun

Reputation: 1601

Unable to get custom attributes for model properties other than string

I have a model (simplified for relevance) like this:

public abstract class TitleCreateModel : ICreateModel
{
    [Required]
    [MaxLength(400)]
    public string TitleName { get; set; }

    [Required]
    [MaxLength(4)]
    public DateTime ReleaseDate { get; set; }

    [Required]
    [MaxLength(5)]
    public string Test { get; set; }

    [Required]
    [MaxLength(2)]
    public int Wut { get; set; }
}

Then I have a custom HTML helper class and an Expression extension class (both unabridged):

public class InputHelper
{
    public static HtmlString Input<T>(Expression<Func<T, Object>> expression, string id, string label)
    {
        var req = expression.GetAttribute<T, Object, RequiredAttribute>();
        var max = expression.GetAttribute<T, Object, MaxLengthAttribute>();
        var required = "";
        var maxlength = "";
        if(req!=null)
        {
            required = "req";
        }
        if(max!=null)
        {
            maxlength = "maxlength='" + max.Length + "'";
        }
        return new HtmlString("<div class=\"clearfix\"><label for=\""+id+"\">" + label + "</label>" +
                              "<div class=\"input\"><input id=\""+id+"\" class=\""+required+"\" type=\"text\" "+maxlength+"/></div></div>");
    }
}

public static class ExpressionExtensions
{
    public static TAttribute GetAttribute<TIn, TOut, TAttribute>(this Expression<Func<TIn, TOut>> expression) where TAttribute : Attribute
    {
        var memberExpression = expression.Body as MemberExpression;
        if (memberExpression != null)
        {
            var attributes = memberExpression.Member.GetCustomAttributes(typeof(TAttribute), true);
            return attributes.Length > 0 ? attributes[0] as TAttribute : null;
        }
        return null;
    }
}

In my Razor script, I make the following calls:

@(InputHelper.Input<string>(m => Model.Title.TitleName, "titlename", "Title Name"))

@(InputHelper.Input<string>(m => Model.Title.Test, "testfield", "Test Field"))

@(InputHelper.Input<int>(m => Model.Title.Wut, "tester", "Test Field 2"))

@(InputHelper.Input<DateTime>(m => Model.Title.ReleaseDate, "release_year", "Release Year"))

For some reason, the GetAttribute method only finds the attributes for TitleName and Test, both of which are string properties for TitleCreateModel. It's unable to find the attributes for ReleaseDate and Wut, and I have no idea why.

Upvotes: 0

Views: 399

Answers (2)

Kasaku
Kasaku

Reputation: 2192

With the DateTime and int, the Expression is not of type MemberExpression, due to the boxing I believe, so this line:

var memberExpression = expression.Body as MemberExpression;

will return a null.

There's a good question and answer on this topic here, which just involves modifying your Func generic as Eranga as specified.

Upvotes: 1

Eranga
Eranga

Reputation: 32437

Modify the expression used in Input method to Expression<Func<T, TOut>> expression

public static HtmlString Input<T, TOut>(Expression<Func<T, TOut>> expression, string id, string label)
{
    var req = expression.GetAttribute<T, TOut, RequiredAttribute>();
    var max = expression.GetAttribute<T, TOut, MaxLengthAttribute>();
    var required = "";
    var maxlength = "";
    if(req!=null)
    {
        required = "req";
    }
    if(max!=null)
    {
        maxlength = "maxlength='" + max.Length + "'";
    }
    return new HtmlString("<div class=\"clearfix\"><label for=\""+id+"\">" + label + "</label>" +
                          "<div class=\"input\"><input id=\""+id+"\" class=\""+required+"\" type=\"text\" "+maxlength+"/></div></div>");
}

Upvotes: 1

Related Questions