假设我向我的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}
我有以下汽车类定义:
public class Car {
public int Id { get; set; }
[Required]
[StringLength(20)]
public string Make { get; set; }
[Required]
[StringLength(20)]
public string Model { get; set; }
public int Year { get; set; }
[Range(0, 500000)]
public float Price { get; set; }
}
我得到的回复如下:
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);
}
我仍然无法抑制这种行为。
对不起,我最初误解了你的问题。 好的,这是您需要做的:
创建从原始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
替换为自定义的,然后就可以了。
我知道这是一个老问题,但如果其他人感兴趣,我设法通过创建一个[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);
}
}