2016-12-05 64 views
2

我正在使用Web API 5構建Web Service。我通過擴展IModelBinder接口來實現自定義模型綁定器,以將複雜類型映射爲參數以採取行動。綁定部分工作正常。但是模型驗證不會發生。 ModelState.IsValid始終爲true。未使用自定義模型綁定器觸發Web API驗證

public class PagingParamsVM 
{ 
     [Range(1, Int32.MaxValue, ErrorMessage = "Page must be at least 1")] 
     public int? Page { get; set; } 

     [Range(1, Int32.MaxValue, ErrorMessage = "Page size must be at least 1")] 
     public int? PageSize { get; set; } 
} 

public class PaginationModelBinder : IModelBinder 
{ 
     public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext) 
     { 
       var model = (PagingParamsVM)bindingContext.Model ?? new PagingParamsVM(); 
       //model population logic 
       ..... 

       bindingContext.Model = model; 
       return true; 
     } 
} 

public IEnumerable<NewsItemVM> Get([ModelBinder(typeof(PaginationModelBinder))]PagingParamsVM pegination) 
{ 
      //Validate(pegination); //if I call this explicitly ModelState.IsValid is set correctly. 
      var valid = ModelState.IsValid; //this is always true 
} 

public class ModelStateValidationActionFilter : ActionFilterAttribute 
{ 
     public override void OnActionExecuting(HttpActionContext actionContext) 
     { 
      var valid = actionContext.ModelState.IsValid //this is always true. 
     } 
} 

如果我顯式調用Validate()或使用[FromUri]屬性,則ModelState.IsValid設置正確。

public IEnumerable<NewsItemVM> Get([FromUri]PagingParamsVM pegination) 
{ 
      var valid = ModelState.IsValid; 
} 

我是否應該在模型聯編程序中實現驗證部分。如果是的話,我應該如何執行?

+0

可能重複的[SO回答](http://stackoverflow.com/questions/8668869/custom-model-binder-not-validating-model)。 –

+0

@MihailStancescu我看到了這個問題。它適用於DataAnnotations。但如果我使用FluentValidation或類似的,它將無法正常工作。所以這裏似乎缺少一些東西。 – sajith

回答

2

我找到了答案。默認驗證過程可以在自定義模型綁定器中調用如下,

public abstract class PaginationModelBinder : IModelBinder 
{ 
     public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext) 
     { 
       var model = (PagingParamsVM)bindingContext.Model ?? new PagingParamsVM(); 
       //model population logic 
       ..... 

       bindingContext.Model = model; 

       //following lines invoke default validation on model 
       bindingContext.ValidationNode.ValidateAllProperties = true; 
       bindingContext.ValidationNode.Validate(actionContext); 

       return true; 
     } 
} 

謝謝大家的支持。

+0

精彩,非常感謝.. – Pandiarajan

0

DefaultModelBinder.CreateModel應該幫助你保持模型的狀態:

使用粘結劑可以
public class PaginationModelBinder : DefaultModelBinder 
{ 
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) 
    { 
     if(modelType == typeof(PagingParamsVM)) 
     { 
      var page = default(int?); 
      var model = bindingContext.Model; 
      var valueProvider = bindingContext.ValueProvider; 
      var pageValue = valueProvider.GetValue("Page"); 
      var tmp = default(int); 
      if(pageValue != null && int.TryParse(pageValue.AttemptedValue, out tmp)) 
      { 
       page = tmp; 
      } 

      var pageSize = default(int?); 
      var sizeValue = valueProvider.GetValue("PageSize"); 
      if(sizeValue != null && int.TryParse(sizeValue.AttemptedValue, out tmp)) 
      { 
       pageSize = tmp; 
      } 
      return new PagingParamsVM { Page = page, PageSize = pageSize }; 
     } 
     return base.CreateModel(controllerContext, bindingContext, modelType); 
    } 
} 

的Web API控制器:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Web.Http; 
using System.Web.Mvc; 

public class NewsItemController : ApiController 
{ 
    public IEnumerable<NewsItemVM> Get([ModelBinder(typeof(PaginationModelBinder))]PagingParamsVM pegination) 
    { 
     //Validate(pegination); //if I call this explicitly ModelState.IsValid is set correctly. 
     var valid = ModelState.IsValid; //this is always true 
     return Enumerable.Empty<NewsItemVM>(); 
    } 
} 
+0

Web API沒有DefaultModelBinder。 DefaultModelBinder附帶MVC。 – sajith

+0

@sajith,當您在MVC .NET應用程序中開發Web API時,會出現'DefaultModelBinder' :) –

+0

是的,我知道這一點。但問題是,您無法在控制器擴展ApiController中使用PaginationModelBinder:DefaultModelBinder。 – sajith