Mic*_*ltu 8 c# asp.net json.net asp.net-web-api asp.net-web-api2
public class MyModel
{
[JsonProperty(PropertyName = "foo", Required = Required.Always)]
public String Bar;
}
public class MyController : ApiController
{
public String PostVersion1([FromBody] MyModel myModel)
{
if (ModelState.IsValid)
{
if (myModel.Bar == null)
return "What?!";
else
return "Input is valid.";
}
else
{
return "Input is invalid.";
}
}
}
Run Code Online (Sandbox Code Playgroud)
结果:
Input |Output
-------------------|------
{ "bad" : "test" } | What?!
{ "Bar" : "test" } | What?!
{ "foo" : "test" } | Input is valid.
Run Code Online (Sandbox Code Playgroud)
显然支持JsonPropertyAttribute,因为我能够设置PropertyName并使其生效.但是,我希望ModelState.IsValid前两个示例输入为false,因为RequiredJsonProprty参数设置为Always.
如果我只是通过JsonConvert运行它:
JsonConvert.DeserializeObject<MyModel>(@"{'bad':'test'}");
Run Code Online (Sandbox Code Playgroud)
在反序列化期间抛出异常,如预期的那样:
Result Message: Newtonsoft.Json.JsonSerializationException : Required property 'foo' not found in JSON. Path '', line 1, position 14.
Run Code Online (Sandbox Code Playgroud)
默认情况下JsonMediaTypeFormatter不依赖heJsonProperty来决定模型字段是否是必需的。然而,它确实依赖于RequiredAttribute
如果您想这样做,请实现一个新的IRequiredMemberSelector并将其设置为MediaTypeFormatter.RequiredMemberSelector.
在您的实施中,IRequiredMemberSelector您将传递一个MemberInfo. 您可以使用它来评估模型成员是否具有该JsonProperty属性以及是否设置了必需的标志,最后返回 true 或 false。这将传播到该ModelState.IsValid属性(但它不会使用 JSON.NET 错误消息,而是使用 DataAnnotations/WebApi 错误消息。
如果您这样做,那么我建议您也保留默认行为。
为了解决这个问题,我最终创建了自己的自定义 JSON.NET MediaTypeFormatter。我的格式化程序允许 JSON.NET 反序列化异常冒泡,从而将异常信息返回给调用者。
这是我构建的 MediaTypeFormatter:
public class JsonMediaFormatter : MediaTypeFormatter
{
private readonly JsonSerializer _jsonSerializer = new JsonSerializer();
public JsonMediaFormatter()
{
SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));
}
public override Boolean CanReadType(Type type)
{
if (type == null)
return false;
return true;
}
public override Boolean CanWriteType(Type type)
{
if (type == null)
return false;
return true;
}
public override Task<Object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)
{
return Task.FromResult(Deserialize(readStream, type));
}
public override Task WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken)
{
Serialize(writeStream, value);
return Task.FromResult(0);
}
private Object Deserialize(Stream readStream, Type type)
{
var streamReader = new StreamReader(readStream);
return _jsonSerializer.Deserialize(streamReader, type);
}
private void Serialize(Stream writeStream, Object value)
{
var streamWriter = new StreamWriter(writeStream);
_jsonSerializer.Serialize(streamWriter, value);
streamWriter.Flush();
}
}
Run Code Online (Sandbox Code Playgroud)
为了在内置格式化程序上使用此格式化程序,我将这一行添加到我的 WebApiConfig 中:
config.Formatters.Insert(0, new Formatters.JsonMediaFormatter());
Run Code Online (Sandbox Code Playgroud)
通过将其插入索引 0,它优先于内置格式化程序。如果您愿意,可以删除内置的 JSON 格式化程序。
在这种情况下,ModelState在操作中始终有效,因为如果反序列化失败,在触发操作之前会向用户抛出异常。为了仍然使用空FromBody参数执行操作,需要做更多的工作。
| 归档时间: |
|
| 查看次数: |
7547 次 |
| 最近记录: |