我有许多属性需要一个或多个验证属性,如下所示:
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>
问题/问题
CustomRequired
。但是,如果我使用RequiredAttribute
,为什么它会从基类CustomRequired
中获取消息。 data-val-required
应该说必需。StringLenth
。没有为StringLength
呈现任何内容的迹象,为什么?答案 0 :(得分:3)
您的自定义DataAnnotationsModelMetadataProvider
正在做的是创建/修改与您的媒体相关联的ModelMetada
。
如果您检查ModelMetadata课程,则会注意到它包含string DisplayName
和string DisplayFormatString
等属性,这些属性是根据[Display]
和{{的应用程序设置的1}}属性。它还包含一个[DisplayFormat]
属性,用于确定是否需要属性的值(稍后会更多)。
它不包含任何与正则表达式或最大长度相关的内容,或者实际上与验证相关的任何内容(bool IsRequired
属性除外,IsRequired
用于验证值是否可以转换为ModelType
)。
负责生成传递给视图的html的type
方法。要生成HtmlHelper
属性,您的data-val-*
方法会在内部调用TextBoxFor()
类的GetUnobtrusiveValidationAttributes()
方法,后者又调用最终生成的HtmlHelper
类中的方法用于生成html的DataAnnotationsModelValidatorProvider
属性名称和值的Dictionary
。
如果您需要更多详细信息(请参阅下面的链接),我将留给您探索源代码,但总结一下,它会获取应用于您继承自data-val
属性的所有属性的集合。 Truck
来构建字典。在您的情况下,唯一的ValidationAttribute
是ValidationAttribute
,其源自[Some]
,因此会添加RegularExpressionAttribute
和data-val-regex
属性。
但是因为您已在data-val-regex-pattern
中添加了CustomRequiredAttribute
,TruckNumberMetadataProvider
的{{1}}属性已设置为IsRequired
。如果您发现ModelMetadata
true
,您会看到GetValidators()
会自动添加到属性集合中,因为您尚未向该属性应用DataAnnotationsModelValidatorProvider
。相关的代码片段是
RequiredAttribute
导致if (AddImplicitRequiredAttributeForValueTypes && metadata.IsRequired && !attributes.Any(a => a is RequiredAttribute))
{
attributes = attributes.Concat(new[] { new RequiredAttribute() });
}
属性被添加到html中(并且它使用默认消息,因为它对您的data-val-required
一无所知)
如果您想了解内部工作原理,可以开始使用源代码文件
CustomRequiredAttribute
方法GetUnobtrusiveValidationAttributes()
如果您真的只想使用一个ValidationAttributes
,那么一种可能的解决方案就是让它实现ValidationAttribute
,并在IClientValidatable
方法中添加规则,例如
GetClientValidationRules()
将由var rule = new ModelClientValidationRule
{
ValidationType = "required",
ErrorMessage = "Required"
}
读取(并删除您的ClientDataTypeModelValidatorProvider
类)。但是,这会造成维护噩梦,因此我建议您只需将3个验证属性添加到您的属性