Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/asp.net-mvc-3/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/solr/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Asp.net mvc 3 如何在.NET MVC中读取属性数据注释值_Asp.net Mvc 3 - Fatal编程技术网

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

Asp.net mvc 3 如何在.NET MVC中读取属性数据注释值,asp.net-mvc-3,Asp.net Mvc 3,我刚开始使用w/ASP.netmvc3,我正在尝试在create/edit视图的ViewModel上呈现以下字符串属性的HTML <input id="PatientID" name="PatientID" placeholder="Patient ID" type="text" value="" maxlength="30" /> 每个值都与ViewModel上的属性相关联,id和name是属性名称,占位符是显示属性,value是属性值,maxlength是StringLen

我刚开始使用w/ASP.netmvc3,我正在尝试在create/edit视图的ViewModel上呈现以下字符串属性的HTML

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

每个值都与ViewModel上的属性相关联,id和name是属性名称,占位符是显示属性,value是属性值,maxlength是StringLength属性

我想我应该尝试使用SingleLineTextBox的名称创建一个EditorTemplate,并在我的字符串属性上使用UIHint,或者在调用EditFor时传递视图的名称,而不是键入上面的HTML和每个字符串属性的正确值。到目前为止还不错,只是我不知道如何从StringLength属性中获取maxlength值

以下是我目前掌握的代码:

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

如您所见,不确定如何设置maxlength值。有人知道怎么做吗


还有,我这样做是不是最好的方式?正如我之前所说,我可以自己为页面上的每个属性编写简单的HTML。我已经研究过使用TextBoxFor,因为它没有设置maxlength,而是因为我不想要的StringLength属性而向HTML输出添加了一堆验证标记。我看到的另一个选项是HTML类的扩展/帮助程序。

要做到这一点,您需要创建自己的HtmlHelper扩展,并使用反射来获取model属性上的属性。查看上的源代码,以获取现有的
…for()
HtmlHelper扩展。您需要使用作为参数传入的表达式获取模型属性的PropertyInfo对象。他们有几个助手类,可以作为模板。获得该属性后,使用PropertyInfo上的GetCustomAttributes方法查找StringLength属性并提取其值。由于您将使用标记生成器创建输入,因此可以通过标记生成器将长度添加为属性

   ...

   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 ) );
}
。。。
var attribute=propInfo.GetCustomAttributes(typeof(StringLengthAttribute),false)
第()类
.FirstOrDefault();
变量长度=属性!=无效的属性。最大长度:20//提供默认值
builder.Attributes.Add(“maxlength”,length);
...
返回新的MvcHtmlString(builder.ToString(TagRenderMode.SelfClosing));
}

请看我对为什么我认为这是一个坏主意的评论

您可以使用
AdditionalMetadata
属性,而不是
StringLength
属性(因为它是验证器属性而不是元数据提供程序)。示例用法:

public class ViewModel
{
    [AdditionalMetadata("maxLength", 30)]
    public string Property { get; set; }
}
基本上,它将值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"  />

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) />
@model System.String
@{
var metadata=ViewData.ModelMetadata;
var prop=metadata.ContainerType.GetProperty(metadata.PropertyName);
var attrs=prop.GetCustomAttributes(false);
var maxLength=attrs.OfType().FirstOrDefault();
}
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;
    }
}
公共静态类EditorTemplateHelper
{
公共静态属性信息GetPropertyInfo(ViewDataDictionary viewData)
{
var metadata=viewData.ModelMetadata;
var prop=metadata.ContainerType.GetProperty(metadata.PropertyName);
返回道具;
}
公共静态对象[]GetAttributes(ViewDataDictionary viewData)
{
var prop=GetPropertyInfo(视图数据);
var attrs=prop.GetCustomAttributes(false);
返回属性;
}
公共静态字符串GenerateAttributeHtml(ViewDataDictionary viewData、IEnumerable 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);
返回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 />
@model System.String
@使用System.ComponentModel.DataAnnotations;
@使用Brass9.Web.Mvc.EditorTemplateHelpers;
@{
var metadata=ViewData.ModelMetadata;
var attrs=EditorTemplateHelper.GenerateAttributes(ViewData,新委托[]){
新函数(len=>maxlength=“+len.MaximumLength),
新函数(最大=>“maxlength=“+max.Length”)
});
if(metadata.IsRequired)
{
属性添加(“必需”);
}
string attrsHtml=string.Join(“,attrs);
}
因此,您传入一个委托数组,并为每个条目使用
Func
,然后为每个属性返回所需的HTML字符串


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

一个更简单的解决方案是实现自定义的
数据注释ModelMetadataProvider
,如下所示:

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

可以从编辑器模板中获取StringLength验证程序,以下是一些示例:

根据以上文章的结果,我使用和测试的内容可以在下面的答案中看到(使用MVC 5进行测试,EF 6):

在没有具体说明的情况下,我个人在尝试实现其他一些方法时遇到了一些复杂的结果,我认为这两种方法都不是很长;然而,我确实认为其他一些方法看起来有点“漂亮”。

@使用System.ComponentModel.DataAnnotations
@模型条纹
object maxLength;
ViewData.ModelMetadata.AdditionalValues.TryGetValue("maxLength", out maxLength);
@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)