Как прочитать значение аннотации данных свойства в .NET MVC - PullRequest
4 голосов
/ 13 ноября 2011

I Я только начинаю с ASP.NET MVC 3, и я пытаюсь отобразить следующий HTML-код для свойств строки в ViewModel в представлении создания / редактирования.

<input id="PatientID" name="PatientID" placeholder="Patient ID" type="text" value="" maxlength="30" />

Каждое значение связаноВозвращаясь к свойству в ViewModel, id и name - это имя свойства, placeholder - это атрибут Display, значение - это значение свойства, а maxlength - атрибут StringLength.

Вместо того, чтобы вводить приведенный выше HTML-кодс правильными значениями для каждого из моих строковых свойств, я подумал, что я попытаюсь создать EditorTemplate с именем SingleLineTextBox и использовать UIHint в моих строковых свойствах или передать имя представления при вызове EditFor.Пока все хорошо, за исключением того, что я не могу понять, как получить значение maxlength из атрибута StringLength.

Вот код, который у меня есть:

<input id="@ViewData.ModelMetadata.PropertyName" name="@ViewData.ModelMetadata.PropertyName" placeholder="@ViewData.ModelMetadata.DisplayName" type="text" value="@ViewData.Model" maxlength="??" />

Как вы можетевидите, не знаете, как установить значение максимальной длины.Кто-нибудь знает, как?

Кроме того, я иду об этом лучшим способом?Как я уже говорил, я мог просто написать простой HTML для каждого свойства на странице.Я смотрел на использование TextBox, потому что он не устанавливал максимальную длину и добавлял кучу проверочной разметки в вывод HTML из-за атрибута StringLength, который мне не нужен.Еще одна опция, которую я видел, это расширения / помощники в классе HTML.

Ответы [ 6 ]

7 голосов
/ 25 апреля 2013

Полный пример кода для ответа tvanfosson:

Модель:

public class Product
{
    public int Id { get; set; }

    [MaxLength(200)]
    public string Name { get; set; }

EditorTemplates \ String.cshtml

@model System.String
@{
    var metadata = ViewData.ModelMetadata;
    var prop = metadata.ContainerType.GetProperty(metadata.PropertyName);
    var attrs = prop.GetCustomAttributes(false);

    var maxLength = attrs.OfType<System.ComponentModel.DataAnnotations.MaxLengthAttribute>().FirstOrDefault();
}
<input id=@Html.IdForModel()@(metadata.IsRequired ? " required" : "")@(maxLength == null ? "" : " maxlength=" + maxLength.Length) />

Вывод HTML:

<input id=Name maxlength=200 />

Ужасно, но это работает. Теперь давайте отвлечемся от этого и немного очистим. Вспомогательный класс:

public static class EditorTemplateHelper
{
    public static PropertyInfo GetPropertyInfo(ViewDataDictionary viewData)
    {
        var metadata = viewData.ModelMetadata;
        var prop = metadata.ContainerType.GetProperty(metadata.PropertyName);
        return prop;
    }

    public static object[] GetAttributes(ViewDataDictionary viewData)
    {
        var prop = GetPropertyInfo(viewData);
        var attrs = prop.GetCustomAttributes(false);
        return attrs;
    }

    public static string GenerateAttributeHtml(ViewDataDictionary viewData, IEnumerable<Delegate> attributeTemplates)
    {
        var attributeMap = attributeTemplates.ToDictionary(t => t.Method.GetParameters()[0].ParameterType, t => t);
        var attrs = GetAttributes(viewData);

        var htmlAttrs = attrs.Where(a => attributeMap.ContainsKey(a.GetType()))
            .Select(a => attributeMap[a.GetType()].DynamicInvoke(a));

        string s = String.Join(" ", htmlAttrs);
        return s;
    }
}

Шаблон редактора:

@model System.String
@using System.ComponentModel.DataAnnotations;
@using Brass9.Web.Mvc.EditorTemplateHelpers;
@{
    var metadata = ViewData.ModelMetadata;

    var attrs = EditorTemplateHelper.GenerateAttributes(ViewData, new Delegate[] {
        new Func<StringLengthAttribute, string>(len => "maxlength=" + len.MaximumLength),
        new Func<MaxLengthAttribute, string>(max => "maxlength=" + max.Length)
    });

    if (metadata.IsRequired)
    {
        attrs.Add("required");
    }

    string attrsHtml = String.Join(" ", attrs);
}
<input type=text id=@Html.IdForModel() @attrsHtml />

Таким образом, вы передаете массив делегатов, и для каждой записи используйте Func<AttributeTypeGoesHere, string>, а затем возвращаете любую строку HTML, которую вы хотите для каждого атрибута.

Это на самом деле хорошо разделяет - вы можете отобразить только те атрибуты, которые вам нужны, вы можете отобразить разные наборы для разных частей одного и того же HTML, и конечное использование (например, @attrsHtml) не повредит читабельности шаблона.

5 голосов
/ 13 ноября 2011

Вместо атрибута StringLength (поскольку это атрибут валидатора, а не поставщик метаданных), вы можете использовать атрибут AdditionalMetadata. Пример использования:

public class ViewModel
{
    [AdditionalMetadata("maxLength", 30)]
    public string Property { get; set; }
}

В основном это помещает значение 30 под ключом maxLength в словаре ViewData.ModelMetadata.AdditionalValues. Так что вы можете использовать его в своем EditorTemplate:

<input maxlength="@ViewData.ModelMetadata.AdditionalValues["maxLength"]" id="@ViewData.ModelMetadata.PropertyName" name="@ViewData.ModelMetadata.PropertyName" placeholder="@ViewData.ModelMetadata.DisplayName" type="text" value="@ViewData.Model"  />
2 голосов
/ 13 ноября 2011

Для этого вам нужно создать собственное расширение HtmlHelper и использовать отражение, чтобы получить атрибуты свойства модели.Посмотрите на исходный код http://codeplex.com/aspnet для существующих ...For() расширений HtmlHelper.Вам нужно получить объект PropertyInfo для свойства модели, используя выражение, переданное в качестве аргумента.У них есть несколько вспомогательных классов, которые должны служить шаблонами для этого.Получив это, используйте метод GetCustomAttributes в PropertyInfo, чтобы найти атрибут StringLength и извлечь его значение.Поскольку вы будете использовать TagBuilder для создания ввода, добавьте длину в качестве атрибута через TagBuilder.

   ...

   var attribute = propInfo.GetCustomAttributes(typeof(StringLengthAttribute),false)
                           .OfType<StringLengthAttribute>()
                           .FirstOrDefault();
   var length = attribute != null ? attribute.MaximumLength : 20; //provide a default
   builder.Attributes.Add("maxlength",length);

   ...

   return new MvcHtmlString( builder.ToString( TagRenderMode.SelfClosing ) );
}

См. Мой комментарий о том, почему я считаю это плохой идеей.*

0 голосов
/ 28 мая 2015
@using System.ComponentModel.DataAnnotations
@model string
@{
    var htmlAttributes = ViewData["htmlAttributes"] ?? new { @class = "checkbox-inline" };

    var attributes = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);

    if (!attributes.ContainsKey("maxlength"))
    {
        var metadata = ViewData.ModelMetadata;
        var prop = metadata.ContainerType.GetProperty(metadata.PropertyName);
        var attrs = prop.GetCustomAttributes(false);
        var maxLength = attrs.OfType<MaxLengthAttribute>().FirstOrDefault();
        if (maxLength != null)
        {
            attributes.Add("maxlength", maxLength.Length.ToString());
        }
        else
        {
            var stringLength = attrs.OfType<StringLengthAttribute>().FirstOrDefault();

            if (stringLength != null)
            {
                attributes.Add("maxlength", stringLength.MaximumLength.ToString());
            }
        }
    }

}

@Html.TextBoxFor(m => m, attributes)
0 голосов
/ 24 марта 2015

Вы можете получить StringLength Валидатор из шаблона редактора , вот несколько примеров:

https://jefferytay.wordpress.com/2011/12/20/asp-net-mvc-string-editor-template-which-handles-the-stringlength-attribute/

То, что я использовал и проверял, в результате из статьи выше, можно увидеть в моем ответе ниже ( протестировано с MVC 5 , EF 6):

ASP.NET MVC 3 - аннотации данных и максимальная длина / размер для рендеринга текстового поля

Не вдаваясь в подробности, я лично имел некоторые смешанные результаты с попытками реализовать некоторые другие подходы, и я не нахожу ни один из заявленных методов особенно долгим; Тем не менее, я думаю, что некоторые другие подходы выглядели немного «красивее».

0 голосов
/ 17 июня 2014

Гораздо более простым решением является реализация пользовательского DataAnnotationsModelMetadataProvider, например:

internal class CustomModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
    protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
    {
        ModelMetadata modelMetadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);

        var maxLengthAttribute = attributes.OfType<MaxLengthAttribute>().SingleOrDefault();
        if (maxLengthAttribute != null)
        {
            modelMetadata.AdditionalValues.Add("maxLength", maxLengthAttribute.Length);
        }
        return modelMetadata;
    }
}

В шаблоне вы можете просто использовать:

object maxLength;
ViewData.ModelMetadata.AdditionalValues.TryGetValue("maxLength", out maxLength);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...