ASP.NET Core API POST parameter is always null

62,965

Solution 1

The problem is that the Content-Type is application/json, whereas the request payload is actually text/plain. That will cause a 415 Unsupported Media Type HTTP error.

You have at least two options to align then Content-Type and the actual content.

Use application/json

Keep the Content-Type as application/json and make sure the request payload is valid JSON. For instance, make your request payload this:

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

Then the action signature needs to accept an object with the same shape as the JSON object.

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

Instead of the CookieWrapper class, or you can accept dynamic, or a Dictionary<string, string> and access it like cookie["cookie"] in the endpoint

public IActionResult GetRankings([FromBody] CookieWrapper cookie)

public IActionResult GetRankings([FromBody] dynamic cookie)

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

Use text/plain

The other alternative is to change your Content-Type to text/plain and to add a plain text input formatter to your project. To do that, create the following class.

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);
    }
}

And configure Mvc to use it.

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

See also

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

Solution 2

Shaun Luttin's answer works, but it misses one important piece of information. The reason your string is not recognised is because it is not a JSON string.

Do this;

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

Then you can leave the controller as it is;

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

It is embarassing how long this took me to figure out. I really hope it helps someone!

Solution 3

ridiculously, in dot net core you cannot use just "frombody string parameter". you should make a model class for just one string parameter.

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)

Solution 4

I struggled with this for far to long and finally, after looking at what a DevExpress control was doing for "PUT"ting to a Razor Page, I discovered this nugget:

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 
}

The trick is to use the "application/x-www-form-urlencoded; charset=UTF-8" as your contentType for the request. This way you don't need to create a class for a single string value. And things work as expected.

Solution 5

For me, just adding [FromBody] to the parameters list solved the problem.

May this save someone's time.

Share:
62,965
Douglas Gaskell
Author by

Douglas Gaskell

Updated on July 31, 2022

Comments

  • Douglas Gaskell
    Douglas Gaskell almost 2 years

    I have read the following:

    My endpoint:

    [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();
    }
    

    My request:

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

    Where cookie is the a string I am sending from the user input.

    The request posts to the endpoint with the appropriate data. However, my string is always null. I have tried removing the [FromBody] tag, as well as adding a = in front of the posted data with no luck. I have also tried adding and removing different content types with all combinations of the above.

    The reason why I am doing this specific action is long and does not matter for this question.

    Why is my parameter always null no matter what I seem to do?

    Edit: I have also tried using {cookie: cookie}

    Edit2: The request:

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

    Response Headers

    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?=
    

    Request Headers

    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
    

    Request Payload

    =sec_session_id=[redacted]; _ga=[redacted]; AWSELB=[redacted]
    
  • Douglas Gaskell
    Douglas Gaskell over 7 years
    Thanks for the reply, just tried, same deal. Do the ASP.NET parameters not accept data in the standard way other frameworks do?
  • Shaun Luttin
    Shaun Luttin over 7 years
    Got it... ASP.NET Core does not support text/plain as a Content-Type out of the box.
  • Douglas Gaskell
    Douglas Gaskell over 7 years
    The variable cookie is already a string, it is getting passed around the JS as a string.
  • Haney
    Haney over 7 years
    Right, but the request payload also needs to be encapsulated in double quote characters in order for the media type formatter to handle the [FromBody] attribute correctly.
  • Douglas Gaskell
    Douglas Gaskell over 7 years
    Shaun, I ended up using Dictionary<string,string> with a {"cookie":cookie} object. I then access it like cookie["cookie"] in my endpoint. I will accept your answer if you can add that as one of the potential solutions.
  • statler
    statler over 6 years
    This should not be the answer. You can send a string really easily in .Net Core without all this jiggery pokery. Refer my answer below
  • Valuator
    Valuator about 6 years
    A plain text formatter is included with ASP.NET Core: docs.microsoft.com/en-us/aspnet/core/mvc/advanced/…
  • Guilherme Ferreira
    Guilherme Ferreira over 5 years
    Worked. Using axios to post payload
  • Jacob Foshee
    Jacob Foshee over 5 years
    You can see he is deriving from the TextInputFormatter in Microsoft.AspNetCore.Mvc.Formatters. However that is an abstract class and the only derived classes at this time are for JSON and XML. That said, I really wish TextPlainInputFormatter was included. Thanks so much, Shaun!
  • RooSoft
    RooSoft about 5 years
    This thing should be included in the framework. MVC should also have that formatter added by default.