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

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

В моем окне отладки отображается: 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).

Вы должны опубликовать либо JSON (с соответствующим заголовком Content-Type «application / json»), либо данные формы (с соответствующим Content-Type «application / x-www-form-urlencoded», но не оба сразу.

Heretic Monkey 19.07.2018 22:10

@heretic Я их не выкладываю одновременно. Я делаю два отдельных сообщения: один с JSON, а другой с данными формы. Тип контента автоматически устанавливается скрипачом и совпадает.

Kevin Shaffer 19.07.2018 22:21

Попробуйте использовать почтальона или скрипача, чтобы протестировать Api. У вас api привязка модели нормально, когда вы их используете ??

sawbeanraz 19.07.2018 22:49
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
12
3
20 116
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

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

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

Тип содержимого: приложение / json

Ответ принят как подходящий

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

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

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

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

In some cases you may need to be able to bind both types of data to an action. In that case, you're a little bit stuck, as it won't be possible to have the same end point receive two different sets of data.

Здесь, ссылаясь на оба типа данных, Эндрю имеет в виду как сообщение 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] оказывает на значения по умолчанию, модифицированный пример выше меняет положение.


См. Мой ответ здесь для потенциального подхода, который позволяет использовать один и тот же URL-адрес как для FromForm, так и для FromBody с использованием настраиваемого IActionConstraint.

Если вы хотите получить данные формы для заголовка 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)
    {

    }
Install-Package Toycloud.AspNetCore.Mvc.ModelBinding.BodyOrDefaultBinding

Конфиг

services.AddMvc(options =>
     {
         options.ModelBinderProviders.InsertBodyOrDefaultBinding();
     })

Включить для одного параметра

[HttpPost]
public int SaveData([FromBodyOrDefault]DataPoco m)
{
    ;//
}

https://github.com/shamork/Toycloud.AspNetCore.Mvc.ModelBinding.BodyAndFormBinding

Другие вопросы по теме