2015-01-14 43 views
2

我有很多問題試圖讓我的Web API RESTful POST方法在我的控制器中使用ModelState驗證模型。Web API未執行自定義ActionFilterAttribute

this網站提到需要創建一個自定義過濾器繼承ActionFilterAttribute我似乎無法通過單元測試。當單步執行代碼時,它永遠不會遇到OnActionExecuting方法,並且ModelState.IsValid總是返回True。我到處搜索了代碼示例,並嘗試了所有代碼,但都沒有工作。我甚至引用了正確的名稱空間,正如你在下面的代碼中看到的那樣。

ValidationActionFilter.cs

using System.Net; 
using System.Net.Http; 
using System.Web.Http.Controllers; 
using System.Web.Http.Filters; 
using System.Linq; 
using System.Diagnostics; 

namespace OrbitWorksAPI.Filters 
{ 
    public class ValidationActionFilter : ActionFilterAttribute 
    { 
     public override void OnActionExecuting(HttpActionContext actionContext) 
     { 
      Debug.WriteLine("ACTION 1 DEBUG pre-processing logging"); 

      var modelState = actionContext.ModelState; 

      if (actionContext.ActionArguments.Any(kv => kv.Value == null)) 
       actionContext.Response = actionContext.Request 
        .CreateErrorResponse(HttpStatusCode.BadRequest, "Arguments cannot be null"); 

      if (!modelState.IsValid) 
       actionContext.Response = actionContext.Request 
        .CreateErrorResponse(HttpStatusCode.BadRequest, modelState); 
     } 
    } 
} 

WebApiConfig.cs

public static class WebApiConfig 
{ 
    public static void Register(HttpConfiguration config) 
    { 
     // Register routes 
     ... 

     // Register filters 
     config.Filters.Clear(); 
     config.Filters.Add(new Filters.ValidationActionFilter()); 
    } 
} 

我有此控制器POST方法:

Controller.cs

[HttpPost] 
[ResponseType(typeof(Contracts.Models.IInvoice))] 
[ActionFilterAttribute] 
public async Task<IHttpActionResult> Post(Contracts.Models.IInvoice invoice) 
{ 
    if (!ModelState.IsValid) 
     BadRequest(); 

    var newInvoice = await _repository.UpsertInvoice(invoice); 
    if (newInvoice != null) 
     return CreatedAtRoute<Contracts.Models.IInvoice>("invoice", new { newInvoice.Id }, newInvoice); 

    return Conflict(); 
} 

我也有一個單元測試:

ControllerUnitTests.cs

[TestMethod] 
public async Task POST_New_Invoice_With_Required_Fields_Missing() 
{ 
    // Arrange 
    Contracts.Models.IInvoice model = new Models.Invoice() { }; 

    var config = new HttpConfiguration(); 
    config.Filters.Add(new Filters.ValidationActionFilter()); 

    var repository = new Mock<Contracts.Repository.IInvoiceRepository>(); 
    repository.Setup(x => x.UpsertInvoice(It.IsAny<Contracts.Models.IInvoice>())) 
     .Returns(Task.FromResult<Contracts.Models.IInvoice>(model)); 

    // set up the controller instance. 
    var controller = new InvoiceController(repository.Object); 
    controller.Request = new HttpRequestMessage(); 
    controller.Configuration = config; 

    // Act 
    var result = await controller.Post(model); 

    // Assert 
    var response = result as InvalidModelStateResult; 

    Assert.IsNotNull(response); 
} 

和模型:

Invoice.cs

public class Invoice : IInvoice 
{ 
    [Key] 
    public int Id { get; set; } 

    [Required] 
    public int InvoiceNo { get; set; } 

    [Required] 
    public int CompanyId { get; set; } 

    [Required] 
    [MaxLength(50)] 
    public string CompanyName { get; set; } 

    [Required] 
    [MaxLength(250)] 
    public string InvoiceAddress { get; set; } 

    [Required] 
    [MaxLength(250)] 
    public string SiteAddress { get; set; } 

    [Required] 
    public string OrderDate { get; set; } 

    [Required] 
    [MaxLength(10)] 
    public string OrderNo { get; set; } 

    [Required] 
    public string OnHire { get; set; } 

    [Required] 
    public string InvoiceDate { get; set; } 

    [Required] 
    public decimal NettAmount { get; set; } 

    [Required] 
    public decimal VATAmount { get; set; } 

    [Required] 
    public decimal TotalAmount { get; set; } 

    [Required] 
    public bool IsCreditNote { get; set; } 

    [Required] 
    public float VATRate { get; set; } 
} 

回答

0

由於您將模型狀態驗證的行爲與控制器中包含的邏輯分開,因此您應該查看單元測試以驗證其功能。

如果你想驗證任何排序無效模式將被過濾器拒絕再簡單的單元測試自身的過濾器和放心,他們打你的控制器動作之前,無效的模型將被拒絕。

有關單元測試操作過濾器的示例,請參閱Web API Action Filter Unit Tests

如果要在config.Filters集合中全局添加它,並且還可以從操作中刪除模型狀態檢查,則還可以在操作方法上刪除[ActionFilterAttribute]