ASP.NET ядро — как передать необязательный параметр [FromBody]?

#asp.net-core #controller

Вопрос:

Как передать необязательный (обнуляемый) параметр [FromBody] в ASP.NET Ядро (5.0)? Если я не отправлю тело в своем запросе, я получу ошибку 415 Неподдерживаемого типа носителя. Можно ли это настроить, и если да, то как это сделать на контроллере или действии, а не на уровне приложения? Я предполагаю, что это как-то связано с проверкой модели, но не уверен. Спасибо.

 [HttpGet("[action]")]
public async Task<IActionResult> GetElementsAsync([FromBody] IEnumerable<int> elements = default)
{
  var result = await dataService.GetData(elements);
  return Ok(result);
}
 

ИЗМЕНИТЬ: Чтобы уточнить:

Это типичный сценарий, и он работает нормально: Это типичный сценарий, и он работает нормально

Но прохождение пустого тела сразу же возвращает 415, даже не достигнув действия: Прохождение пустого тела сразу же возвращает 415, не достигнув действия

Ответ №1:

Просто добавьте тип содержимого в заголовок вашего запроса. Без content-type:application/json воли появится 415 , когда тело опустеет.

Никаких изменений в вашем контроллере. Тест на моей стороне в порядке.

введите описание изображения здесь

Я создал новую asp.net проект api core 5, и это мой контроллер:

 using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;

namespace WebApi_net5.Controllers
{
    public class HomeController : ControllerBase
    {
        [HttpGet("[action]")]
        public string GetElementsAsync([FromBody] IEnumerable<int> elements = default)
        {
            return "value";
        }
    }
}
 

Ответ №2:

Вы можете найти решение здесь:
https://github.com/pranavkm/OptionalBodyBinding

Из этого выпуска на github:
https://github.com/dotnet/aspnetcore/issues/6878

И из .net Core 5 вы можете использовать этот:

 public async Task<IActionResult> GetElementsAsync([FromBody(EmptyBodyBehavior = EmptyBodyBehavior.Allow)] IEnumerable<int> elements = default)
...
 

Также необходимо (из опыта Павла):

 services.AddControllers(options =>{options.AllowEmptyInputInBodyModelBinding = true;})
 

Комментарии:

1. Требует ли это решение по-прежнему создания пользовательского фильтра? Я на .NET core 5.0 и просто добавляю (EmptyBodyBehavior = EmptyBodyBehavior. Разрешить) не изменил поведение.

2. Должно быть доступно без пользовательского фильтра. Проверьте глобальную настройку. Документ в GitHub и ms doc

3. Я попытался добавить аннотацию ссылочного типа с возможностью обнуления ( IEnumerable<int>? — кто-то утверждал, что это сработало для них: github.com/dotnet/aspnetcore/issues/30690 ), настроить службы services.AddControllers(options =>{options.AllowEmptyInputInBodyModelBinding = true;}) и отключить проверку модели services.Configure<ApiBehaviorOptions>(options => {options.SuppressModelStateInvalidFilter = true;}); , если ничего из этого не сработало :/

4. Отличная работа, Павел !

5. Я думаю, что [от бога(пустотелое поведение = пустотелое поведение. Разрешить)] ожидает, что пользователь отправит пустое тело (как следует из названия), а не просто не отправит никакого тела. Разница между сообщением без тела и сообщением с пустым телом выглядит так: vs curl --location --request POST 'https://localhost:44349/MyController/MyAction' curl --location --request POST 'https://localhost:44349/MyController/MyAction' --data-raw ''