【问题标题】:ASP.NET Core API POST parameter is always nullASP.NET Core API POST 参数始终为空
【发布时间】:2017-06-07 12:25:59
【问题描述】:

我已阅读以下内容:

我的端点:

[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]

【问题讨论】:

  • 您是否使用过 Fiddler 或浏览器的网络控制台等工具来确保 POST 正确发送正文?
  • @ShaunLuttin 是的,我提到它确实发布了适当的数据。数据在请求中发送。
  • 您可以发布实际的 HTTP 请求及其标头和正文,而不是发布您如何发出 AJAX 请求。这可能有助于解决问题。
  • @ShaunLuttin 我已经在里面添加了请求
  • 您的请求负载不是 JSON,而您的 Content-Type 是 application/json。

标签: c# ajax asp.net-web-api asp.net-core


【解决方案1】:

问题在于Content-Typeapplication/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&lt;string, string&gt; 并像端点中的 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

【讨论】:

  • 感谢回复,刚刚试过,同样的交易。 ASP.NET 参数是否不像其他框架那样接受数据?
  • 知道了... ASP.NET Core 不支持将text/plain 作为开箱即用的Content-Type
  • Shaun,我最终将Dictionary&lt;string,string&gt;{"cookie":cookie} 对象一起使用。然后我在我的端点中像cookie["cookie"] 一样访问它。如果您可以将其添加为潜在的解决方案之一,我将接受您的回答。
  • 这不应该是答案。您可以在 .Net Core 中非常轻松地发送字符串,而无需所有这些棘手的操作。请参阅下面的答案
  • 您可以看到他是从Microsoft.AspNetCore.Mvc.Formatters 中的TextInputFormatter 派生的。然而,这是一个抽象类,此时唯一的派生类是 JSON 和 XML。也就是说,我真的希望 TextPlainInputFormatter 被包括在内。非常感谢,肖恩!
【解决方案2】:

您只需将正文放在引号中,使其代表string。您还需要将请求类型保留为application/json。这样媒体类型格式化程序就会弄清楚:

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

应该做的伎俩。

【讨论】:

  • 变量cookie已经是一个字符串,它作为字符串在JS中传递。
  • 对,但是请求负载也需要用双引号字符封装,以便媒体类型格式化程序正确处理[FromBody] 属性。
【解决方案3】:

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

令人尴尬的是,我花了多长时间才弄清楚。我真的希望它可以帮助别人!

【讨论】:

  • 工作。使用 axios 发布 payload
【解决方案4】:

可笑的是, 在 dot net core 中,您不能只使用“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)

【讨论】:

    【解决方案5】:

    我需要通过 .Net 桌面客户端将字符串数据发布到 .NET Core 主机。我收到不支持的媒体错误。我遵循了 Shaun Luttin 的回答并且工作正常。我发现了一些更容易获取字符串数据的方法,以防其他人发现有用:

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

    This post 很有用。

    【讨论】:

      【解决方案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。这样您就不需要为单个字符串值创建一个类。一切都按预期进行。

      【讨论】:

        【解决方案7】:

        我的特殊问题是模型绑定对于 JSON 模型静默失败。 (它始终为空)。

        由于我发布了确切的 JSON,我能够通过在本地运行 Web 服务在本地调试它,并通过 cURL 发布到我的控制器(可以使用 POSTMAN)。

        使用下面的代码,我能够看到序列化过程中发生的确切异常。

            [HttpPost]
            public IActionResult MyAction([FromBody] dynamic request)
            {            
                if (request != null)
                {
                    try
                    {
                        var objAttempt =
                            JsonConvert.DeserializeObject<MyModel>(
                                JsonConvert.SerializeObject(request));
                    }
                    catch (Exception exception)
                    {
                        Console.WriteLine(exception);
                        throw;
                    }
                }
        

        【讨论】:

          【解决方案8】:

          对我来说,只需将[FromBody] 添加到参数列表即可解决问题。

          希望这可以节省别人的时间。

          【讨论】:

            【解决方案9】:

            就我而言,我按照@guhyeon 的建议进行了设置,模型类只包含一个字符串属性。除了,它没有被定义为属性,它只是

            public class PdfInfoRequestDto
            {
                public string PdfInBase64;
            }
            

            由于某种原因,这适用于 .net 框架 4.7.2 webapi,我可以从请求正文中收到我需要的值。但是当我尝试在 .net core 3.1 webapi 中使用相同的请求、模型和所有内容复制相同内容时,PdfInBase64 中的值总是以 null 的形式到达我的控制器。将字段更改为属性后:

            public string PdfInBase64 { get; set; }
            

            我开始正确获取请求正文中传递的值。

            【讨论】:

              【解决方案10】:

              在两个参数上使用 [FromForm] 为我修复了它。如:

              [HttpPost]
              public IActionResult Insrtmyinfo([FromForm] string firstparam, [FromForm] string secndparam)
              

              ...

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2016-11-22
                • 2017-02-06
                • 2017-08-28
                • 1970-01-01
                • 1970-01-01
                • 2021-01-26
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多