ModelValidator基于元数据的验证

Posted xuyoungzhe98

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ModelValidator基于元数据的验证相关的知识,希望对你有一定的参考价值。

ModelValidator主要是应用在ModelMetadata元数据的类型上或类型属性上。它是验证的基础类型,所有的ModelValidatorProviders、DataAnnotationValidator、DataAnnotationValidatorProvider都是主要通过GetValidators这个方法来获取IEnumerable<ModelValidator>对象。然后循环这个迭代对象,利用ModelValidator的Validator对每个元数据进行验证。有个例子可以很好的说明:

1 private IEnumerable<ModelValidator> GetValidator(Type type)
2 {
3    ModelValidatorProvider provider=new DataAnnodationModelValidatorProvider();
   ModelMetaData metadata=ModelMetadataProviders.Current.GetMetadataForType(null,type);
   foreach(var validator in provider.GetValidator(metadata,ControllerContext))
{
     yeild return validator 
   }

   foreach(var propertyMetadata in metadata.Properties)
   {
     foreach(var validator in provider.GetValidator(propertyMetadata,ControllerContext))
      yeild return validator;
   }
4 }

 

元数据ModelMetaData包含:IEnumrable<ModelValidator> GetValidator(ContollerContext)  实现方法:

IEnumrable<ModelValidator> GetValidator(ControllerContext context)
{
   return ModelValidatorProviders.Providers.GetValidator(this,context)
}
其中Providers来源:
private static readonly ModelValidatorProviderCollection _providers=new ModelValidatorProviderCollecton
{
  new DataAnnotationModelValidatorProvider(),
  new DataErrorInfoModelValidatorProvider(),
  new ClinetDataTypeModelValidatorProvider()
}
继续实现 Providets的GetValidator的方法:
public class
ModelValidatorProviderCollection:ICollection<ModelValidatorProvider>
{
  public IEnumrable<ModelValidator> GetValidator(ModelMedatata modeltadata,ControllerContext context)
  {
    return this.CombindItems.SelectMany(ModelValidatorProvider provider)=>provider.GetValidators(modeltadata,context);
    //这个方法CombindItems可理解为内部已定义数据集合和外部自定义的数据集合的合计。具体的实现在MultiServiceResolver:IResolver<IEnumrable<TServerice>>
  }
  //对了这个类我本来不想往下记录下 但是为了以后再学习和本着研究的心态还是硬着头皮写写去吧
  
  public IResolver<IEnumrable<ModelValidatorProvider>> _serviceResolver;
  privite IEnumeable<ModelValidator> CombindItems
  {
    get{  
        return this._serviceResoler.Current;
      }
  }
  public ModelValidatorProviderCollection()
  {
    this._serviceResolver=new MultiServiceResolver<ModelValidatorProvider>(()=>this.Items);
  }
  public ModelValidatorProviderCollection(IList<ModelValidatorProvider> list):base(list);
  {
    this._serviceResolver=new MultiServerResolver<ModelValdatorProvider>(()=>this.Items);
  }
  internal ModelValidatorProviderCollection(IReslover<IEnumrable<ModelValidatorProvider>> services,Params ModelValidatorProvider[] modelValidatorProviders):base(modelValidatorProviders)
  {
    IResolver<IEnumrable<ModelValidaotProvider>> arge=services;
    if(arge==null)
    {
      arge=new MultiServiceReslover<ModelValidatorProvider>(this.Items);
    }
    this._serviceResolber=arge;
  }
  prottect override void SetItem(int index,ModelValidatorProvider item)
  {
    if(item==null)
      throw new ArgumentNullException("item");
    base.SetItem(index,item);
  }
}

//【下面要介绍的是MultiServiceResolver类的只要实现,主要是通过依赖组件DependencyResolver.Current的GerServices<TService>得到一组数据,然后通过构造函数传入的委托方法得到另外一组数据,通过Current实现两组数据的结合】
public class MultiServiceReslover<TService>:IService<IEnumrable<TService>> where TService :Class
{
  private Lazy<IEnumerable<TService>> _itemsFormService;
  private Func<IEnumrable<IService>> _itemThunk;
  private Func<IEnumrable<TService>> _resolverThunk;
  public IEnumrable<TService> Current
  {
    get{
      return this.itemsFormService.Value.Cacat(this._itemThunk());
    }
  }
  public MultiServiceResolve(Func<IEnumrable<TService>> itemsThunk)
  {
    if(itemThunk==null)
      throw new ArgumentNullException("itemThunk");
    this._itemsThunk=itemsThunk;
    this._resolverThunk=(()=>DependencyResolver.Curremt);
    this._itemsFormServices=new Lazy<IEnumerable<TService>>(()=>this._resolverThunk.GetService<TService>());
  }
}

 

 前面一直围绕着获取ModelValidatorProvider来实现方法。可ModelValidatorProvider本身是一个抽象类和只有一个abstract的GetValidators(ModelMedata,ControllerContext)的方法。现在对系统中默认继承和实现ModelValidatorProvider抽象类的其中一个比较常用的类型做说明,那就是 DataAnnotationModelValidatorProvider,它是系统间接实现了ModelValidatorProvider,是我们最常用的基于验证特性的声明式 Model 验证。

在了解DataAnnotationModelValidatorProvider时 会提到DataAnnotationModelValidator这类,它具体地实现了ModelValidator定义的方法(包括Validate(object container))。

public class DataAnnotationModelValidatorProvider:AssocitatedValidatorProvider
{
         //这里只编辑主要的实现方法

      // 这里的DataAnnotationModelValidatorFactory的系统定义的一个委托。如果元数据属性未定义在AttributeFactories中 则采用默认的ModelValidator对象
      internal static DataAnnotationModelValidatorFactory DefaultAttributeFactory=(ModelMetaData metadata,ControllerContext context,ValidatorAttribute attrubute)=>new DataAnnotaionModelValidator(metadata,context,attribute);   
  
 //主要为创建元数据"自我验证"集合,可以通过RegisterValidatableObjectAdapter(Type modelType,Type adapterType)来实现自我注册
   internal static Dictionary<Type,DataAnnotationModelValidatorFactiory>  AttributeFactories=DataAnnotationModelValidatorProvider.BuildAttributeFactoriesDictionary();
            
  //接下来是最主要的代码了  
    protext override IEnumerable<ModelValidator> GetValidators(ModelMetaData metadata,ControllerContext context,ValidatorAttribute attributes)
    {
        var result=new List<ModelValidator>;
         try{
//这一步的意思是: AddImplicitRequiredAttributeForValueTypes (为值类型添加隐式必填验证) 值为True,元数据也声明了Required=True,则必须在attributes里包含 RequiredAttribute  if(DataAnnotatoonModelValidatorProvider.AddImplicitRequiredAttributeForValueType && metadata.IsRequired)
             {
                  if(!attributes.Any((Attribute t)=>t is RequiredAttribute))
                 {
                     attrubutes=attribites.concat(new RequiredAttribute[]{new RequiredAttrbute()});
                 }
             } 
            foreach(var ValidatorAttribute current in attributes.ofType<ValidatorAttribute>)
            {
                 DataAnnotationModelValidatorFactory defaultFactory;
                 if(!DataAnnotationModelValidatorProvider.AttrbuteFactories.TryValue(current.GetType(),out defualtFactory))
                 {
                      defaultFactory=DataAnnotationModelValidatorProvider.DefaultAttrbuteFactoty;
                  }
                  result.Add(defaultFactory(metadata,context,current))
             }
             if(typeof(IValidatableObject).IsAssignableForm(medatat.ModelType))
            {
                 DataAnnotationsValidatableObjectAdapterFactory defaultValidatableFactory;
                    if (!DataAnnotationsModelValidatorProvider.ValidatableFactories.TryGetValue(metadata.ModelType, out defaultValidatableFactory))
                    {
                        defaultValidatableFactory = DataAnnotationsModelValidatorProvider.DefaultValidatableFactory;
                    }
                    result.Add(defaultValidatableFactory(metadata, context));
                    
            }
         }
         finally{

          }
          return result;
    }
    //上面这个方法写了这么多无非就是 根据元数据上的属性获取继承了ModelValidator的对象集合,然后利用集合里每个对象所定义的Validator方法进行验证
    //下面是一些自定义注册方法

    
    public static void RegistAdapter(Type attrbuteType,Type adaperType)
     {
         //获取当前 adaperType的特定构造函数
         ConstructorInfo  constructor=adapterType.GetConstructor(typeOf(ModelMetadata),typeof(ControllerContext),attrbuteType);
        try{
             DataAnnotationModelValidatorProvider.AttributeFacties[attrbuteType]=((ModelMedatada metadata,ControllerContext context,ValidatorAttribute attribute)=>(ModelValidator)constructor.Invoker(new object[]{metadata,context,attrbute}));
         }
         finally{
           }
     }
    
//直接用委托方法注册
     public static void  RegisterAdapterFactory(Type attributeType,DataAnnotationsModelValidatorFactory factory)  BuildAttributeFacoriesDictionary
{
   //还有好多自定义注册方法  反编译后查看吧
   //下面实现的是系统自定义一些ValidatorAttribute
    private static Dictionary<Type,DataAnnotationModelValidatorFactory> dictionary=new Dictionary<Type,DataAnnotationModelValidatorFactory>();
     DataAnnotationsModelValidatorProvider.AddValidationAttributeAdapter(dictionary, typeof(RangeAttribute), (ModelMetadata metadata, ControllerContext context, ValidationAttribute attribute) => new RangeAttributeAdapter(metadata, context, (RangeAttribute)attribute));
            DataAnnotationsModelValidatorProvider.AddValidationAttributeAdapter(dictionary, typeof(RegularExpressionAttribute), (ModelMetadata metadata, ControllerContext context, ValidationAttribute attribute) => new RegularExpressionAttributeAdapter(metadata, context, (RegularExpressionAttribute)attribute));
            DataAnnotationsModelValidatorProvider.AddValidationAttributeAdapter(dictionary, typeof(RequiredAttribute), (ModelMetadata metadata, ControllerContext context, ValidationAttribute attribute) => new RequiredAttributeAdapter(metadata, context, (RequiredAttribute)attribute));
            DataAnnotationsModelValidatorProvider.AddValidationAttributeAdapter(dictionary, typeof(StringLengthAttribute), (ModelMetadata metadata, ControllerContext context, ValidationAttribute attribute) => new StringLengthAttributeAdapter(metadata, context, (StringLengthAttribute)attribute));
            DataAnnotationsModelValidatorProvider.AddValidationAttributeAdapter(dictionary, ValidationAttributeHelpers.MembershipPasswordAttributeType, (ModelMetadata metadata, ControllerContext context, ValidationAttribute attribute) => new MembershipPasswordAttributeAdapter(metadata, context, attribute));
            DataAnnotationsModelValidatorProvider.AddValidationAttributeAdapter(dictionary, ValidationAttributeHelpers.CompareAttributeType, (ModelMetadata metadata, ControllerContext context, ValidationAttribute attribute) => new CompareAttributeAdapter(metadata, context, attribute));
            DataAnnotationsModelValidatorProvider.AddValidationAttributeAdapter(dictionary, ValidationAttributeHelpers.FileExtensionsAttributeType, (ModelMetadata metadata, ControllerContext context, ValidationAttribute attribute) => new FileExtensionsAttributeAdapter(metadata, context, attribute));
            DataAnnotationsModelValidatorProvider.AddDataTypeAttributeAdapter(dictionary, ValidationAttributeHelpers.CreditCardAttributeType, "creditcard");
            DataAnnotationsModelValidatorProvider.AddDataTypeAttributeAdapter(dictionary, ValidationAttributeHelpers.EmailAddressAttributeType, "email");
            DataAnnotationsModelValidatorProvider.AddDataTypeAttributeAdapter(dictionary, ValidationAttributeHelpers.PhoneAttributeType, "phone");
            DataAnnotationsModelValidatorProvider.AddDataTypeAttributeAdapter(dictionary, ValidationAttributeHelpers.UrlAttributeType, "url");
            return dictionary;
 }
}

 

上面这个类引用了之类AssociatedValidatorProvider    Associated(关联的意思)。这个类首先利用GetValidator(ModelMetadata,ControllerContext) 对元数据提取Attribute, 得到的Attribute数组去调用抽象方法GetValidator(ModelMetadata,ControllerContext,IEnumrable<ModelValidator>),这个方法在上面的DataAnnotationModelValidatorProvider被实现。

AssociatedValidatorProvider类重点对传入的元数据ModelMetadata进行解析。

public sealed override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata,ControllerContext context)
{
    if(metadata==null)
         throw new ArgumentNullExecption("metadata");
    if(context==null)
         throw new ArgumentNullExecption("context");
    
}   
protect abstract IEnumrable<ModelValidator> GetValidators(ModelMetadata,ControllerContext,IEunmerable<Attribute> atttibutes);//这个抽象方法在上面类(DataAnnotationModelValidatorProvider)里有具体的实现

protected override ICustomTypeDescriptor GetTypeDescriptor(Type type)
{
     return TypeDescriptorHepler.Get(type);
} 

pritvate IEnumerable<ModelValidator> GetValidatorForProperty(ModelMetadata metadata,ControllerContextg context)
{
     IcustomTypeDescriptor typedescriptor=this.GetTypeDescriptor(metadata.ContainerType);
     PropertyDescriptor propertyDescriptor=typedescriptor.GetProperties.Find(metadata.PropertyName,true);
     if(propertyDescriptor==null)
           throw new ArgumentException("PropertyNoFound");
     return this.GetValidator(metadata,context,propertyDescriptor.Attributes.OfType<Attribute>);  
}

private IEnumerable<ModelValidator> GetValidatorsForType(MedelMetadata metadata,ControllerContext context)
{
     return this.GetValidator(metadata,context,this.GetTypeDescriptor(metadata.ModelType).GetAttributes().Cast<Attribue>);
}

 

上面的DataAnnotationModelValidatorProvider中  根据属性来查找实现委托DataAnnotationsModelValidationFactory时,有一个默认的实现:DataAnnotationsModelValidator。这个方法是真正实现了验证功能Validate(object contatiner).

下面就是这个类大概的实现过程。

public class DataAnnotationModelValidator:ModelValidator
{
    public override IEnumerable<ModelValidatorResult> Validate(object container)
    {
       ValidationContext validationContext=new ValidationContext(container??base.Metadata.Model,null,null);
       validationContext.DisplayName=this.Metadata.DisPlayName();
    validationResult result=this.Attribute.GetValidationResult(base.Metadata.Model,validationContext);
    if(result!=result.Scuess)
    {
           yeild return New ModelValidateResult
{ Message
=validation.ErrorMessage;    }; yeild break;    } } protect internal string ErrorMessage { get{ return this.Attribute.FormatErrorMessage(base.Metadata.DispalyName()); } } }

 



















































































以上是关于ModelValidator基于元数据的验证的主要内容,如果未能解决你的问题,请参考以下文章

上市公司新元科技:签署5.8亿元分布式存储中心项目合同——Filecoin正得到更多大型科技公司的认可和参与,前景一片大好。

验证坐标在某片坐标区域内 php 代码

qt memring固定片元内存池制作

找不到类验证器的元数据

php验证地图坐标在某片坐标区域内

GitIntelliJ IDEA 提交代码到 GitCode 远程仓库 ( GitCode 创建远程仓库 | 将本地工程推送到 GitCode 远程仓库 | 验证权限 | 生成个人访问令牌 )(代码片