Customized DataAnnotationsModelMetadataProvider not working

随声附和 提交于 2019-12-02 02:07:26

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).

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).

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.

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.

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() });
}

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 - refer GetUnobtrusiveValidationAttributes() methods at line 413
  2. ModelValidatorProviders.cs - gets the various ValidatorProviders used for validation
  3. DataAnnotationsModelValidatorProvider.cs - the ValidatorProvider for ValidationAttributes

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"
}

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!