Post参数始终为null


197

自从为WebAPI升级到RC以来,在WebAPI上调用POST时遇到了一些真正的奇怪问题。我什至回到了在新项目上生成的基本版本。所以:

public void Post(string value)
{
}

并从Fiddler致电:

Header:
User-Agent: Fiddler
Host: localhost:60725
Content-Type: application/json
Content-Length: 29

Body:
{
    "value": "test"
}

当我调试时,字符串“值”从未分配给它。它始终是NULL。有人遇到这个问题吗?

(我首先看到了一个更复杂的类型的问题)

该问题不仅与ASP.NET MVC 4绑定,在RC安装后,对于新的ASP.NET MVC 3项目也会发生相同的问题


只是增加了问题-它不是JSON独有的,它也发生在XML中。
ianrathbone 2012年

3
我已经坚持了两天,阅读完我能找到的每篇文章后,结果发现它就像在WebRequest中正确格式化JSON字符串一样简单:数据必须以双引号开头和结尾,如果然后在您的json数据中使用单引号,效果都很好。
Gineer

Answers:


101

由于您只有一个参数,因此可以尝试使用[FromBody]属性来修饰它,或者更改方法以接受具有值作为属性的DTO,如我在此处建议的那样:MVC4 RC WebApi参数绑定

更新:官方ASP.NET网站今天进行了更新,并提供了很好的解释:https : //docs.microsoft.com/zh-cn/aspnet/web-api/overview/advanced/sending-html-form-data-part- 1个

简而言之,在正文中发送单个简单类型时,仅发送以等号(=)为前缀的值,例如body:

=test


9
我确实给了[FromBody]一个旋转,但没有任何改变
ianrathbone 2012年


8
=直到我遵循Jim在他的注释中的建议(而不是作为JSON对象),前面的追加对我才有用。这是关键!我真的不喜欢WebAPI多么挑剔。
gitsitgo 2014年

16
这是如此愚蠢和烦人,以至于我不知道该赞成还是不赞成帮助我解决问题的答案……到底为什么必须采用这种格式?(很抱歉,您的态度太浪费时间了,这没有任何意义... :()。您应该真正增加人们期望它接受的格式的支持。
gdoron支持Monica 2015年

6
谢谢!在地球上,我们如何知道仅发送一个参数时必须删除参数名称?哪个鸟脑想出了这个主意?
珍妮·奥雷利

104

我今天为此一直在挠头。

我的解决方案是将更[FromBody]改为HttpRequestMessage,实质上是将HTTP堆栈向上移动。

就我而言,我正在通过有线json发送的数据发送数据,然后将其进行base64处理。所有这一切都来自android应用。

我的Web端点的原始签名如下所示(使用[FromBody]):

我的原始终点

我针对此问题的解决方法是恢复为使用HttpRequestMessage终结点的签名。

在此处输入图片说明

然后,您可以使用以下代码访问帖子数据:

在此处输入图片说明

这可以正常工作,并允许您访问原始的未修改帖子数据。您不必弄乱提琴手在字符串的开头放置=符号或更改内容类型。

顺便说一句,我首先尝试遵循以上答案之一,即将内容类型更改为:“ Content-Type:application / x-www-form-urlencoded”。对于原始数据,这是个坏建议,因为它会去除+号。

因此,以这样的开头的base64字符串:“ MQ0AAB + LCAAAAAA”最终像这样的“ MQ0AAB LCAAAAAA”!不是你想要的。

使用的另一个好处HttpRequestMessage是您可以从端点内访问所有http标头。


6
出色的解决方案...花了9个小时,我才找到了它,删除了[FromBody]字符串值并用HttpRequestMessage替换了它之后,问题就解决了
Kev

1
奇迹般有效!但是没有办法使用某个对象的实际参数类型吗?例如,用于Web api方法的Order类型的参数?
Ron

7
只是附带说明,您不需要HttpRequestMessage request方法签名,因为您已经拥有了它。在方法主体中,可以在Request对象上对其进行访问。例如Request.Content.ReadAsStringAsync().Result;
Morvael

通常,此问题是因为您的JSON对象不正确。我发现这始终是因为构造函数中的类型无效,而Json不知道如何将其转换为Guid到字符串。因此,可以通过设置添加转换器,也可以添加空白的构造函数,而无需返回到这样的旧代码。
尼克·特纳

最简单的方法是将对象切换为字符串,然后尝试对其进行转换,您将看到JSON错误。检查您是否也是标题。
尼克·特纳

71

我刚刚使用Fiddler发生了这种情况。问题是我没有指定Content-Type

尝试Content-Type在POST请求中包含标头。

Content-Type: application/x-www-form-urlencoded

另外,根据下面的注释,您可能需要包含JSON标头

Content-Type: application/json

11
我有一个类似的问题,除了我需要设置Content-Type:application / json
dvallejo 2013年

2
如文章中所指定-我已经添加了Content-Type:application / json
ianrathbone 2014年

2
application / x-www-form-urlencoded对我不起作用,Content-Type:application / json对我来说不起作用。
liang 2014年

1
无论内容类型如何,如果只有一个参数,则必须仅在请求正文中发送不带参数名称的值。所以id = 13将不起作用。您需要单独发送13。参见吉姆的答案。
珍妮·奥雷利

我必须使用contentType: "application/x-www-form-urlencoded; charset=UTF-8",有关完整示例,请参阅Complete Cient and Server
RyBolt

57

我也遇到了这个问题,这就是我解决问题的方式

webapi代码:

public void Post([FromBody] dynamic data)
{
    string value = data.value;
    /* do stuff */
}

客户代码:

$.post( "webapi/address", { value: "some value" } );

1
如果客户端发送JSON,则此方法有效。如果我要发送一个简单的值,例如string some valuedata则为null。
brianestey

轻松,更改您的客户端代码以发送回js对象。
乔治

大和干净的方式从JSON获取数据
沃特Vanherck

如果要发送json,则var json = JsonConvert.SerializeObject(data);
dvallejo

41

我正在使用Postman,我在做同样的错误..传递valueas json对象而不是字符串

{
    "value": "test"
}

显然,当api参数为string类型时,上述错误错误的。

因此,只需在api主体中的双引号中传递字符串即可:

"test"

2
这是我的问题,可能是该问题的真正解决方案。JSON编码的字符串带有引号
Kyle W

1
我在邮递员上也遇到了这个问题。事实证明,当Content-Type设置为application / json时,我错误地为Body选择了“ form-data”而不是“ raw”。您可以在aspnet Github问题上参考zzyykk123456的屏幕截图:github.com/aspnet/Home/issues/2202
Chun Lin

这对我有用。使用Swagger(swashbuckle),我必须设置Content Type:application / json并使用双引号。
约翰·亨克尔

1
确实是我的问题,但我必须指出,在Ajax请求中,您应该执行“数据:JSON.stringify(“ YourString”)“
Amir Hossein Ahmadi

1
@AmirHosseinAhmadi我刚刚在ajax上遇到了这个问题,发现实际使用JSON.stringify导致我[frombody]成为了null。将数据字段设置为字符串值(即json字符串)后,它可以工作。
Nexaspx

19

尝试创建一个用作数据模型的类,然后发送一个属性与数据模型类的属性匹配的JSON对象。(注意:我已经对此进行了测试,并且可以与我今天下载的最新MVC 4 RC 2012一起使用)。

public HttpResponseMessage Post(ValueModel model)
{
    return Request.CreateResponse<string>(HttpStatusCode.OK, "Value Recieved: " + model.Value);
}

public class ValueModel
{
    public string Value { get; set; }
}

下面的JSON对象在HTTP-POST正文中发送,内容类型为application / json

{ "value": "In MVC4 Beta you could map to simple types like string, but testing with RC 2012 I have only been able to map to DataModels and only JSON (application/json) and url-encoded (application/x-www-form-urlencoded body formats have worked. XML is not working for some reason" }

我相信您必须创建数据模型类的原因是因为假定简单值来自url参数,而单个复杂值则假定来自正文。它们确实具有[FromBody][FromUrl]属性,但是[FromBody] string value对我来说仍然无法使用。似乎他们仍在解决许多错误,因此我相信将来会有所改变。

编辑: 获得XML在正文中工作。默认的XML序列化器已更改为DataContractSerializer,而不是XmlSerializer。将以下行放入我的Global.asax文件中可解决此问题(参考

GlobalConfiguration.Configuration.Formatters.XmlFormatter.UseXmlSerializer = true;

这对我有用request.ContentType =“ application / json; charset = UTF-8”;
Arvind Krmar,

15

经过一番尝试,我认为默认行为是正确的,没有什么可破解的。

唯一的技巧是:如果您的post方法参数string如下所示,则应发送一个在主体中带有双引号的纯字符串(使用ajax或postman时),例如,

//send "{\"a\":1}" in body to me, note the outer double quotes
[HttpPost("api1")]
public String PostMethod1([FromBody]string value)
{
    return "received " + value; //  "received {\"a\":1}"
}

否则,如果您在帖子主体中发送的json字符串没有外部双引号和转义内部引号,则应该能够将其解析为模型类(参数类型),例如,{"a":1, "b":2}

public class MyPoco{
    public int a;
    public int b;
}

//send {"a":1, "b":2} in body to me
[HttpPost("api2")]
public String PostMethod2([FromBody]MyPoco value)
{
    return "received " + value.ToString();  //"received your_namespace+MyPoco"
}

11

我现在正在寻找解决此问题的方法,因此,我将分享我的解决方案。

如果发布模型,则模型需要具有空/默认构造函数,否则显然无法创建模型。重构时要小心。;)


重构正是在这里困扰我的,感谢您的提示!
艾伦(Alan)

10

这为我工作:

  1. 创建一个C#DTO类,为要从jQuery / Ajax传递的每个属性提供一个属性

    public class EntityData
    {
        public string Attr1 { get; set; }
        public string Attr2 { get; set; }
    }
  2. 定义Web API方法:

    [HttpPost()]
    public JObject AddNewEntity([FromBody] EntityData entityData)
    {
  3. 这样调用Web API:

    var entityData = {
        "attr1": "value1",
        "attr2": "value2"
    };
    
    $.ajax({
        type: "POST",
        url: "/api/YOURCONTROLLER/addnewentity",
        async: true,
        cache: false,
        data: JSON.stringify(entityData),
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        success: function (response) {
            ...
        }
    });

感谢您发布此内容,我尝试了很多示例,但这对我有用!
萨特比尔

10

对于那些像我一样遇到SwaggerPostman问题的人,如果您在帖子中传递简单属性作为字符串,即使指定了“ ContentType”,您仍将获得null值。

仅通过:

我的价值

将作为空值进入控制器。

但是,如果您通过:

“我的价值”

该值将正确。

引号在这里有所不同。当然,这仅适用于Swagger和Postman。例如,在使用Angular的前端应用程序中,此问题应由框架自动解决。


6

我遇到了同样的问题,发现将内容类型更改为“ application / json”并不能解决问题。但是,“ application / json; charset = utf-8”有效。


是的,没有charset = utf-8,Web API不会反序列化。blog.codenamed.nl/2015/05/12/...
山姆Rueby

4

我有一个类似的问题,其中我的Web API方法的请求对象始终为null。我注意到,由于控制器操作名称以“ Get”为前缀,因此Web API将其视为HTTP GET而不是POST。重命名控制器动作后,它现在可以按预期工作。


3

使用Angular,我能够以这种格式传递数据:

 data: '=' + JSON.stringify({ u: $scope.usrname1, p: $scope.pwd1 }),
 headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8' }

在Web API Controler中:

    [HttpPost]
    public Hashtable Post([FromBody]string jsonString)
    {
        IDictionary<string, string> data = JsonConvert.DeserializeObject<IDictionary<string, string>>(jsonString);
        string username = data["u"];
        string pwd = data["p"];
   ......

另外,我也可以这样发布JSON数据:

    data: { PaintingId: 1, Title: "Animal show", Price: 10.50 } 

并且,在控制器中,接受这样的类类型:

    [HttpPost]
    public string POST(Models.PostModel pm)
    {

     ....
    }

无论哪种方法都有效,如果您在API中建立了公共类,则发布JSON,否则发布'='+ JSON.stringify({..:...,..:...})


3

在我的情况下,问题是参数是一个字符串而不是一个对象,我将参数更改为Newsoft.Json的JObject并且它可以工作。


2

加线

        ValueProviderFactories.Factories.Add(new JsonValueProviderFactory());

protected void Application_Start()Global.asax.cs 中功能的末尾,在ASP.NET MVC3中为我解决了类似的问题。


感谢您的帮助,但不幸的是它没有帮助。我会暂时保留这条线,因为无论如何它可能会有所帮助!
ianrathbone 2012年

只是要添加同样的问题,当我发布XML时也会发生
ianrathbone 2012年

2

如果您为Xml Formatter或JSON Formatter 使用DataContractSerializer,则需要摆脱它。我在WebApiConfig文件中有此文件:

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

     var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
     jsonFormatter.UseDataContractJsonSerializer = true;
}

简而言之,我将其注释掉,jsonFormatter.UseDataContractJsonSerializer = true;而我的输入参数不再为null。感谢“ Despertar”给我一个线索。


2

如果您确定已发送的JSON,则必须仔细跟踪API:

  1. 安装Microsoft.AspNet.WebApi.Tracing套件
  2. 添加config.EnableSystemDiagnosticsTracing();WebApiConfig类中Register的方法。

现在查看Debug输出,您可能会发现一个无效的ModelState日志条目。

如果ModelState无效,则可以在其中找到真正的原因Errors

没有人能猜出这样的例外:

Could not load file or assembly 'Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)

你救了我的命。在将null作为模型并安装软件包后,发现我的JSON格式不正确。
Khizar Iqbal '18

2

我也遇到了将null作为参数的问题,但它与大型对象有关。原来,问题与IIS最大长度有关。可以在web.config中进行配置。

  <system.web>
    <httpRuntime targetFramework="4.7" maxRequestLength="1073741824" />
  </system.web>

我想知道为什么Web API抑制了该错误并将空对象发送到我的API。我使用Microsoft.AspNet.WebApi.Tracing发现了错误。



1

我知道这不是这个问题的答案,但是当我寻找问题的解决方案时遇到了它。

就我而言,没有绑定复杂类型,但是我没有执行POST,而是使用querystring参数进行GET。解决方法是将[FromUri]添加到arg:

public class MyController : ApiController
{
    public IEnumerable<MyModel> Get([FromUri] MyComplexType input)
    {
        // input is not null as long as [FromUri] is present in the method arg
    }
}

这是因为使用GET时,请求的正文会被忽略(有时会导致错误)。它现在起作用的原因是b / c,您正在传递查询字符串上的参数,并且您的身体像在GET上一样
RyBolt

1

我在Fiddler中遇到了同样的问题。我已经有Content-Type: application/json; charset=utf-8Content-Type: application/json在请求标头中。

我的请求正文也是一个普通字符串,在Fiddler中我写了:{'controller':'ctrl'}。这使我的POST方法中的string参数为null

修复:请记住使用引号,以指示字符串。也就是说,我通过写来修复它"{'controller':'ctrl'}"。(注意:编写JSON时,请确保使用撇号或使用引号将其转义,例如:)"{\"controller\":\"ctrl\"}"


我必须在邮递员中做同样的事情。但是,当我调用Spring服务时,不需要这样做。似乎在.Net方面存在问题。
Malcolm McRoberts

1

我发现处理传递到MVC 6的简单JSON对象的最简单方法是获取post参数的类型,例如NewtonSoft jObject:

public ActionResult Test2([FromBody] jObject str)
{
        return Json(new { message = "Test1 Returned: "+ str }); ;
}

Test([FromBody] object body, [FromHeader(Name="Content-Type")] string bodyMediaType)可以更好地工作,因为bodyMediaType == "application.json"在将主体转换为JObject之前进行检查可以提供替代方法。
VladH

1

对我来说最好的解决方案是使用完整的HTTP,如下所示:

[Route("api/open")]
[HttpPost]
public async Task<string> open(HttpRequestMessage request)
{
    var json = await request.Content.ReadAsStringAsync();
    JavaScriptSerializer jss = new JavaScriptSerializer();            
    WS_OpenSession param = jss.Deserialize<WS_OpenSession>(json);
    return param.sessionid;
}

然后将字符串反序列化为所需的文章正文中的对象。对我来说,WS_OpenSession是一个包含sessionid,user和key的类。

您可以从那里使用param对象并访问其属性。

非常非常有效。

我确实说过从这个网址获得:

http://bizcoder.com/posting-raw-json-to-web-api


1

对于复杂类型,Web API尝试使用媒体类型格式化程序从消息正文中读取值。

请检查是否有[Serializable]装饰模型类的属性。

删除该属性以查看它是否有效。这对我有用。


1

我参加聚会有点晚了,但是任何偶然发现使用控制器时传递的NULL值的人都只需在POST请求的前面添加“ =”。

当我使用application / json Content-Type 时,控制器还传递了一个NULL值。请注意下面的“ application / x-www-form-urlencoded”内容类型。API的返回类型为“ application / json”。

 public static string HttpPostRequest(string url, Dictionary<string, string> postParameters)
    {
        string postData = "=";

        foreach (string key in postParameters.Keys)
        {
            postData += HttpUtility.UrlEncode(key) + "="
                  + HttpUtility.UrlEncode(postParameters[key]) + ",";
        }

        HttpWebRequest myHttpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url);
        myHttpWebRequest.Method = "POST";

        byte[] data = System.Text.Encoding.ASCII.GetBytes(postData);

        myHttpWebRequest.ContentType = "application/x-www-form-urlencoded";
        myHttpWebRequest.ContentLength = data.Length;

        Stream requestStream = myHttpWebRequest.GetRequestStream();
        requestStream.Write(data, 0, data.Length);
        requestStream.Close();

        HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();

        Stream responseStream = myHttpWebResponse.GetResponseStream();

        StreamReader myStreamReader = new StreamReader(responseStream, System.Text.Encoding.Default);

        string pageContent = myStreamReader.ReadToEnd();

        myStreamReader.Close();
        responseStream.Close();

        myHttpWebResponse.Close();

        return pageContent;
    }

1

希望发布哪种类型的值都没有关系,只需将其括在引号中即可将其作为字符串获取。不适用于复杂类型。

javascript:

    var myData = null, url = 'api/' + 'Named/' + 'NamedMethod';

    myData = 7;

    $http.post(url, "'" + myData + "'")
         .then(function (response) { console.log(response.data); });

    myData = "some sentence";

    $http.post(url, "'" + myData + "'")
         .then(function (response) { console.log(response.data); });

    myData = { name: 'person name', age: 21 };

    $http.post(url, "'" + JSON.stringify(myData) + "'")
         .then(function (response) { console.log(response.data); });

    $http.post(url, "'" + angular.toJson(myData) + "'")
         .then(function (response) { console.log(response.data); });

C#:

    public class NamedController : ApiController
    {
        [HttpPost]
        public int NamedMethod([FromBody] string value)
        {
            return value == null ? 1 : 0;
        }
    }

1

如果放置[FromBody]批注,并且您有一个Dto对象作为方法的参数,但仍然无法获取数据,请开始查看DTO的属性和字段。

我遇到了同样的问题,我的DTO无效。我发现原因是这些属性之一指向了无法序列化对象 :(这导致媒体格式化程序无法解析数据。因此该对象始终为null。希望它也对其他人有所帮助


1

仔细检查您的数据类型。dotnet模型联编程序不会将浮点数转换为整数(并且我假设其他相关概念)。这将导致整个模型被拒绝。

如果您有这样的json:

{
    "shoeSize": 10.5
}

但是您的C#模型如下所示:

class Shoe{
    public int shoeSize;
}

模型联编程序将拒绝该模型,并且您将获得null。


1

我对此很晚了,但是遇到了类似的问题,经过一天在这里进行大量回答并获得背景的一天后,我发现将一个或多个参数传递回Web API 2的最简单/轻巧的解决方案是如下:

假设您知道如何使用正确的路由来设置Web API控制器/操作(如果未参考):https : //docs.microsoft.com/zh-cn/aspnet/web-api/overview/getting-started-with -aspnet-web-api / tutorial-your-first-web-api

首先是Controller Action,此解决方案还需要Newtonsoft.Json库。

[HttpPost]
public string PostProcessData([FromBody]string parameters) {
    if (!String.IsNullOrEmpty(parameters)) {
        JObject json = JObject.Parse(parameters);

        // Code logic below
        // Can access params via json["paramName"].ToString();
    }
    return "";
}

客户端使用jQuery

var dataToSend = JSON.stringify({ param1: "value1", param2: "value2"...});
$.post('/Web_API_URI', { '': dataToSend }).done(function (data) {
     console.debug(data); // returned data from Web API
 });

我发现的关键问题是确保仅将单个总体参数发送回Web API,并确保其名称不只是值 { '': dataToSend }否则在服务器端您的值将为null。

使用此方法,您可以将一个或多个参数以JSON结构发送到Web API,而无需在服务器端声明任何其他对象来处理复杂数据。JObject还允许您动态迭代传入的所有参数,从而在您的参数随时间变化时可以更轻松地进行扩展。希望这可以帮助像我一样挣扎的人。


0

正确将正文中的单个参数传递给WebAPI可以正常工作 $.post(url, { '': productId }

并付诸行动 [HttpPost] public ShoppingCartAddRemoveViewModel Delete([FromBody]string value)

关键是使用魔术字“值”。它也可以是int或某种原始类型。无论内容类型还是标头更正,Mess都不是该代码在mvc post操作中有效。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.