ModelValidator基於元數據的驗證

来源:https://www.cnblogs.com/xuyoungzhe98/archive/2018/09/19/9635539.html
-Advertisement-
Play Games

ModelValidator主要是應用在ModelMetadata元數據的類型上或類型屬性上。它是驗證的基礎類型,所有的ModelValidatorProviders、DataAnnotationValidator、DataAnnotationValidatorProvider都是主要通過GetVa ...


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

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • import requests from requests.exceptions import RequestException import re import json from multiprocessing import Pool def get_one_page(url): headers... ...
  • 異常處理,是編程語言或電腦硬體里的一種機制,用於處理軟體或信息系統中出現的異常狀況(即超出程式正常執行流程的某些特殊條件)。 1.異常的類型 異常的類型多種多樣,常見的異常有: 其他的異常: Exception可以捕獲任意異常 2.捕獲異常,處理異常 只有將對應的異常類型捕獲才能進行異常的處理 異 ...
  • 文件名全小寫,可使用下劃線 包應該是簡短的、小寫的名字。如果下劃線可以改善可讀性可以加入。如mypackage。 模塊與包的規範同。如mymodule。 類總是使用首字母大寫單詞串。如MyClass。內部類可以使用額外的前導下劃線。 函數&方法函數名應該為小寫,可以用下劃線風格單詞以增加可讀性。如: ...
  • 深淺拷貝 淺拷貝 a=[[1,2],3,4] b=a[:] #b=a.copy() 淺拷貝 作用 輸出 ['Xiaomei', 345, [15000, 6000]] 淺拷貝copy.copy() 深拷貝copy.deepcopy() 輸出 ['Xiaomei', 345, [15000, 6000 ...
  • 條件語句的執行過程: if 條件判斷註意:1.每個條件後面要使用冒號 : ,表示條件為True時要執行的代碼;2.使用縮進來劃分代碼塊,相同縮進數的語句在一起組成一個代碼塊。 if...else,單條件判斷 if...elif...else,多條件判斷 ...
  • using SqlSugar; using System; using System.Collections.Generic; using System.Configuration; using System.Linq; using System.Web; namespace Web.Code.DA... ...
  • 轉眼九月份了,忙忙碌碌 發現今年還沒開過張,寫一篇吧。 15年在空閑時就倒騰過angularjs那玩意兒 ,覺得還是挺好的,李金龍那厚厚的一本書,只不過沒有系統化應用。最主要的是原來有一個東西沒有用到 那就是路由。在中衡的時候看到黃國文同志用那種全ajax的方式做的網站,那感覺。。。現在公司竟然也這 ...
  • 嚴格意義上來說,簡單工廠模式並不屬於GoF的23種設計模式,但是它是學習其他工廠模式的基礎和前提條件。理解了簡單工廠模式,學習工廠方法模式和抽象工廠模式會比較容易一些。 簡單工廠模式的定義 定義一個工廠類,他可以根據不同的參數返回不同類的實例。通常情況下,被創建的類的實例通常都具有共同的父類。 簡單 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...