【发布时间】:2016-01-20 15:10:58
【问题描述】:
我创建了一个非常简单的 OData v4 控制器。控制器基本上包含以下 Pet 实体的实体框架支持的 CRUD 方法:
public class Pet
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
public int Age { get; set; }
}
这里很重要的是Pet.Age 是不可为空的必需属性。
这是控制器本身(仅显示Post 方法):
public class PetController : ODataController
{
private DatabaseContext db = new DatabaseContext();
// POST: odata/Pet
public IHttpActionResult Post(Pet pet)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Pet.Add(pet);
db.SaveChanges();
return Created(pet);
}
// Other controller methods go here...
}
这是我的WebApiConfig 控制器配置:
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Pet>("Pet");
config.MapODataServiceRoute("odata", "odata", builder.GetEdmModel());
现在,如果我想在我的数据库中创建一个新的 Pet,我会发出这样的 POST 请求:
POST http://localhost:8080/odata/Pet
Content-type: application/json
{ Name: "Cat", Age: 5 }
但是,我可以简单地省略 JSON 请求负载中的 Age 属性,因此 JSON 反序列化器将使用默认值 0,而我希望返回 400 Bad Request 状态。此问题称为发布不足。
使用常规 WebApi 控制器时可以轻松解决(解决方案描述为here)。您只需创建一个 PetViewModel 并让您的控制器接受 PetViewModel 而不是实际的 Pet 实体:
public class PetViewModel
{
// Make the property nullable and set the Required attribute
// to distinguish between "zero" and "not set"
[Required]
public int? Age { get; set; }
// Other properties go here...
}
然后在您的控制器中,您只需将PetViewModel 转换为Pet 实体并像往常一样将其保存到数据库中。
不幸的是,这种方法不适用于 OData 控制器:如果我将 Post 方法更改为接受 PetViewModel 而不是 Pet,我会收到以下错误:
System.Net.Http.UnsupportedMediaTypeException:没有 MediaTypeFormatter 可用于从媒体类型为“application/json”的内容中读取“PetViewModel”类型的对象。
at System.Net.Http.HttpContentExtensions.ReadAsAsync[T](HttpContent content, Type type, IEnumerable'1 formatters, IFormatterLogger formatterLogger, CancellationToken cancelToken)
at System.Net.Http.HttpContentExtensions.ReadAsAsync(HttpContent content, Type type, IEnumerable'1 formatters, IFormatterLogger formatterLogger, CancellationToken cancelToken)
at System.Web.Http.ModelBinding.FormatterParameterBinding.ReadContentAsync(HttpRequestMessage request, Type type, IEnumerable`1 formatters, IFormatterLogger formatterLogger, CancellationToken cancelToken)
那么,在使用 OData 控制器时,有什么方法可以防止发布不足?
【问题讨论】:
-
在这种情况下,您可以使用
RangeAttribute并将其指定为 1 到 999。然后ModelState.IsValid应捕获值 0 不在范围内并返回BadRequest状态。另一种选择是创建一个自定义过滤器并在传入的 JSON 映射到模型之前手动解析它,但这似乎有点矫枉过正。 -
@Igor 我已经使用第二种方法解决了这个问题,因为需要区分默认值和
null值的通用解决方案。有兴趣的可以看看答案。感谢您的帮助!
标签: asp.net .net asp.net-web-api odata asp.net-web-api-odata