Я создал очень простой контроллер OData v4. Контроллер содержит в основном Entity Framework, поддержанные методы CRUD для следующего Pet
объекта:Как предотвратить недопоставление в службе ASP.NET Web API OData?
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 }
Однако я могу просто опустить свойство Age
в запросе JSON, поэтому десериализатор 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: No MediaTypeFormatter is available to read an object of type 'PetViewModel' from content with media type 'application/json'.
at System.Net.Http.HttpContentExtensions.ReadAsAsync[T](HttpContent content, Type type, IEnumerable'1 formatters, IFormatterLogger formatterLogger, CancellationToken cancellationToken)
at System.Net.Http.HttpContentExtensions.ReadAsAsync(HttpContent content, Type type, IEnumerable'1 formatters, IFormatterLogger formatterLogger, CancellationToken cancellationToken)
at System.Web.Http.ModelBinding.FormatterParameterBinding.ReadContentAsync(HttpRequestMessage request, Type type, IEnumerable`1 formatters, IFormatterLogger formatterLogger, CancellationToken cancellationToken)
Итак, есть ли способ предотвратить под -posting при использовании контроллеров OData?
В этом примере вы можете использовать «RangeAttribute» и указать его с 1 по 999. Затем «ModelState.IsValid» должен поймать, что значение 0 не находится в пределах диапазона и возвращает статус «BadRequest». Другой вариант - создать настраиваемый фильтр и вручную проанализировать входящий JSON, прежде чем он будет сопоставлен с моделью, но это похоже на излишний. – Igor
@Igor Я решил проблему, используя второй подход, потому что требуется общее решение для различения значений по умолчанию и 'null'. Посмотрите на ответ, если вы заинтересованы. Спасибо за помощь! –