it-swarm.com.ru

Публикация данных формы в MVC Core API

Я хотел бы опубликовать данные в своем API с помощью AJAX, но у меня возникли проблемы. Я использую Fiddler для тестирования своего API и могу правильно публиковать JSON, но при публикации строки с именем/значением urlencoded я получаю 400 неверных запросов с телом ответа: «{» »: [« Ввод неверный . "]}».

Мое окно отладки отображает: Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor:Information: Executing ObjectResult, writing value of type 'Microsoft.AspNetCore.Mvc.SerializableError'.

Размещаемый JSON:

{
    "Name": "Test"
}

Публикуемые данные формы:

Name=Test

Это Контроллер и Действие:

[Route("api/[Controller]")]
[ApiController]
public class AccountsController : Controller
{
    [HttpPost]
    public IActionResult CreateAccount(Account account)
    {
        //code
    }
}

Это класс Account:

public class Account
{
    public string Id { get; set; }
    public string Name { get; set; }
    public string Type { get; set; }
    public string Website { get; set; }
}

Кажется очевидным, что существует проблема во время связывания модели, но данные формы кажутся действительными (я также сгенерировал данные формы, используя AJAX и также получил 400).

4
Kevin Shaffer

В своем посте Модель связывания JSON POSTs в ASP.NET Core от 2016 года Эндрю Локк объясняет, что для привязки JSON POST в ASP.NET Core атрибут [FromBody] должен быть указан в аргумент, вот так:

[HttpPost]
public IActionResult CreateAccount([FromBody] Account account)
{
    // ...
}

С введением [ApiController] в ASP.NET Core 2.1 это больше не требуется. Здесь важно то, что этот атрибут эффективно определяет наличие атрибута [FromBody], когда привязываемый тип является «сложным» (как в вашем примере). Другими словами, вы как будто написали код, как я продемонстрировал выше.

В своем посте Андрей также заявляет следующее:

В некоторых случаях вам может понадобиться связать оба типа данных с действием. В этом случае вы немного застряли, поскольку невозможно, чтобы одна и та же конечная точка получала два разных набора данных.

Здесь, когда ссылаются на оба типа данных, Эндрю ссылается как на сообщение JSON, так и на POST на основе формы. Он продолжает объяснять, как на самом деле достичь требуемого результата. Модифицируя его пример для ваших целей, вам нужно будет сделать что-то вроде следующего:

// Form.
[HttpPost("FromForm")]
public IActionResult CreateAccountFromForm([FromForm] Account account)) =>
    DoSomething(account);

// JSON.
[HttpPost("FromBody")]
public IActionResult CreateAccountFromBody(Account account) =>
    DoSomething(account);

private IActionResult DoSomething(Account account) {
    // ...
}

В примере Эндрю [FromBody] является явным, а [FromForm] неявным, но учитывая влияние, которое [ApiController] оказывает на значения по умолчанию, модифицированный пример выше переворачивает это.

8
Kirk Larkin

Убедитесь, что ваш тип запроса установлен на «application/json». Я воспроизвел ваш код, и метод не вызывался с помощью Postman, пока я не установил тип запроса application/json.

Правка: Когда я добавил следующее в заголовки в fiddler, я смог заставить fiddler также вызывать мой метод:

Тип контента: приложение/JSON

2
James

Если вы хотите получить данные формы для headr Content-Type: application/x-www-form-urlencoded) в ваш контроллер API, тогда вы должны поместить атрибут [FromForm] в метод действия, например:

    // POST: api/Create
    [HttpPost]
    public IActionResult CreateAccount([FromForm] Account account)
    {

    }

Если вы хотите получить данные формы для заголовка Content-Type: application/json в свой контроллер API, тогда вы должны поместить атрибут [FromBody]/No в метод действия, например 

    // POST: api/Create
    [HttpPost]
    public IActionResult CreateAccount([FromBody] Account account)
    {

    }

Или же

    // POST: api/Create
    [HttpPost]
    public IActionResult CreateAccount(Account account)
    {

    }
1
Towhidul Islam Tuhin