【发布时间】:2017-06-23 13:04:56
【问题描述】:
我试图阻止我的 REST API 在我的控制器中接受无效的 json 正文。
我有一个带有 .NET MVC 端点的 REST API。在这个端点上,我们有一个 post 方法,它接受一个客户类型的主体(在这个例子中大大简化了),它的类如下:
public class Customer
{
public string FirstName { get; set; }
public string LastName { get; set; }
public List<Address> Addresses { get; set; }
public List<Xref> Xrefs { get; set; }
}
public class Address
{
public string AddressLineOne { get; set; }
public string AddressLineTwo { get; set; }
}
public class Xref
{
public string System { get; set; }
public List<Segment> Segments { get; set; }
}
public class Segment
{
public string Name { get; set; }
public string Value { get; set; }
}
控制器的方法如下:
[HttpPost]
public async Task<IHttpActionResult> Post([FromBody]Customer customer)
{
...
}
一个有效的json正文表示如下:
{
"FirstName": "firstName",
"LastName": "lastName",
"Addresses":
[
{
"AddressLineOne" : "addressLineOne",
"AddressLineTwo" : "addressLineTwo"
}
],
"Xrefs":[
{
"System":"systemOne",
"Segments":[
{
"Name":"name",
"Value":"value"
}
]
}
]
}
我注意到,如果我使用无效的 json 向 API 发出请求,请求控制器仍然会收到正文,并且会忽略错误部分之后的所有内容。下面是这种表示的示例,其中外部参照没有右大括号:
{
"FirstName": "firstName",
"LastName": "lastName",
"Xrefs":[
{
"System":"systemOne",
"Segments":[
{
"Name":"name",
"Value":"value"
}
]
,
"Addresses":
[
{
"AddressLineOne" : "addressLineOne",
"AddressLineTwo" : "addressLineTwo"
}
],
}
当此数据发布到控制器时,客户对象将包含名字、姓氏和外部参照,但不包含地址。这是因为根据 json 层次结构,我们仍然在外部参照中并且没有关闭它。
当为此功能创建单元测试并尝试 DeserializeObject 时,您会遇到 JsonSerializationException,但这不会发生在控制器方法中。
现在我正在尝试找到一种方法来阻止控制器中接受无效的 json。我不希望以任何形式进行部分 json 反序列化,无论 json 是否有效。我考虑过构建一个验证过滤器并将其添加到 HttpConfig 中,该过滤器将使用反射来找出请求的预期主体应该是什么样子,然后它会尝试将主体反序列化到其中,如果抛出异常请求不会通过。
我推迟了这样做,因为我认为 MVC 中内置了一种更简单且资源消耗更少的方法,例如允许不完整 json 主体的标志,但我一直找不到它。我也不愿意在过滤器中执行此操作,因为像这样过滤每个请求将非常耗费资源,特别是因为反射非常费力并且我们正在捕获一个异常来尝试验证。此过滤器在小型 MVC API 中会很好,但此系统需要极短的响应时间。
如果您知道任何更好的解决方案,请告诉我。
谢谢
【问题讨论】:
-
使用 Json Schema,见newtonsoft.com/jsonschema
-
和一个自定义模型绑定器,您可以在其中验证 JSON
-
或使用字符串客户...您将获得JSON字符串,验证并将json转换为所需的对象。
标签: c# asp.net-mvc asp.net-mvc-4 asp.net-web-api asp.net-mvc-5