0

我遇到的情況,我有一定的基類,我們將其稱之爲「PagingCriteriaBase」自定義模型綁定在Asp.Net核心的子類

public class PagingCriteriaBase : CriteriaBase 
{ 
    public Int32 CountOfItemsPerPage { get; set; } 
    public SortOrder SortingOrder { get; set; } 
    public String SortBy { get; set; } 
    public Int32 PageNo { get; set; } 
    public PagingCriteriaBase(Int32 pageNo,Int32 countOfItemsPerPage, SortOrder sortingOrder, String sortBy,Int32 draw) 
    { 
     this.PageNo = pageNo>0?pageNo:1; 
     this.CountOfItemsPerPage = countOfItemsPerPage>0?countOfItemsPerPage:10; 
     this.SortBy = sortBy; 
     this.SortingOrder = sortingOrder; 
     this.Draw = draw; 
    } 
} 

,然後我有其他類將繼承「 PagingCriteriaBase」,例如

public class UserCriteria:PagingCriteriaBase 
{ 
    public String Email { get; set; } 
    public String DisplayName { get; set; } 

    public UserCriteria():base(1,0,SortOrder.Asc,"",1) 
    { 

    } 
    public UserCriteria(Int32 pageNo,Int32 countOfItemsPerPage, SortOrder sortingOrder, String sortBy, Int32 draw) 
     :base(pageNo, countOfItemsPerPage,sortingOrder,sortBy,draw) 
    { 
    } 
} 

現在我想要做的是什麼,我想創建一個模型綁定,將與網頁API方法一起使用,並且模型粘結劑將與所有的子類中使用「PagingCriteriaBase」,這個模型綁定的目的是根據t來設置一些屬性O數據從Ajax請求的到來,我想做到以下幾點:

  1. 我創建瞭如下一個實現 「IModelBinder」 一類:

    public class PagingModelBinder : IModelBinder 
    { 
    
    public Task BindModelAsync(ModelBindingContext bindingContext) 
    { 
        if (!bindingContext.ModelType.IsSubclassOf(typeof(PagingCriteriaBase))) 
        { 
         return Task.FromResult(false); 
        } 
    
        String startModelName = "start"; 
        String lengthModelName = "length"; 
        var startResult = bindingContext.ValueProvider.GetValue(startModelName); 
        var lengthResult = bindingContext.ValueProvider.GetValue(lengthModelName); 
        Int32 start, length; 
        if (!Int32.TryParse(startResult.FirstValue, out start)) 
        { 
         start = 0; 
        } 
        if (!Int32.TryParse(lengthResult.FirstValue, out length)) 
        { 
         length = SystemProp.PAGE_SIZE; 
        } 
        else 
        { 
         length = 20; 
        } 
        var model = Activator.CreateInstance(bindingContext.ModelType); 
    
        Int32 pageNo = (int)Math.Ceiling((decimal)start/length); 
    
        bindingContext.ModelState.SetModelValue("PageNo", new ValueProviderResult(pageNo.ToString())); 
        bindingContext.ModelState.SetModelValue("CountOfItemsPerPage", new ValueProviderResult(length.ToString())); 
        bindingContext.Model = model; 
        var mProv = (IModelMetadataProvider)bindingContext.HttpContext.RequestServices.GetService(typeof(IModelMetadataProvider)); 
    
        bindingContext.Result = ModelBindingResult.Success(model); 
    
        return Task.CompletedTask; 
    } 
    } 
    
  2. 我創建了一個ModelBinderProvider如下:

    public class PagingEntityBinderProvider:IModelBinderProvider 
    { 
    public IModelBinder GetBinder(ModelBinderProviderContext context) 
    { 
        if (context == null) 
        { 
         throw new ArgumentNullException(nameof(context)); 
        } 
    
        if (context.Metadata.ModelType == typeof(PagingCriteriaBase)) 
        { 
         return new BinderTypeModelBinder(typeof(PagingModelBinder)); 
        } 
    
        return null; 
    } 
    } 
    
  3. 我註冊使用模型綁定:

    services.AddMvc(op => op.ModelBinderProviders.Insert(0, new PagingEntityBinderProvider())) ; 
    
  4. 在我的Web API方法,我做了以下內容:

    public IActionResult GetAll([ModelBinder(typeof(PagingModelBinder))]UserCriteria crit) 
    { 
    //Code goes here 
    } 
    

當我使用的模型粘合劑如上面我發現,一旦代碼到達的Web API的方法,從數值沒什麼例如「PageNo」屬性保持爲1,所以我需要做的是讓模型聯編程序設置子類對象的所有相關屬性,而不管類本身的類型如何,最後一次代碼到達Web API方法,模型將會正確設置所有屬性,請問我需要在代碼中更改哪些內容以處理此問題?

請注意,我使用Asp.Net核2.0

回答

0

我想那是因爲你還沒有設置模型的任何財產,僅實例化它。

我想我們可以走線槽與反射子類的所有屬性,並設置基於模型的狀態值的值(假設屬性名稱是用模型狀態鍵相同)

public Task BindModelAsync(ModelBindingContext bindingContext) 
    { 
     ... 
     bindingContext.ModelState.SetModelValue("PageNo", new ValueProviderResult(pageNo.ToString())); 
     bindingContext.ModelState.SetModelValue("CountOfItemsPerPage", new ValueProviderResult(length.ToString())); 

     ModelStateEntry v; 
     foreach (PropertyInfo pi in bindingContext.ModelType.GetProperties()) 
     { 
      if (bindingContext.ModelState.TryGetValue(pi.Name, out v)) 
      { 
       try 
       { 
        pi.SetValue(model, v.RawValue); 
       } 
       catch 
       { 
       } 
      } 
     } 

     bindingContext.Model = model; 
     ... 
    } 

改變你的PagingEntityBinderProvider

public class PagingEntityBinderProvider : IModelBinderProvider 
{ 
    public IModelBinder GetBinder(ModelBinderProviderContext context) 
    { 
     if (context == null) 
     { 
      throw new ArgumentNullException(nameof(context)); 
     } 

     if (typeof(PagingCriteriaBase).IsAssignableFrom(context.Metadata.ModelType)) 
     { 
      return new BinderTypeModelBinder(typeof(PagingModelBinder)); 
     } 

     return null; 
    } 
} 

並從Web API刪除ModelBinder的屬性的方法

public IActionResult GetAll(UserCriteria crit) 
{ 
    //Code goes here 
} 
+1

感謝@laksmono,首先,「PropertyInfo」的SetValue方法給了我一個錯誤,因爲String和Int32之間的類型不同,但我將代碼更改爲:012.SXValue(model,Convert.ChangeType(v .RawValue,pi.PropertyType)) 並按預期工作。 –