所以我有一个ApiController ......
public class MetaDataController : ApiController
{
[HttpPost]
public HttpResponseMessage Test(TestModel model)
{
//Do Stuff
return new HttpResponseMessage(HttpStatusCode.OK);
}
}
接受模特......
[JsonObject(ItemRequired = Required.Always)]
public class TestModel
{
public int Id { get; set; }
public IEnumerable<SubModel> List { get; set; }
}
public class SubModel
{
public int Id { get; set; }
}
以Json的形式......
{ "Id": 1, "List": [{ "Id": 11 }, { "Id": 12 } ] }
当发布到此控制器操作时,TestModel上的属性应该使Json.Net在Json缺少属性时抛出JsonSerializationException。我编写单元测试来确保这种行为按预期工作。
[Test]
public void Test()
{
var goodJson = @"{ 'Id': 1,
'List': [ {'Id': 11}, {'Id': 12} ]
}";
Assert.DoesNotThrow(() => JsonConvert.DeserializeObject<TestModel>(goodJson));
var badJson = @"{ 'Id': 1 }";
Assert.That(()=>JsonConvert.DeserializeObject<TestModel>(badJson),
Throws.InstanceOf<JsonSerializationException>().
And.Message.Contains("Required property 'List' not found in JSON."));
}
当将形式良好的Json发布到controlelr动作时,一切正常。但是如果json缺少必需的属性,则不会抛出任何异常。映射到缺少的属性的TestModel成员为null。
为什么JsonConvert按预期工作,但是通过WebApiController的自动Json反序列化无法遵守TestModel上的属性?
答案 0 :(得分:1)
对于咯咯笑,我决定确定我的应用程序使用Json.Net进行json反序列化。所以我写了一个MediaTypeFormatter
public class JsonTextFormatter : MediaTypeFormatter
{
public readonly JsonSerializerSettings JsonSerializerSettings;
private readonly UTF8Encoding _encoding;
public JsonTextFormatter(JsonSerializerSettings jsonSerializerSettings = null)
{
JsonSerializerSettings = jsonSerializerSettings ?? new JsonSerializerSettings();
SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));
_encoding = new UTF8Encoding(false, true);
SupportedEncodings.Add(_encoding);
}
public override bool CanReadType(Type type)
{
if (type == null)
{
throw new ArgumentNullException();
}
return true;
}
public override bool CanWriteType(Type type)
{
return true;
}
public override Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)
{
var serializer = JsonSerializer.Create(JsonSerializerSettings);
return Task.Factory.StartNew(() =>
{
using (var streamReader = new StreamReader(readStream, _encoding))
{
using (var jsonTextReader = new JsonTextReader(streamReader))
{
return serializer.Deserialize(jsonTextReader, type);
}
}
});
}
public override Task WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext)
{
var serializer = JsonSerializer.Create(JsonSerializerSettings);
return Task.Factory.StartNew(() =>
{
using (
var jsonTextWriter = new JsonTextWriter(new StreamWriter(writeStream, _encoding))
{
CloseOutput = false
})
{
serializer.Serialize(jsonTextWriter, value);
jsonTextWriter.Flush();
}
});
}
}
并修改了我的WebApiConfig以使用它而不是默认值。
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Filters.Add(new HandleSerializationErrorAttribute());
config.Formatters.RemoveAt(0);
var serializerSettings = new JsonSerializerSettings
{
MissingMemberHandling = MissingMemberHandling.Error
};
config.Formatters.Insert(0, new JsonTextFormatter(serializerSettings));
}
}
我还添加了一个ExceptionFilterAttribute来捕获序列化错误并返回有关错误的相关信息。
public class HandleSerializationErrorAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
if (context.Exception is JsonSerializationException)
{
var responseMessage = new HttpResponseMessage(HttpStatusCode.BadRequest);
responseMessage.Content = new StringContent(JsonConvert.SerializeObject(context.Exception.Message));
context.Response = responseMessage;
}
}
}
所以它是:.net MVC 4 WebApi SAYS它使用Json.Net,但默认的JsonFormatter拒绝服从装饰我的模型的Json属性。手动显式设置格式化程序可以解决问题。