Параметр POST для основного API-интерфейса ASP.NET всегда равен нулю

Я прочитал следующее:

Моя конечная точка:

[HttpPost]
[Route("/getter/validatecookie")]
public async Task<IActionResult> GetRankings([FromBody] string cookie)
{
    int world = 5;
    ApiGetter getter = new ApiGetter(_config, cookie);
    if (!await IsValidCookie(getter, world))
    {
        return BadRequest("Invalid CotG Session");
    }
    HttpContext.Session.SetString("cotgCookie", cookie);
    return Ok();
}

Мой запрос:

$http.post(ENDPOINTS["Validate Cookie"],  cookie , {'Content-Type': 'application/json'});

Где cookie - это строка, которую я отправляю с пользовательского ввода.

Запрос отправляется в конечную точку с соответствующими данными. Однако моя строка всегда равна нулю. Я попытался удалить тег [FromBody], а также добавить = перед опубликованными данными без везения. Я также попытался добавить и удалить разные типы контента со всеми комбинациями из вышеперечисленного.

Причина, по которой я делаю это конкретное действие, длинна и не имеет значения для этого вопроса.

Почему мой параметр всегда равен нулю, что бы я ни делал?

Изменить: я также пробовал использовать {cookie: cookie}

Edit2: запрос:

Request URL:http://localhost:54093/getter/validatecookie
Request Method:POST
Status Code:400 Bad Request
Remote Address:[::1]:54093

Заголовки ответов

Content-Type:text/plain; charset=utf-8
Date:Mon, 23 Jan 2017 03:12:54 GMT
Server:Kestrel
Transfer-Encoding:chunked
X-Powered-By:ASP.NET
X-SourceFiles:=?UTF-8?B?QzpcVXNlcnNcRG91Z2xhc2cxNGJcRG9jdW1lbnRzXFByb2dyYW1taW5nXENvdEdcQ290RyBBcHBcc3JjXENvdEdcZ2V0dGVyXHZhbGlkYXRlY29va2ll?=

Заголовки запросов

POST /getter/validatecookie HTTP/1.1
Host: localhost:54093
Connection: keep-alive
Content-Length: 221
Accept: application/json, text/plain, */*
Origin: http://localhost:54093
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
Content-Type: application/json;charset=UTF-8
Referer: http://localhost:54093/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.8

Запрос полезной нагрузки

=sec_session_id=[redacted]; _ga=[redacted]; AWSELB=[redacted]

Ответ 1

Проблема в том, что Content-Type равен application/json, тогда как полезная нагрузка запроса фактически text/plain. Это вызовет ошибку 415 Unsupported Media Type HTTP.

У вас есть как минимум два параметра для выравнивания, затем Content-Type и фактического содержимого.

Использовать приложение /json

Сохраните Content-Type как application/json и убедитесь, что полезная нагрузка запроса действительна JSON. Например, сделайте свой запрос полезным:

{
    "cookie": "=sec_session_id=[redacted]; _ga=[redacted]; AWSELB=[redacted]"
} 

Затем сигнатуре действия необходимо принять объект с той же формой, что и объект JSON.

public class CookieWrapper
{
    public string Cookie { get; set; }
}

Вместо класса CookieWrapper или вы можете принять динамический или Dictionary<string, string> и получить доступ к нему как cookie["cookie"] в конечной точке

public IActionResult GetRankings([FromBody] CookieWrapper cookie)

public IActionResult GetRankings([FromBody] dynamic cookie)

public IActionResult GetRankings([FromBody] Dictionary<string, string> cookie)

Использовать текст/обычный

Другой альтернативой является изменение вашего Content-Type на text/plain и добавление форматирования ввода текста в текст для вашего проекта. Для этого создайте следующий класс.

public class TextPlainInputFormatter : TextInputFormatter
{
    public TextPlainInputFormatter()
    {
        SupportedMediaTypes.Add("text/plain");
        SupportedEncodings.Add(UTF8EncodingWithoutBOM);
        SupportedEncodings.Add(UTF16EncodingLittleEndian);
    }

    protected override bool CanReadType(Type type)
    {
        return type == typeof(string);
    }

    public override async Task<InputFormatterResult> ReadRequestBodyAsync(
        InputFormatterContext context, 
        Encoding encoding)
    {
        string data = null;
        using (var streamReader = context.ReaderFactory(
            context.HttpContext.Request.Body, 
            encoding))
        {
            data = await streamReader.ReadToEndAsync();
        }

        return InputFormatterResult.Success(data);
    }
}

И настройте Mvc, чтобы использовать его.

services.AddMvc(options =>
{
    options.InputFormatters.Add(new TextPlainInputFormatter());
});

См. также

https://github.com/aspnet/Mvc/issues/5137

Ответ 2

Ответ Shaun Luttin работает, но он пропускает одну важную часть информации. Причина, по которой ваша строка не распознана, состоит в том, что она не является строкой JSON.

Сделайте это;

var payload=JSON.stringify("=sec_session_id=[redacted]; _ga=[redacted]; AWSELB=[redacted]");

Затем вы можете оставить контроллер таким, какой он есть;

$.ajax({
    url: http://localhost:54093/getter/validatecookie,
    type: 'POST',
    contentType: 'application/json',
    data: payload
});

Это смущает, как долго мне это приходило в голову. Я действительно надеюсь, что это поможет кому-то!

Ответ 3

как ни странно, в ядре dot net нельзя использовать просто "строковый параметр frombody". Вы должны создать класс модели только для одного строкового параметра.

public async Task<IActionResult> GetRankings([FromBody] string cookie)

=>

//1. make a model. MyCookie.cs
class MyCookie{
   public string Cookie { get; set; }
}
//2. edit your parameter
public async Task<IActionResult> GetRankings([FromBody] MyCookie cookie)

Ответ 4

Вам просто нужно поместить тело в кавычки так, чтобы он представлял string. Вам также необходимо оставить тип запроса как application/json. Таким образом, формирователь форматов мультимедиа выяснит это:

"=sec_session_id=[redacted]; _ga=[redacted]; AWSELB=[redacted]"

Должен сделать трюк.

Ответ 5

Мне нужно было отправить строковые данные с помощью .Net Desktop Client на хост .NET Core. Я получаю ошибку неподдерживаемого носителя. Я следил за ответом Шона Люттина и работал нормально. Я обнаружил, что проще получить только строковые данные в виде следующих строк, если кто-то найдет что-то полезное:

[HttpPost]
[Route("Request/Echo")]
public async Task<string> Echo()
{
    using (var Reader = new StreamReader(Request.Body, Encoding.UTF8))
    {
        return await Reader.ReadToEndAsync();
    }
}

Этот пост очень полезен.

Ответ 6

Я долго и долго боролся с этим, и, наконец, посмотрев, что делает элемент управления DevExpress для "PUT" ссылки на страницу Razor, я обнаружил этот самородок:

JavaScript

$.ajax({
        type: "PUT",
        url: "/GoalGrid?handler=Single",
        dataType: "json",
        contentType: "application/x-www-form-urlencoded; charset=UTF-8",
        data: {values: single }
    })

GoalGrid.cshtml.cs

public JsonResult OnPutSingle(string values)
{ 
     // Do stuff with 'values' here 
}

Хитрость заключается в том, чтобы использовать "application/x-www-form-urlencoded; charset = UTF-8" в качестве вашего contentType для запроса. Таким образом, вам не нужно создавать класс для единственного строкового значения. И все работает как положено.