Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom Html helper that can browse DataAnnotations

Say I have a model like this

public class User
{
    [Required]
    [StringLength(14, ErrorMessage = "Can only be 14 characters long")]
    public string UserName;

}

I want to create a Html helper like this:

@Html.ValidatableEditorFor(m => m.UserName)

so that it spits out a text field with the correct format for jQuery Vaidation plugin to be able to validate, like this:

   <input type="text" class="required" maxlength="14" />

From my research, it seems that there is no way to iterate over all the data annotations in a MetaDataModel so that I can check to see which one's are applicable to jQuery Validation.

How I envision it working in pseudo code:

    var tag = new TagBuilder("input");
    tag.mergeAttribute("type", "text");
    foreach(var attribute in metadata.attributes)
    {
       CheckForValidatableAttribute(attribute, tag);
    }

...
    private void CheckForValidatableAttribute(DataAnnotation attribute, TagBuilder tag)
    {
        switch(attribute.type)
       {
          case Required:
             tag.addClass("required");
             break;
          case StringLength
             tag.mergeAttribute("maxlength", attribute.value)
             break;
       }
    }

How could I go about achieving a helper like this? I want it to work on data annotations so that I don't have to duplicate the validation literals.

For instance, the current Html helpers like TextEditorFor do append validatable attributes to their output fields. How does it do this, and how can I make my own implementation?

Cheers

like image 364
Chris Avatar asked Apr 30 '12 10:04

Chris


People also ask

How do I use system ComponentModel DataAnnotations?

Data annotations (available as part of the System. ComponentModel. DataAnnotations namespace) are attributes that can be applied to classes or class members to specify the relationship between classes, describe how the data is to be displayed in the UI, and specify validation rules.

What is HTML helpers in MVC?

In MVC, HTML Helper can be considered as a method that returns you a string. This string can describe the specific type of detail of your requirement. Example: We can utilize the HTML Helpers to perform standard HTML tags, for example HTML<input>, and any <img> tags.

What is DataAnnotations MVC?

DataAnnotations is used to configure your model classes, which will highlight the most commonly needed configurations. DataAnnotations are also understood by a number of . NET applications, such as ASP.NET MVC, which allows these applications to leverage the same annotations for client-side validations.

What are DataAnnotations in net core?

Data Annotations attributes are . NET attributes which can be applied on an entity class or properties to override default conventions in EF 6 and EF Core. Data annotation attributes are included in the System. ComponentModel.


2 Answers

You may use this simple condition:

if(attribute.Type is ValidationAttribute)
{
   string className = attribute.Type.Name.Replace("Attribute", "").ToLower();
}

UPDATE

Define an Html helper:

public static MvcHtmlString ValidationEditorFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, 
        Expression<Func<TModel, TProperty>> expression)
{
    ....
}

Create this helper method:

private static string GetPropertyNameFromExpression<TModel, TProperty>(HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
{
    MemberExpression memberExpression = expression.Body as MemberExpression;
    if (memberExpression == null)
        throw new InvalidOperationException("Not a memberExpression");

    if (!(memberExpression.Member is PropertyInfo))
        throw new InvalidOperationException("Not a property");

    return memberExpression.Member.Name;
}

Now use this in ValidationEditorFor:

var propertyName = GetPropertyNameFromExpression(htmlHelper, expression);
var propertyType = typeof(TModel).GetProperties().Where(x=>x.Name == propertyName).First().PropertyType;
var attributes = propertyType.GetCustomAttributes(true).OfType<ValidationAttribute>();

Now you can check the attributes.... rest is easy.

like image 169
Aliostad Avatar answered Oct 05 '22 02:10

Aliostad


Slightly altered and extracted into a helper.

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace Payntbrush.Infrastructure.Web.Mvc
{
    public static class ReflectionHelper
    {
        public static IEnumerable<ValidationAttribute> GetAttributes<TModel, TProperty>(Expression<Func<TModel, TProperty>> expression)
        {
            Type type = typeof(TModel);
            var prop = type.GetProperty(GetPropertyNameFromExpression(expression));
            return prop.GetCustomAttributes(true).OfType<ValidationAttribute>();
        }


        private static string GetPropertyNameFromExpression<TModel, TProperty>(Expression<Func<TModel, TProperty>> expression)
        {
            var memberExpression = expression.Body as MemberExpression;
            if (memberExpression == null)
                throw new InvalidOperationException("Not a memberExpression");

            if (!(memberExpression.Member is PropertyInfo))
                throw new InvalidOperationException("Not a property");

            return memberExpression.Member.Name;
        }
    }
}
like image 24
Chris Avatar answered Oct 05 '22 02:10

Chris