【问题标题】:StringLength in ViewModel not setting maxlength on textboxViewModel 中的 StringLength 未在文本框上设置 maxlength
【发布时间】:2013-01-22 06:44:32
【问题描述】:

这里是我的 ViewModel 中的属性:

[Display(Name = "Ext.")]
[MaxLength(6, ErrorMessage = "Must be a maximum of 6 characters")]
[StringLength(6)]
public string Extension { get; set; }

在我看来:

@Html.EditorFor(model => model.Extension)

它会渲染:

<input class="text-box single-line" data-val="true" data-val-length="The field Ext. must be a string with a maximum length of 6." data-val-length-max="6" id="Extension" name="Extension" type="text" value="" />

这应该在我的文本框上设置 maxlength 属性吗?如果没有,我该如何使用 DataAttributes 来做到这一点?

【问题讨论】:

  • 您是否验证过是否可以发布超过 6 个字符的字符串?
  • 我确实收到了验证错误,但我希望它实际设置 maxlength 属性。
  • 如果你把它改成TextBoxFor你可以传入HTML选项。
  • 是的,但如果可能的话,我希望我在 ViewModel 中设置的属性来控制它。
  • 如果您使用的是unobtrusive validation,这个post 可能会有所帮助

标签: razor asp.net-mvc-4


【解决方案1】:

我希望我在 ViewModel 中设置的属性来控制它,如果 可能。

ASP.NET MVC 提供了一个可扩展的系统来实现这一点。以下是您需要做的:

  1. 实现自定义ModelMetadataProvider
  2. 查找StringLengthAttributeMaxLengthAttribute,提取信息并将其添加到ModelMetadata
  3. 提供一个使用这些信息的自定义编辑器模板。

第 1 步:实现自定义 ModelMetadataProvider

创建一个派生自ModelMetadataProvider 的类。通常您会从 DataAnnotationsModelMetadataProvider 派生,因为它提供了一些默认功能,这意味着您只需覆盖一个名为 CreateMetadata 的方法。

第 2 步:提取信息:

要获取信息,需要查找属性,提取最大长度信息,并将其添加到ModelMetadataAdditionalValues 字典中。实现看起来像这样(这是整个实现):

public class CustomModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
    protected override ModelMetadata CreateMetadata(
        IEnumerable<Attribute> attributes, 
        Type containerType, 
        Func<object> modelAccessor, 
        Type modelType, 
        string propertyName)
    {
        // Call the base class implementation to create the default metadata...
        var metadata = base.CreateMetadata(
            attributes, 
            containerType, 
            modelAccessor, 
            modelType, 
            propertyName);

        // Extract the stringLengthAttribute (you can do the same for the
        // MaxLengthAttribute if you want).
        var attr = attributes
            .OfType<StringLengthAttribute>()
            .First();

        // This could be getting called on a property that doesn't have the
        // attribute so make sure you check for null!
        if (attr != null)
        {
            metadata.AdditionalValues["maxLength"] = attr.MaximumLength;
        }

        return metadata;
    }
}

为了让 ASP.NET MVC 使用它,您需要在 Global.asaxApplication_Start 方法中注册它。

ModelMetadataProviders.Current = new CustomModelMetadataProvider();

第 3 步:创建自定义编辑器模板。

您现在需要创建一个使用该信息的视图。在Views\Shared\ 文件夹中创建一个名为String 的新视图。

String.cshtml

@{
    object maxLength;
    if (!ViewData.ModelMetadata.AdditionalValues
            .TryGetValue("maxLength", out maxLength))
    {
        maxLength = 0;
    }

    var attributes = new RouteValueDictionary
    {
        {"class", "text-box single-line"},
        { "maxlength", (int)maxLength },
    };
}

@Html.TextBox("", ViewContext.ViewData.TemplateInfo.FormattedModelValue, attributes)

当您运行应用程序时,您将通过调用 @Html.EditorFor 获得以下 HTML 输出。

<input class="text-box single-line" id="Extension" maxlength="6" name="Extension" type="text" value="" />

如果您想了解有关模型元数据提供程序系统的更多信息,Brad Wilson has a series of blog posts 详细说明它是如何工作的(这些是在 Razor 视图引擎之前编写的,因此某些视图语法有点时髦,但其他信息是合理的)。

【讨论】:

  • 本杰明,你今天是一台机器!
  • 没问题,很高兴我能帮上忙。
【解决方案2】:

基本上基于 Brad 的回答,使用 lambda 语法包装在 Html 帮助程序的扩展中,这样您就不会用反射的东西污染 Razor 视图:

using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Web.Mvc;

public static class HtmlHelper
{
    public static int? MaxLength<TModel, TProperty>(
        this HtmlHelper<TModel> htmlHelper,
        Expression<Func<TModel, TProperty>> expression)
    {
        MemberExpression memberExpression = (MemberExpression)expression.Body;

        PropertyInfo property = typeof(TModel)
            .GetProperty(memberExpression.Member.Name);

        StringLengthAttribute attribute = (StringLengthAttribute)property
            .GetCustomAttributes(typeof(StringLengthAttribute), true)
            .FirstOrDefault();

        if (attribute != null)
        {
            return attribute.MaximumLength;
        }

        return null;
    }
}

像这样使用它:

@Html.TextBoxFor(x => x.Name, new { maxlength = Html.MaxLength(x => x.Name) })

x 指的是您的型号。

如果没有为属性声明StringLengthAttribute,则将返回null,并且文本框元素上的maxlength 属性将为空。

请记住在您的剃须刀页面中包含使用,以便您可以访问该方法。

@using HtmlHelper

您还需要为该方法使用不可为空的结果来克服编译错误。

【讨论】:

    【解决方案3】:

    我遇到了类似的情况,这是我快速而肮脏的解决方案:

    在 .cshtml 文件的顶部添加以下行:

    @{
    var max = ((System.ComponentModel.DataAnnotations.StringLengthAttribute)(typeof(MyType))
    .GetProperty("MyProp")
    .GetCustomAttributes(typeof(System.ComponentModel.DataAnnotations.StringLengthAttribute), true)[0]).MaximumLength;    
    }
    

    在您的 html 中,将 EditorFor 替换为:

    @Html.TextBoxFor(model => model.Extension, htmlAttributes: new {maxlength=max })
    

    我最终决定我宁愿只用脚本来做:

    <script>
        $(function ()
        {
            var max = $("#myinput").attr("data-val-length-max");
            $("#myinput").attr("maxlength", max);
        });
    </script>
    

    但如果您不想添加脚本,第一个示例应该可以工作。

    【讨论】:

    • 此代码有效,但您可能希望使用帮助程序之类的工具保持 Razor 视图更清晰。有关示例,请参阅我的答案。
    猜你喜欢
    • 2011-01-24
    • 1970-01-01
    • 2016-01-08
    • 2011-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-10
    • 1970-01-01
    相关资源
    最近更新 更多