自定义的DataAnnotationsModelMetadataProvider无法正常工作 [英] Customized DataAnnotationsModelMetadataProvider not working

查看:148
本文介绍了自定义的DataAnnotationsModelMetadataProvider无法正常工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有许多需要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>

问题/问题

  1. 已应用CustomRequired.但是,如果我使用的是CustomRequired,为什么它会从基类RequiredAttribute中提取消息. data-val-required应该只说 Required .
  2. 不应用6个字符的StringLenth.没有迹象表明StringLength有任何渲染,为什么?
  1. The CustomRequired was applied. But why does it pick up the message from the base class RequiredAttribute if I am using CustomRequired. The data-val-required should just say Required.
  2. The StringLenth of 6 chars is not applied. There is no sign of anything rendered for StringLength, 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-regexdata-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,所以ModelMetadataIsRequired属性已设置为true.如果您发现DataAnnotationsModelValidatorProviderGetValidators(),您将看到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

  1. HtmlHelper.cs -请参阅第413行的GetUnobtrusiveValidationAttributes()方法
  2. ModelValidatorProviders.cs -获取用于验证的各种ValidatorProviders
  3. DataAnnotationsModelValidatorProvider.cs -ValidationAttributes
  4. 的ValidatorProvider
  1. HtmlHelper.cs - refer GetUnobtrusiveValidationAttributes() methods at line 413
  2. ModelValidatorProviders.cs - gets the various ValidatorProviders used for validation
  3. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆