如何在.NET MVC中读取属性数据注释值

Bil*_*lly 4 asp.net-mvc-3

我刚刚开始使用ASP.NET MVC 3,我试图在创建/编辑视图上为ViewModel上的字符串属性渲染以下HTML.

<input id="PatientID" name="PatientID" placeholder="Patient ID" type="text" value="" maxlength="30" />
Run Code Online (Sandbox Code Playgroud)

每个值绑定到ViewModel上的属性,id和name是属性名称,占位符是Display属性,value是属性的值,maxlength是StringLength属性.

我没有用我的每个字符串属性键入上面的HTML和正确的值,而是认为我会尝试使用SingleLineTextBox的名称创建一个EditorTemplate,并在我的字符串属性上使用UIHint,或者在调用EditFor时传递视图的名称.到目前为止一直很好,除了我无法弄清楚如何从StringLength属性中获取maxlength值.

这是我到目前为止的代码:

<input id="@ViewData.ModelMetadata.PropertyName" name="@ViewData.ModelMetadata.PropertyName" placeholder="@ViewData.ModelMetadata.DisplayName" type="text" value="@ViewData.Model" maxlength="??" />
Run Code Online (Sandbox Code Playgroud)

如您所见,不确定如何设置maxlength值.谁知道怎么样?

另外,我是最好的方式吗?正如我之前所说,我可以自己为页面上的每个属性写出纯HTML.我看用TextBoxFor它没有设置最大长度,并加入一些验证标记的HTML输出,因为我不想StringLength属性.我看到的另一个选项是HTML类的扩展/帮助.

Chr*_*ini 8

tvanfosson答案的完整代码示例:

模型:

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

    [MaxLength(200)]
    public string Name { get; set; }
Run Code Online (Sandbox Code Playgroud)

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) />
Run Code Online (Sandbox Code Playgroud)

HTML输出:

<input id=Name maxlength=200 />
Run Code Online (Sandbox Code Playgroud)

丑陋但有效.现在让我们抽象它并清理一下.助手班:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑模板:

@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 />
Run Code Online (Sandbox Code Playgroud)

因此,您传入一个Delegates数组,并为每个条目使用a Func<AttributeTypeGoesHere, string>,然后返回您想要的每个属性的HTML字符串.

这实际上很好地解耦 - 您只能映射您关心的属性,您可以为同一HTML的不同部分映射不同的集合,最终用法(如@attrsHtml)不会损害模板的可读性.


nem*_*esv 5

StringLength您可以使用该AdditionalMetadata属性代替属性(因为它是验证程序属性而不是元数据提供程序).样品用法:

public class ViewModel
{
    [AdditionalMetadata("maxLength", 30)]
    public string Property { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

基本上它将值30放在ViewData.ModelMetadata.AdditionalValues字典中的键maxLength下.所以你可以使用它的EditorTemplate:

<input maxlength="@ViewData.ModelMetadata.AdditionalValues["maxLength"]" id="@ViewData.ModelMetadata.PropertyName" name="@ViewData.ModelMetadata.PropertyName" placeholder="@ViewData.ModelMetadata.DisplayName" type="text" value="@ViewData.Model"  />
Run Code Online (Sandbox Code Playgroud)