23

I have created HtmlHelper in ASP.NET MVC 4 razor view engine C#.
Can I pass view model property to my helper class?
For example, I have property

[Required]
[Display(Name = "Your Lastname")]
public string Lastname { get; set; }

Can I pass this property to my helper something like this @Html.Example(model => model.Lastname) and then get data annotations in helper (if this field is required what is display name and etc.)?

1 Answer 1

39

The [Display] attribute enriches the metadata. So you could fetch the information from the metadata.

For example if you wanted to retrieve the display name inside the helper:

public static class HtmlHelpers
{
    public static IHtmlString Example<TModel, TProperty>(
        this HtmlHelper<TModel> html, 
        Expression<Func<TModel, TProperty>> ex
    )
    {
        var metadata = ModelMetadata.FromLambdaExpression(ex, html.ViewData);
        var displayName = metadata.DisplayName;
        return new HtmlString(html.Encode(displayName));
    }
}

and then if we assume that you have a view model:

public class MyViewModel
{
    [Required]
    [Display(Name = "Your Lastname")]
    public string Lastname { get; set; }
}

you could use the helper in your strongly typed view:

@model MyViewModel

@Html.Example(x => x.Lastname)

Now let's suppose that you wrote a custom metadata attribute:

public class FooBarAttribute : Attribute, IMetadataAware
{
    public FooBarAttribute(string bar)
    {
        Bar = bar;
    }
    public string Bar { get; private set; }

    public void OnMetadataCreated(ModelMetadata metadata)
    {
        metadata.AdditionalValues["foo"] = Bar;
    }
}

that you used to decorate your model with:

public class MyViewModel
{
    [Required]
    [FooBar("This is the bar")]
    public string SomeBar { get; set; }
}

and then inside your helper you could fetch the custom attribute:

public static class HtmlHelpers
{
    public static IHtmlString Example<TModel, TProperty>(
        this HtmlHelper<TModel> html, 
        Expression<Func<TModel, TProperty>> ex
    )
    {
        var metadata = ModelMetadata.FromLambdaExpression(ex, html.ViewData);
        if (metadata.AdditionalValues.ContainsKey("foo"))
        {
            var foo = metadata.AdditionalValues["foo"] as string;
            return new HtmlString(html.Encode(foo));
        }
        return MvcHtmlString.Empty;
    }
}

UPDATE:

It seems that you need to fetch the Required message. No idea why you need to do this in a custom helper but here's an example how you could achieve that:

public static class HtmlHelpers
{
    public static IHtmlString Example<TModel, TProperty>(
        this HtmlHelper<TModel> html, 
        Expression<Func<TModel, TProperty>> ex
    )
    {
        var me = (ex.Body as MemberExpression);
        if (me != null)
        {
            var required = me
                .Member
                .GetCustomAttributes(typeof(RequiredAttribute), false)
                .Cast<RequiredAttribute>()
                .FirstOrDefault();
            if (required != null)
            {
                var msg = required.FormatErrorMessage(me.Member.Name);
                return new HtmlString(html.Encode(msg));
            }
        }
        return MvcHtmlString.Empty;
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

and can you say how i can find data-val-required message ? i want to get this messagess >>> data-val-date="The field BirthDate must be a date." data-val-required="The BirthDate field is required.
data-val-required is a client side attribute. I guess you want to fetch the message that is used by the Required attribute. I will update my answer with an example.
Thanks, and the need to get the required message is something i needed building my own custom DateTimePicker for model property. i needed to know if there was a required attribute to add markup for data-val to be true, and then use required message to set the data-val-required . So my extension helper would work with validation without any extra work. So Many Thanks for this!!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.