ModelValidator基于元数据的验证
ModelValidator主要是应用在ModelMetadata元数据的类型上或类型属性上。它是验证的基础类型,所有的ModelValidatorProviders、DataAnnotationValidator、DataAnnotationValidatorProvider都是主要通过GetValidators这个方法来获取IEnumerable<ModelValidator>对象。然后循环这个迭代对象,利用ModelValidator的Validator对每个元数据进行验证。有个例子可以很好的说明:
private IEnumerable<ModelValidator> GetValidator(Type type)
{
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;
}
}
元数据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基于元数据的验证的更多相关文章
- 基于.Net Framework 4.0 Web API开发(4):ASP.NET Web APIs 基于令牌TOKEN验证的实现
概述: ASP.NET Web API 的好用使用过的都知道,没有复杂的配置文件,一个简单的ApiController加上需要的Action就能工作.但是在使用API的时候总会遇到跨域请求的问题, ...
- 基于easyui的验证扩展
基于easyui的验证扩展 ##前言 自己做项目也有好几年的时间了,一直没有时间整理自己的代码,趁春节比较闲,把自己以前的代码整理了一篇.这是基于easyui1.2.6的一些验证扩展,2012年就开始 ...
- Web APIs 基于令牌TOKEN验证的实现
Web APIs 基于令牌TOKEN验证的实现 概述: ASP.NET Web API 的好用使用过的都知道,没有复杂的配置文件,一个简单的ApiController加上需要的Action就能工作.但 ...
- ASP.NET Web APIs 基于令牌TOKEN验证的实现(保存到DB的Token)
http://www.cnblogs.com/niuww/p/5639637.html 保存到DB的Token 基于.Net Framework 4.0 Web API开发(4):ASP.NET We ...
- .net core 基于Claim登录验证
网站,首先需要安全,实现安全就必须使用登录验证,.net core 基于Claim登录验证就很简单使用. Claim是什么,可以理解为你的身份证的中的名字,性别等等的每一条信息,然后Claim组成一个 ...
- 在 Linux 客户端配置基于 Kerberos 身份验证的 NFS 服务器
在这篇文章中我们会介绍配置基于 Kerberos 身份验证的 NFS 共享的整个流程.假设你已经配置好了一个 NFS 服务器和一个客户端.如果还没有,可以参考 安装和配置 NFS 服务器[2] - 它 ...
- ADO.NET实体框架Entity Framework模型-基于元数据解析
上一篇简单介绍了EF的XML模型结构,在基于xml解析一文中,主要使用xml查询技术Xpath,XQuery来得到实体模型中相应信息的,由于这种方式在数据库庞大,表关系复杂的情况下,有诸 ...
- 批量部署SSH基于key的验证脚本
工作中,使用ansible等自动化运维工具实现服务器批量自动化运维管理,需要先解决管理端和被管理端的免密码登录,可以脚本实现ssh基于key的验证,代码如下: #!/bin/bash PASS=123 ...
- 基于COCO数据集验证的目标检测算法天梯排行榜
基于COCO数据集验证的目标检测算法天梯排行榜 AP50 Rank Model box AP AP50 Paper Code Result Year Tags 1 SwinV2-G (HTC++) 6 ...
随机推荐
- .net上传文件,利用npoi读取文件信息到datatable里
整理代码,.net上传文件,利用npoi读取文件到datatable里,使用了FileUpload控件,代码如下: protected void Button1_Click(object sender ...
- rails 新建user的phonenumber字段
1.新建字段 //rails g migration add_字段名_to_表名 字段名:字段类型 rails g migration add_title_to_contents title:stri ...
- 一道区间DP的水题 -- luogu P2858 [USACO06FEB]奶牛零食Treats for the Cows
https://www.luogu.org/problemnew/show/P2858 方程很好想,关键我多枚举了一次(不过也没多大关系) #include <bits/stdc++.h> ...
- centos7 sqoop 1 搭建笔记
1.require : java环境,hadoop,hive ,mysql2.下载解压sqoop13.设置环境变量 export SQOOP_HOME=/data/spark/bin/sqoop ex ...
- 2018.11.06 bzoj1093: [ZJOI2007]最大半连通子图(缩点+拓扑排序)
传送门 先将原图缩点,缩掉之后的点权就是连通块大小. 然后用拓扑排序统计最长链数就行了. 自己yyyyyy了一下一个好一点的统计方法. 把所有缩了之后的点都连向一个虚点. 然后再跑拓扑,这样最后虚点的 ...
- 2018.10.29 bzoj4564: [Haoi2016]地图(仙人掌+莫队)
传送门 根据原图建一棵新的树. 把原图每一个环上除了深度最浅的点以外的点全部向深度最浅的点连边. 然后可以搞出来一个dfsdfsdfs. 这个时候我们就成功把问题转换成了对子树的询问. 然后就可以对权 ...
- IBM X3650 M3/M4的服务器装系统
IBM X3650 M3/M4的服务器一般都有两块以上的硬盘.所以如果没有做RAID,那首先应该做好raid 磁盘阵列.本文装系统的前提是RAID已经做好. 一般安装系统的方式为先在IBM官网下载对应 ...
- ubuntu 16.04 安装pgadmin3
1.Ctrl+Alt+t 打开终端 2.输入 wget -q -O - http://www.pgadmin.org/pgp/archive_key_debian_Ubuntu.gpg | sudo ...
- ajax实现
AJAX是为了实现异步通信,提高用户体验度.JavaScript本身并不具有向服务器发送请求的功能(不使用NodeJs),要么使用window.open()方法重新打开一个页面向服务器发送请求,要么使 ...
- 20155205 《Java程序设计》实验四 Android程序设计
20155205 <Java程序设计>实验四 Android程序设计 一.实验内容及步骤 (一) Android Stuidio的安装测试 参考<Java和Android开发学习指南 ...