自定义的DataAnnotationsModelMetadataProvider无法正常工作 [英] Customized DataAnnotationsModelMetadataProvider not working
问题描述
我有许多需要1个或多个验证属性的属性,如下所示:
I have many properties that require 1 or more validation attributes, like the following:
public class TestModel
{
[Some]
[StringLength(6)]
[CustomRequired] // more attributes...
public string Truck { get; set; }
}
请注意上述所有注释均有效.
Please note all the above annotations work.
我不想一直这样写,因为每当应用Some
时,所有其他属性也将应用于该属性.我希望能够做到这一点:
I do not want to write that all the time because whenever Some
is applied, all other attributes are also applied to the property. I want to be able to do this:
public class TestModel
{
[Some]
public string Truck { get; set; }
}
现在这可以通过继承来实现;因此,我编写了一个自定义DataAnnotationsModelMetadataProvider
并覆盖了CreateMetadata
.这会查找用Some
装饰的所有内容,然后向其添加更多属性:
Now this is doable by inheriting; therefore, I wrote a custom DataAnnotationsModelMetadataProvider
and overrode the CreateMetadata
. This looks for anything that is decorated with Some
and then adds more attributes to it:
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);
}
}
以下是有助于解决问题的属性:
These are the attributes in case it helps:
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
.但是,如果我使用的是CustomRequired
,为什么它会从基类RequiredAttribute
中提取消息.data-val-required
应该只说 Required . - 不应用6个字符的
StringLenth
.没有迹象表明StringLength
有任何渲染,为什么?
- The
CustomRequired
was applied. But why does it pick up the message from the base classRequiredAttribute
if I am usingCustomRequired
. Thedata-val-required
should just say Required. - The
StringLenth
of 6 chars is not applied. There is no sign of anything rendered forStringLength
, why?
推荐答案
自定义DataAnnotationsModelMetadataProvider
正在执行的操作是创建/修改与您的媒体资源相关的ModelMetada
.
What your custom DataAnnotationsModelMetadataProvider
is doing is creating/modifying the ModelMetada
associated with your property.
If you inspect the ModelMetadata class you will note that it contains properties such as string DisplayName
and string DisplayFormatString
which are set based on the application of the [Display]
and [DisplayFormat]
attributes. It also contains a bool IsRequired
attribute that determines if the value of a property is required (a bit more on that later).
它不包含任何与正则表达式或最大长度有关的内容,或与验证有关的任何内容(IsRequired
属性和ModelType
除外,用于验证该值可以转换为type
).
It does not contain anything relating to a regular expression or the maximum length, or indeed anything related to validation (except the IsRequired
property and the ModelType
which is used to validate that that the value can be converted to the type
).
HtmlHelper
方法负责生成传递到视图的html.要生成data-val-*
属性,您的TextBoxFor()
方法在内部调用HtmlHelper
类的GetUnobtrusiveValidationAttributes()
方法,该方法又调用DataAnnotationsModelValidatorProvider
类中的方法,这些方法最终生成data-val
属性的Dictionary
用于生成html的名称和值.
It is the HtmlHelper
methods that are responsible for generating the html that is passed to the view. To generate the data-val-*
attributes, your TextBoxFor()
method internally calls the GetUnobtrusiveValidationAttributes()
method of the HtmlHelper
class which in turn calls methods in the DataAnnotationsModelValidatorProvider
class which ultimately generate a Dictionary
of the data-val
attribute names and values used to generate the html.
如果您需要更多细节(请参见下面的链接),我将留给您研究源代码,但总而言之,它获得了应用于从ValidationAttribute
继承到Truck
属性的所有属性的集合.建立字典.在您的情况下,唯一的ValidationAttribute
是[Some]
,它是从RegularExpressionAttribute
派生的,因此添加了data-val-regex
和data-val-regex-pattern
属性.
I'll leave it to you to explore the source code if you want more detail (refer links below) but to summarize, it gets a collection of all attributes applied to your Truck
property that inherit from ValidationAttribute
to build the dictionary. In your case the only ValidationAttribute
is [Some]
which derives from RegularExpressionAttribute
so the data-val-regex
and data-val-regex-pattern
attributes are added.
但是因为您已经在TruckNumberMetadataProvider
中添加了CustomRequiredAttribute
,所以ModelMetadata
的IsRequired
属性已设置为true
.如果您发现DataAnnotationsModelValidatorProvider
的GetValidators()
,您将看到RequiredAttribute
自动添加到属性集合中,因为您尚未对属性应用一个.相关的代码段是
But because you have added your CustomRequiredAttribute
in the TruckNumberMetadataProvider
, the IsRequired
property of the ModelMetadata
has been set to true
. If you insect the GetValidators()
of DataAnnotationsModelValidatorProvider
you will see that a RequiredAttribute
is automatically added to the collection of attributes because you have not applied one to the property. The relevant snippet of code is
if (AddImplicitRequiredAttributeForValueTypes && metadata.IsRequired && !attributes.Any(a => a is RequiredAttribute))
{
attributes = attributes.Concat(new[] { new RequiredAttribute() });
}
这会导致将data-val-required
属性添加到html中(并且使用默认消息,因为它对您的CustomRequiredAttribute
一无所知)
which results in the data-val-required
attribute being added to the html (and it uses the default message because it knows nothing about your CustomRequiredAttribute
)
如果您想了解内部工作原理,请开始使用源代码文件
Source code files to get you started if you want to understand the internal workings
- HtmlHelper.cs -请参阅第413行的
GetUnobtrusiveValidationAttributes()
方法 - ModelValidatorProviders.cs -获取用于验证的各种ValidatorProviders
- DataAnnotationsModelValidatorProvider.cs -
ValidationAttributes
的ValidatorProvider
- HtmlHelper.cs - refer
GetUnobtrusiveValidationAttributes()
methods at line 413 - ModelValidatorProviders.cs - gets the various ValidatorProviders used for validation
- DataAnnotationsModelValidatorProvider.cs - the ValidatorProvider for
ValidationAttributes
如果您真的只想使用一个ValidationAttribute
,则可能的解决方案是使其实现IClientValidatable
,并在GetClientValidationRules()
方法中添加规则,例如
One possible solution if you really want to use just one single ValidationAttribute
would be to have it implement IClientValidatable
and in the GetClientValidationRules()
method, add rules, for example
var rule = new ModelClientValidationRule
{
ValidationType = "required",
ErrorMessage = "Required"
}
,它将由ClientDataTypeModelValidatorProvider
读取(并删除您的TruckNumberMetadataProvider
类).但是,这将造成维护的噩梦,因此我建议您仅将3个验证属性添加到属性中
which will be read by the ClientDataTypeModelValidatorProvider
(and delete your TruckNumberMetadataProvider
class). However that will create a maintenance nightmare so I recommend you just add the 3 validation attributes to your property
这篇关于自定义的DataAnnotationsModelMetadataProvider无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!