Пользовательский помощник Html, который может просматривать DataAnnotations

Скажем, у меня есть такая модель

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

}

Я хочу создать Html-помощник следующим образом:

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

чтобы он выдавал текстовое поле с правильным форматом для плагина jQuery Vaidation, чтобы его можно было проверить, например:

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

Из моих исследований кажется, что нет способа перебрать все аннотации данных в MetaDataModel, чтобы я мог проверить, какие из них применимы к проверке jQuery.

Как я предполагаю, что он работает в псевдокоде:

    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;
       }
    }

Как я могу найти помощника, подобного этому? Я хочу, чтобы он работал над аннотациями данных, так что мне не нужно дублировать литералы проверки.

Например, текущие Html-помощники, такие как TextEditorFor, добавляют в свои выходные поля атрибуты validatable. Как это сделать и как я могу выполнить свою собственную реализацию?

Приветствия

Ответ 1

Вы можете использовать это простое условие:

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

UPDATE

Определите html-помощник:

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

Создайте этот вспомогательный метод:

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;
}

Теперь используйте это в 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>();

Теперь вы можете проверить атрибуты.... отдых прост.

Ответ 2

Немного изменено и извлечено в помощника.

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;
        }
    }
}