经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » ASP.net » 查看文章
ModelValidator基于元数据的验证
来源:cnblogs  作者:xuyoungzhe98  时间:2018/9/25 20:47:09  对本文有异议

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

  1. 1 private IEnumerable<ModelValidator> GetValidator(Type type)
  2. 2 {
  3. 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. 4 }

 

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

  1. IEnumrable<ModelValidator> GetValidator(ControllerContext context)
  2. {
  3. return ModelValidatorProviders.Providers.GetValidator(this,context)
  4. }
    其中Providers来源:
    private static readonly ModelValidatorProviderCollection _providers=new ModelValidatorProviderCollecton
    {
      new DataAnnotationModelValidatorProvider(),
      new DataErrorInfoModelValidatorProvider(),
      new ClinetDataTypeModelValidatorProvider()
    }
  1. 继续实现 ProvidetsGetValidator的方法:
    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>());
  1.   }
    }

 

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

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

  1. public class DataAnnotationModelValidatorProvider:AssocitatedValidatorProvider
  2. {
  3. //这里只编辑主要的实现方法
  4. // 这里的DataAnnotationModelValidatorFactory的系统定义的一个委托。如果元数据属性未定义在AttributeFactories中 则采用默认的ModelValidator对象
  5. internal static DataAnnotationModelValidatorFactory DefaultAttributeFactory=(ModelMetaData metadata,ControllerContext context,ValidatorAttribute attrubute)=>new DataAnnotaionModelValidator(metadata,context,attribute);
  6. //主要为创建元数据"自我验证"集合,可以通过RegisterValidatableObjectAdapter(Type modelType,Type adapterType)来实现自我注册
  7. internal static Dictionary<Type,DataAnnotationModelValidatorFactiory> AttributeFactories=DataAnnotationModelValidatorProvider.BuildAttributeFactoriesDictionary();
  8. //接下来是最主要的代码了
  9. protext override IEnumerable<ModelValidator> GetValidators(ModelMetaData metadata,ControllerContext context,ValidatorAttribute attributes)
  10. {
  11. var result=new List<ModelValidator>;
  12. try{
  13. //这一步的意思是: AddImplicitRequiredAttributeForValueTypes (为值类型添加隐式必填验证) 值为True,元数据也声明了Required=True,则必须在attributes里包含 RequiredAttribute if(DataAnnotatoonModelValidatorProvider.AddImplicitRequiredAttributeForValueType && metadata.IsRequired)
  14. {
  15. if(!attributes.Any((Attribute t)=>t is RequiredAttribute))
  16. {
  17. attrubutes=attribites.concat(new RequiredAttribute[]{new RequiredAttrbute()});
  18. }
  19. }
  20. foreach(var ValidatorAttribute current in attributes.ofType<ValidatorAttribute>)
  21. {
  22. DataAnnotationModelValidatorFactory defaultFactory;
  23. if(!DataAnnotationModelValidatorProvider.AttrbuteFactories.TryValue(current.GetType(),out defualtFactory))
  24. {
  25. defaultFactory=DataAnnotationModelValidatorProvider.DefaultAttrbuteFactoty;
  26. }
  27. result.Add(defaultFactory(metadata,context,current))
  28. }
  29. if(typeof(IValidatableObject).IsAssignableForm(medatat.ModelType))
  30. {
  31. DataAnnotationsValidatableObjectAdapterFactory defaultValidatableFactory;
  32. if (!DataAnnotationsModelValidatorProvider.ValidatableFactories.TryGetValue(metadata.ModelType, out defaultValidatableFactory))
  33. {
  34. defaultValidatableFactory = DataAnnotationsModelValidatorProvider.DefaultValidatableFactory;
  35. }
  36. result.Add(defaultValidatableFactory(metadata, context));
  37. }
  38. }
  39. finally{
  40. }
  41. return result;
  42. }
  43. //上面这个方法写了这么多无非就是 根据元数据上的属性获取继承了ModelValidator的对象集合,然后利用集合里每个对象所定义的Validator方法进行验证
  44. //下面是一些自定义注册方法
  45.  
  46. public static void RegistAdapter(Type attrbuteType,Type adaperType)
  47. {
  48. //获取当前 adaperType的特定构造函数
  49. ConstructorInfo constructor=adapterType.GetConstructor(typeOf(ModelMetadata),typeof(ControllerContext),attrbuteType);
  50. try{
  51. DataAnnotationModelValidatorProvider.AttributeFacties[attrbuteType]=((ModelMedatada metadata,ControllerContext context,ValidatorAttribute attribute)=>(ModelValidator)constructor.Invoker(new object[]{metadata,context,attrbute}));
  52. }
  53. finally{
  54. }
  55. }
  56. //直接用委托方法注册
  57. public static void RegisterAdapterFactory(Type attributeType,DataAnnotationsModelValidatorFactory factory) BuildAttributeFacoriesDictionary
  58. {
  59. //还有好多自定义注册方法 反编译后查看吧
  60. //下面实现的是系统自定义一些ValidatorAttribute
  61. private static Dictionary<Type,DataAnnotationModelValidatorFactory> dictionary=new Dictionary<Type,DataAnnotationModelValidatorFactory>();
  62. DataAnnotationsModelValidatorProvider.AddValidationAttributeAdapter(dictionary, typeof(RangeAttribute), (ModelMetadata metadata, ControllerContext context, ValidationAttribute attribute) => new RangeAttributeAdapter(metadata, context, (RangeAttribute)attribute));
  63. DataAnnotationsModelValidatorProvider.AddValidationAttributeAdapter(dictionary, typeof(RegularExpressionAttribute), (ModelMetadata metadata, ControllerContext context, ValidationAttribute attribute) => new RegularExpressionAttributeAdapter(metadata, context, (RegularExpressionAttribute)attribute));
  64. DataAnnotationsModelValidatorProvider.AddValidationAttributeAdapter(dictionary, typeof(RequiredAttribute), (ModelMetadata metadata, ControllerContext context, ValidationAttribute attribute) => new RequiredAttributeAdapter(metadata, context, (RequiredAttribute)attribute));
  65. DataAnnotationsModelValidatorProvider.AddValidationAttributeAdapter(dictionary, typeof(StringLengthAttribute), (ModelMetadata metadata, ControllerContext context, ValidationAttribute attribute) => new StringLengthAttributeAdapter(metadata, context, (StringLengthAttribute)attribute));
  66. DataAnnotationsModelValidatorProvider.AddValidationAttributeAdapter(dictionary, ValidationAttributeHelpers.MembershipPasswordAttributeType, (ModelMetadata metadata, ControllerContext context, ValidationAttribute attribute) => new MembershipPasswordAttributeAdapter(metadata, context, attribute));
  67. DataAnnotationsModelValidatorProvider.AddValidationAttributeAdapter(dictionary, ValidationAttributeHelpers.CompareAttributeType, (ModelMetadata metadata, ControllerContext context, ValidationAttribute attribute) => new CompareAttributeAdapter(metadata, context, attribute));
  68. DataAnnotationsModelValidatorProvider.AddValidationAttributeAdapter(dictionary, ValidationAttributeHelpers.FileExtensionsAttributeType, (ModelMetadata metadata, ControllerContext context, ValidationAttribute attribute) => new FileExtensionsAttributeAdapter(metadata, context, attribute));
  69. DataAnnotationsModelValidatorProvider.AddDataTypeAttributeAdapter(dictionary, ValidationAttributeHelpers.CreditCardAttributeType, "creditcard");
  70. DataAnnotationsModelValidatorProvider.AddDataTypeAttributeAdapter(dictionary, ValidationAttributeHelpers.EmailAddressAttributeType, "email");
  71. DataAnnotationsModelValidatorProvider.AddDataTypeAttributeAdapter(dictionary, ValidationAttributeHelpers.PhoneAttributeType, "phone");
  72. DataAnnotationsModelValidatorProvider.AddDataTypeAttributeAdapter(dictionary, ValidationAttributeHelpers.UrlAttributeType, "url");
  73. return dictionary;
  74. }
  75. }

 

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

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

  1. public sealed override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata,ControllerContext context)
  2. {
  3. if(metadata==null)
  4. throw new ArgumentNullExecption("metadata");
  5. if(context==null)
  6. throw new ArgumentNullExecption("context");
  7. }
  8. protect abstract IEnumrable<ModelValidator> GetValidators(ModelMetadata,ControllerContext,IEunmerable<Attribute> atttibutes);//这个抽象方法在上面类(DataAnnotationModelValidatorProvider)里有具体的实现
  9.  
  10. protected override ICustomTypeDescriptor GetTypeDescriptor(Type type)
  11. {
  12. return TypeDescriptorHepler.Get(type);
  13. }
  14. pritvate IEnumerable<ModelValidator> GetValidatorForProperty(ModelMetadata metadata,ControllerContextg context)
  15. {
  16. IcustomTypeDescriptor typedescriptor=this.GetTypeDescriptor(metadata.ContainerType);
  17. PropertyDescriptor propertyDescriptor=typedescriptor.GetProperties.Find(metadata.PropertyName,true);
  18. if(propertyDescriptor==null)
  19. throw new ArgumentException("PropertyNoFound");
  20. return this.GetValidator(metadata,context,propertyDescriptor.Attributes.OfType<Attribute>);
  21. }
  22. private IEnumerable<ModelValidator> GetValidatorsForType(MedelMetadata metadata,ControllerContext context)
  23. {
  24. return this.GetValidator(metadata,context,this.GetTypeDescriptor(metadata.ModelType).GetAttributes().Cast<Attribue>);
  25. }

 

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

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

  1. public class DataAnnotationModelValidator:ModelValidator
  2. {
  3. public override IEnumerable<ModelValidatorResult> Validate(object container)
  4. {
  5. ValidationContext validationContext=new ValidationContext(container??base.Metadata.Model,null,null);
  6. validationContext.DisplayName=this.Metadata.DisPlayName();
  7.     validationResult result=this.Attribute.GetValidationResult(base.Metadata.Model,validationContext);
  8.     if(result!=result.Scuess)
  9.     {
  10. yeild return New ModelValidateResult
    {
  11. Message=validation.ErrorMessage;
  12.    };
  13. yeild break;
  14.    }
  15. }
  16. protect internal string ErrorMessage
  17. {
  18. get{
  19. return this.Attribute.FormatErrorMessage(base.Metadata.DispalyName());
  20. }
  21. }
  22. }

 

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号