2012-09-17 74 views
3

假設禁止RequiredAttribute標籤驗證我發送者的要求,我的API:爲JsonMediaTypeFormatter中的ASP.NET Web API

POST http://localhost:4940/api/cars HTTP/1.1 
User-Agent: Fiddler 
Host: localhost:4940 
Content-Type: application/json 
Content-Length: 44 

{"Make":"Make1","Year":2010,"Price":10732.2} 

和我有以下汽車類定義:

響應我回來瞭如下:

HTTP/1.1 400 Bad Request 
Cache-Control: no-cache 
Pragma: no-cache 
Content-Type: application/json; charset=utf-8 
Expires: -1 
Server: Microsoft-IIS/8.0 
X-AspNet-Version: 4.0.30319 
X-SourceFiles: =?UTF-8?B?RTpcRHJvcGJveFxCb29rc1xQcm9XZWJBUEkuU2FtcGxlc1xDaGFwdGVyMTNcRGF0YUFubm90YXRpb25WYWxpZGF0aW9uQXR0cmlidXRlc1NhbXBsZVxEYXRhQW5ub3RhdGlvblZhbGlkYXRpb25BdHRyaWJ1dGVzU2FtcGxlXGFwaVxjYXJz?= 
X-Powered-By: ASP.NET 
Date: Mon, 17 Sep 2012 11:38:58 GMT 
Content-Length: 182 

{"Message":"The request is invalid.","ModelState":{"car":["Required property 'Model' not found in JSON. Path '', line 1, position 44."],"car.Model":["The Model field is required."]}} 

這裏是更可讀的消息體的形式:

{ 
    "Message": "The request is invalid.", 
    "ModelState": { 
     "car": [ 
      "Required property 'Model' not found in JSON. Path '', line 1, position 44." 
     ], 
     "car.Model":[ 
      "The Model field is required." 
     ] 
    } 
} 

正如你所看到的,我也有車一個額外的錯誤信息,我猜JsonMediaTypeFormatter進行驗證,以及和它未能執行讀操作。

這是問題嗎?有沒有什麼辦法可以抑制JsonMediaTypeFormatter級別的驗證?我不希望格式化程序執行驗證,因爲在格式化程序讀取消息正文後,也會通過IBodyModelValidator執行驗證。

編輯:

我調試的源代碼,並將其大桶出JsonMediaTypeFormatter如果屬性標記爲必選,而不是提供拋出一個錯誤。下面的代碼是從JsonMediaTypeFormatter部分:

// Error must always be marked as handled 
// Failure to do so can cause the exception to be rethrown at every recursive level and overflow the stack for x64 CLR processes 
jsonSerializer.Error += (sender, e) => 
{ 
    Exception exception = e.ErrorContext.Error; 
    formatterLogger.LogError(e.ErrorContext.Path, exception); 
    e.ErrorContext.Handled = true; 
} 

,這觸發了ModelStateFormatterLogger.LogError方法,提出了ModelState裏面的錯誤:

public void LogError(string errorPath, Exception exception) 
{ 
    if (errorPath == null) 
    { 
     throw Error.ArgumentNull("errorPath"); 
    } 
    if (exception == null) 
    { 
     throw Error.ArgumentNull("exception"); 
    } 

    string key = ModelBindingHelper.ConcatenateKeys(_prefix, errorPath); 
    _modelState.AddModelError(key, exception); 
} 

我仍然無法抑制這種行爲。

+0

在哪個發佈中你得到了這個迴應?我沒有在Webapi 2.1 –

回答

3

對不起,我最初誤解了你的問題。這裏 OK是你需要做什麼:

創建一個類從原來的JsonMediaTypeFormatter派生並設置自定義IRequiredMemberSelector

public class MyJsonMediaTypeFormatter : JsonMediaTypeFormatter 
    { 
     public MyJsonMediaTypeFormatter() : base() 
     { 
      RequiredMemberSelector = new MyRequiredMemberSelector(); 
     } 
    } 

在這種定製IRequiredMemberSelector只定義爲不所需的所有屬性。

public class MyRequiredMemberSelector : IRequiredMemberSelector 
{ 
    public bool IsRequiredMember(System.Reflection.MemberInfo member) 
    { 
     return false; 
    } 
} 

現在用定製一個替換默認JsonMediaTypeFormatter和你去。

+3

這個問題,謝謝!替換格式化器上的IRequiredMemberSelector會更好:GlobalConfiguration.Configuration。Formatters.JsonFormatter.RequiredMemberSelector'。我也發現'JsonContractResolver'如此無用。直接使用'DefaultContractResolver'也可以解決問題。只有'JsonContractResolver'所做的有用的事情是將'IgnoreSerializableAttribute'設置爲'false'。 – tugberk

+0

是的,你是對的,我得到了太多:) 非常奇怪,JsonContractResolver是內部的,如果它是公開的和可覆蓋的,它可能有一些用處! –

+0

它裏面沒有什麼可以重寫的人。這顯然是無用的。 – tugberk

0

我知道這是一個古老的問題,但如果其他人有興趣,我設法通過創建一個[IsNotEmpty]註解來解決這個問題。

這使用反射來確定在屬性上是否存在Empty的實現,並且如果這樣比較它。然後這會在模型驗證時獲得,而不是在解析JSON時。

public class IsNotEmptyAttribute : ValidationAttribute 
{ 

    public override bool IsValid(object value) 
    { 

     if (value == null) return false; 

     var valueType = value.GetType(); 
     var emptyField = valueType.GetField("Empty"); 

     if (emptyField == null) return true; 

     var emptyValue = emptyField.GetValue(null); 

     return !value.Equals(emptyValue); 

    } 
}