WebApi 2 POST с однострочным параметром не работает

У меня есть следующий контроллер:

public class ValuesController : ApiController
{
    // POST api/values
    public IHttpActionResult Post(string filterName)
    {
        return new JsonResult<string>(filterName, new JsonSerializerSettings(), Encoding.UTF8, this);

    }
}

Конфигурация WebApi

config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional });

Я использую этот код js для вызова API

$.ajax(
{
    url: "/api/values/",
    type: "POST",
    dataType: 'json',
    data: { filterName: "Dirty Deeds" },
    success: function (result) {
        console.log(result);
    },
    error: function (xhr, status, p3, p4) {
        var err = "Error " + " " + status + " " + p3;
        if (xhr.responseText && xhr.responseText[0] == "{")
            err = JSON.parse(xhr.responseText).message;
        console.log(err);
    }
});

Я получаю 405 метод не разрешен (пост)


person Danny    schedule 15.06.2016    source источник
comment
К методу веб-API добавьте [HttpPost] под своим комментарием. Также я считаю, что URL-адрес чувствителен к регистру, в javascript он, вероятно, должен читаться как Values с большой буквы V.   -  person Igor    schedule 15.06.2016
comment
Пробовал, но та же ошибка   -  person Danny    schedule 15.06.2016
comment
Также, если вы отправляете данные через http-сообщение (а не по URL-адресу), вы должны добавить [FromBody] к подписи метода. ([FromBody] string filterName)   -  person Igor    schedule 15.06.2016
comment
Ваш метод контроллера ожидает строку, но вы передаете ему объект { filterName: Dirty Deeds }. Это объект javascript с одним свойством filterName. Ваш контроллер не ожидает объект со свойством filterName, просто строку.   -  person peinearydevelopment    schedule 15.06.2016
comment
Когда я использую FromBody, параметр filterName имеет значение null   -  person Danny    schedule 15.06.2016
comment
Когда я устанавливаю данные: Грязные дела, это тоже не работает   -  person Danny    schedule 15.06.2016
comment
Проверьте настройку маршрута. Покажите, как вы настраиваете свои маршруты   -  person Nkosi    schedule 15.06.2016
comment
Я добавил рассматриваемую конфигурацию webApi   -  person Danny    schedule 15.06.2016
comment
@peinearydevelopment это имеет смысл для меня.   -  person Sachin Pakale    schedule 15.02.2017


Ответы (2)


c#

public class ValuesController : ApiController
{
    // POST api/values
    [HttpPost] // added attribute
    public IHttpActionResult Post([FromBody] string filterName) // added FromBody as this is how you are sending the data
    {
        return new JsonResult<string>(filterName, new JsonSerializerSettings(), Encoding.UTF8, this);
    }

JavaScript

$.ajax(
{
    url: "/api/Values/", // be consistent and case the route the same as the ApiController
    type: "POST",
    dataType: 'json',
    data: "=Dirty Deeds", // add an = sign
    success: function (result) {
        console.log(result);
    },
    error: function (xhr, status, p3, p4) {
        var err = "Error " + " " + status + " " + p3;
        if (xhr.responseText && xhr.responseText[0] == "{")
            err = JSON.parse(xhr.responseText).message;
        console.log(err);
    }
});

Объяснение

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

contentType: 'application/x-www-form-urlencoded'

В качестве альтернативы вы также можете отправить контент через URL-адрес ИЛИ обернуть контент в объект на сервере, а также в вызове ajax и преобразовать его в строку.

public class Filter {
    public string FilterName {get;set;}
}

public class ValuesController : ApiController
{
    // POST api/values
    [HttpPost] // added attribute
    public IHttpActionResult Post([FromBody] Filter filter) // added FromBody as this is how you are sending the data
    {
        return new JsonResult<string>(filter.FilterName, new JsonSerializerSettings(), Encoding.UTF8, this);
    }

JavaScript

$.ajax(
{
    url: "/api/Values/", // be consistent and case the route the same as the ApiController
    type: "POST",
    dataType: 'json',
    contentType: 'application/json',
    data: JSON.stringify({FilterName: "Dirty Deeds"}), // send as json
    success: function (result) {
        console.log(result);
    },
    error: function (xhr, status, p3, p4) {
        var err = "Error " + " " + status + " " + p3;
        if (xhr.responseText && xhr.responseText[0] == "{")
            err = JSON.parse(xhr.responseText).message;
        console.log(err);
    }
});
person Igor    schedule 15.06.2016
comment
Это не дает ошибки http, но параметр filterName имеет значение null - person Danny; 15.06.2016
comment
@DannyH - я обновил javascript и протестировал его, это работает. - person Igor; 15.06.2016
comment
Привет, у меня тоже работает. три вопроса: Зачем мне нужен [FormBody] Это также необходимо при передаче объекта? Почему ContentType: 'application/x-www-form-urlencoded', почему = Dirty Deeds - person Danny; 15.06.2016
comment
И как мне подойти к этому при передаче 1 строки и 1 объекта? Так же? - person Danny; 15.06.2016
comment
@DannyH - веб-API позволяет передавать только один объект в теле сообщения. Итак, для этого вы должны создать агрегатный тип, который, как вы ожидаете, содержит все ожидаемые данные, и передать их, используя мой второй пример, который я опубликовал. Если у вас есть простые типы (int, date и т. д.), вы можете передать их как FromUri и передать их в строке запроса. - person Igor; 15.06.2016
comment
@DannyH - если у вас есть одно простое значение, которое передается через тело http-сообщения, веб-API будет ожидать его аналогично использованию кодирования форм. Вот почему = работает. Обычно эти простые значения передаются с использованием URI, а сложные типы передаются с использованием тела сообщения. Вот почему не так много людей сталкиваются с этим сценарием. - person Igor; 15.06.2016
comment
@DannyH - [FromBody] ограничивает входящий параметр телом сообщения, а не URI. Вот как вы публикуете свои данные, поэтому вам, вероятно, следует добавить это ограничение в подпись метода. Это не требуется, и вы можете передать его через URI, если удалите его. - person Igor; 15.06.2016
comment
Я заставил его работать с объектом, но я не использовал JSON.stringify( или [FormBody], и это сработало в первый раз. - person Danny; 15.06.2016
comment
@DannyH - если у вас есть более сложные объекты или типы Java, которые не могут быть преобразованы в строку json с помощью вызова jquery .ajax, тогда потребуется JSON.stringify. Лучше добавлять его всякий раз, когда вы отправляете объект, если только вы не используете такую ​​​​инфраструктуру, как angular, которая делает это за вас. В качестве альтернативы вы можете опустить его, пока не столкнетесь с ошибкой, когда данные не поступают от вашего клиента правильно, и в этот момент вы можете добавить их. - person Igor; 15.06.2016
comment
Ваш последний пример дает мне нулевое значение для свойства фильтра FilterName JSON.stringify({FilterName: Dirty Deeds}) - person Danny; 15.06.2016
comment
Когда я удаляю JSON.stringify во втором примере, он работает. Так что мне не нужно делать JSON.stringify? - person Danny; 15.06.2016
comment
@DannyH - я забыл добавить contentType: 'application/json',. Я обновил пример и протестировал его, должно работать. - person Igor; 15.06.2016
comment
Работает как шарм. Спасибо за помощь - person Danny; 15.06.2016
comment
обратите внимание, что вместо того, чтобы оборачивать его в фиктивный класс (фильтр в примере), вы можете сделать параметр типа динамическим, как так, а затем вы можете добавить любые другие поля, которые вам нравятся, к объекту, используемому при вызове, без необходимости беспокоиться о добавлении их в серверный класс... public IHttpActionResult Post([FromBody] dynamic filter) { return new JsonResult‹string›(filter.FilterName.Value, new JsonSerializerSettings(), Encoding.UTF8, this); } - person C.List; 30.12.2016
comment
Что, если мне нужно передать целое число? Я не могу отправить целое число. Мне нужно изменить метод веб-API, чтобы он принимал строковый параметр вместо int, а затем использовал данные: '' + ID + '' в моем вызове ajax. Почему я не могу отправить целое число? Почему всегда ноль? - person Sachin Pakale; 15.02.2017
comment
@SachinPakale - комментарии - не то место, где можно задавать новый вопрос. Пожалуйста, задайте новый вопрос, используя кнопку «Задать вопрос», и не забудьте указать всю необходимую информацию. - person Igor; 20.02.2017

Добавьте [FromBody] в сигнатуру метода API, например public IHttpActionResult Post([FromBody]string filterName), и заключите параметр данных ajax в кавычки: data: '"' + bodyContent + '"'.

Не очень интуитивно понятно, но работает.

person misha    schedule 27.11.2016
comment
@SachinPakale, вы можете сделать то же самое, просто изменив тип параметра. (int filterNumber). Controller должен автоматически преобразовать переданное значение в String - person Curiousity; 13.10.2017