【问题标题】:Customized DataAnnotationsModelMetadataProvider not working自定义的 DataAnnotationsModelMetadataProvider 不起作用
【发布时间】:2018-02-09 21:46:18
【问题描述】:

我有许多属性需要 1 个或多个验证属性,如下所示:

public class TestModel
{
    [Some]
    [StringLength(6)]
    [CustomRequired] // more attributes...
    public string Truck { get; set; }
}

请注意以上所有注释都有效。

我不想一直这样写,因为每当应用Some 时,所有其他属性也会应用到该属性。我希望能够做到这一点:

public class TestModel
{
    [Some]
    public string Truck { get; set; }
}

现在这可以通过继承来实现;因此,我写了一个自定义的DataAnnotationsModelMetadataProvider 并覆盖了CreateMetadata。这会查找用Some 装饰的任何内容,然后为其添加更多属性:

public class TruckNumberMetadataProvider : DataAnnotationsModelMetadataProvider
{
    protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
    {
        var attributeList = attributes.ToList();
        if (attributeList.OfType<SomeAttribute>().Any())
        {
            attributeList.Add(new StringLengthAttribute(6));
            attributeList.Add(new CustomRequiredAttribute());
        }

        return base.CreateMetadata(attributeList, containerType, modelAccessor, modelType, propertyName);
    }
}

如果有帮助,这些是属性:

public class CustomRequiredAttribute : RequiredAttribute
{
    public CustomRequiredAttribute()
    {
        this.ErrorMessage = "Required";
    }
}
public class SomeAttribute : RegularExpressionAttribute
{
    public SomeAttribute()
        : base(@"^[1-9]\d{0,5}$")
    {
    }
}

用法

@Html.TextBoxFor(x => x.Truck)

HTML 渲染:

<input name="Truck" id="Truck" type="text" value="" 
    data-val-required="The Truck field is required." 
    data-val-regex-pattern="^[1-9]\d{0,5}$" 
    data-val-regex="The field Truck must match the regular expression '^[1-9]\d{0,5}$'." 
    data-val="true">
</input>

问题/疑问

  1. CustomRequired 已应用。但是,如果我使用CustomRequired,它为什么会从基类RequiredAttribute 中获取消息。 data-val-required 应该只是说必填
  2. 不应用 6 个字符的 StringLenthStringLength 没有任何渲染迹象,为什么?

【问题讨论】:

  • 关于(1),您是否在global.asax.cs注册了您的自定义属性?
  • @StephenMuecke 是的,我已经注册了他们。当我直接在我的模型上使用它们时,它们会起作用。您实际上可以获取代码,它会重现问题。
  • 我没有将Required 应用于模型,因此它肯定是从自定义提供程序中获取它,但由于某种原因没有获取错误消息。

标签: c# asp.net-mvc razor asp.net-mvc-5


【解决方案1】:

您的自定义 DataAnnotationsModelMetadataProvider 所做的是创建/修改与您的属性关联的 ModelMetada

如果您检查ModelMetadata 类,您会注意到它包含诸如string DisplayNamestring DisplayFormatString 之类的属性,这些属性是基于[Display][DisplayFormat] 属性的应用而设置的。它还包含一个bool IsRequired 属性,用于确定是否需要某个属性的值(稍后会详细介绍)。

它不包含与正则表达式或最大长度相关的任何内容,或者实际上与验证相关的任何内容(IsRequired 属性和 ModelType 用于验证该值是否可以转换为type)。

HtmlHelper 方法负责生成传递给视图的 html。要生成data-val-* 属性,您的TextBoxFor() 方法在内部调用HtmlHelper 类的GetUnobtrusiveValidationAttributes() 方法,该方法又调用DataAnnotationsModelValidatorProvider 类中的方法,最终生成data-val 属性的Dictionary用于生成 html 的名称和值。

如果您想了解更多详细信息(请参阅下面的链接),我将留给您探索源代码,但总而言之,它获取应用于您的 Truck 属性的所有属性的集合,这些属性继承自 ValidationAttribute 到建立字典。在您的情况下,唯一的ValidationAttribute[Some],它派生自RegularExpressionAttribute,因此添加了data-val-regexdata-val-regex-pattern 属性。

但是因为您已在TruckNumberMetadataProvider 中添加了您的CustomRequiredAttribute,所以ModelMetadataIsRequired 属性已设置为true。如果您检查GetValidators()DataAnnotationsModelValidatorProvider,您将看到RequiredAttribute 自动添加到属性集合中,因为您还没有将一个应用于属性。代码的相关sn-p是

if (AddImplicitRequiredAttributeForValueTypes && metadata.IsRequired && !attributes.Any(a => a is RequiredAttribute))
{
    attributes = attributes.Concat(new[] { new RequiredAttribute() });
}

这会导致data-val-required 属性被添加到 html 中(并且它使用默认消息,因为它对您的 CustomRequiredAttribute 一无所知)

如果您想了解内部工作原理,可帮助您入门的源代码文件

  1. HtmlHelper.cs - 请参阅第 413 行的 GetUnobtrusiveValidationAttributes() 方法
  2. ModelValidatorProviders.cs - 获取用于验证的各种 ValidatorProviders
  3. DataAnnotationsModelValidatorProvider.cs - ValidationAttributes 的 ValidatorProvider

如果您真的只想使用一个 ValidationAttribute,一个可能的解决方案是让它实现 IClientValidatable 并在 GetClientValidationRules() 方法中添加规则,例如

var rule = new ModelClientValidationRule
{
    ValidationType = "required",
    ErrorMessage = "Required"
}

这将被ClientDataTypeModelValidatorProvider 读取(并删除您的TruckNumberMetadataProvider 类)。但是,这将造成维护噩梦,因此我建议您只需将 3 个验证属性添加到您的属性中

【讨论】:

  • 这有帮助,我会在周末后研究它。谢谢。
猜你喜欢
  • 1970-01-01
  • 2013-04-23
  • 2012-05-05
  • 2020-05-21
  • 2019-11-13
  • 1970-01-01
  • 1970-01-01
  • 2013-10-03
相关资源
最近更新 更多