TL; DR: Не використовуйте [FromBody], а прокатуйте свою власну версію з кращою обробкою помилок. Причини, наведені нижче.
Інші відповіді описують багато можливих причин цієї проблеми. Однак першопричиною є те, що [FromBody]
просто існує жахлива обробка помилок, що робить її майже марною у виробничому коді.
Наприклад, однією з найбільш типових причин для параметра null
є те, що тіло запиту має неприпустимий синтаксис (наприклад, недійсний JSON). У цьому випадку повернеться розумний API 400 BAD REQUEST
, і розумна веб-структура зробить це автоматично. Однак веб-API ASP.NET не є обґрунтованим у цьому відношенні. Він просто встановлює для параметра параметр null
, а обробнику запитів потрібен код "вручну", щоб перевірити, чи є цей параметр null
.
Багато з наведених тут відповідей є неповними щодо обробки помилок, і помилка або зловмисний клієнт може спричинити несподівану поведінку на стороні сервера, надіславши невірний запит, який (у найкращому випадку) кине NullReferenceException
кудись і поверне неправильний статус 500 INTERNAL SERVER ERROR
або, що ще гірше, зробити щось несподіване або збити або виявити вразливість системи безпеки.
Правильним рішенням буде написання власного [FromBody]
атрибута, який " " обробляє помилки і повертає належні коди стану, в ідеалі з деякою діагностичною інформацією для допомоги розробникам клієнтів.
Рішення, яке може допомогти (ще не перевірено), полягає у введенні необхідних параметрів, як показано нижче: https://stackoverflow.com/a/19322688/2279059
Наступне незграбне рішення також працює:
public HttpResponseMessage MyAction([FromBody] JObject json)
{
if (json == null) {
var response = new HttpResponseMessage(HttpStatusCode.BadRequest) {
ReasonPhrase = "Invalid JSON"
};
throw new HttpResponseException(response);
}
MyParameterModel param;
try {
param = json.ToObject<MyParameterModel>();
}
catch (JsonException e) {
var response = new HttpResponseMessage(HttpStatusCode.BadRequest) {
ReasonPhrase = String.Format("Invalid parameter: {0}", e.Message)
};
throw new HttpResponseException(response);
}
}
Це робить (сподіваємось) належну обробку помилок, але є менш декларативним. Наприклад, якщо ви використовуєте Swagger для документування вашого API, він не знатиме тип параметра, а це означає, що вам потрібно знайти певний обхідний спосіб для документування ваших параметрів. Це лише для ілюстрації того, що [FromBody]
слід робити.
EDIT: Менш незграбним рішенням є перевірка ModelState
: https://stackoverflow.com/a/38515689/2279059
РЕДАГУВАТИ: Здається, що ModelState.IsValid
не, як можна було б очікувати, встановлено, false
якщо використовується JsonProperty
з, Required = Required.Always
а параметр відсутній. Тож це теж марно.
Однак, на мій погляд, будь-яке рішення, яке вимагає введення додаткового коду в кожен обробник запитів, є неприйнятним. У такій мові, як .NET, з потужними можливостями серіалізації та в такій структурі, як ASP.NET Web API, перевірка запитів повинна бути автоматичною та вбудованою, і це цілком здійсненно, навіть якщо Microsoft не забезпечує необхідну вбудовану програму інструменти.