Post parameter is always null
自从为WebAPI升级到RC以来,在WebAPI上调用POST时遇到了一些真正的奇怪问题。
我什至回到了在新项目上生成的基本版本。 所以:
1 2 3 | public void Post(string value) { } |
并从Fiddler致电:
1 2 3 4 5 6 7 8 9 10 | 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线发送数据,然后将其进行base64处理。所有这一切都来自android应用。
我的Web终结点的原始签名看起来像这样(使用
我针对此问题的解决方法是恢复为使用
然后,您可以使用以下代码行访问发布数据:
这可以正常工作,并允许您访问未修改的原始帖子数据。您不必弄乱提琴手在字符串的开头放置=符号或更改内容类型。
顺便说一句,我首先尝试遵循上面的答案之一,即将内容类型更改为:" Content-Type:application / x-www-form-urlencoded"。对于原始数据,这是个坏建议,因为它会去除+个字符。
因此,以这样的开头的base64字符串:" MQ0AAB + LCAAAAAA"最终像这样的" MQ0AAB LCAAAAAA"!不是你想要的。
使用
由于您只有一个参数,因此可以尝试用
更新:官方ASP.NET网站今天进行了更新,并提供了很好的解释:https://docs.microsoft.com/zh-cn/aspnet/web-api/overview/advanced/sending-html-form-data-part- 1个
简而言之,当在正文中发送单个简单类型时,仅发送以等号(=)为前缀的值,例如身体:
我刚刚使用Fiddler发生了这种情况。问题是我没有指定
尝试在POST请求中包含
1 | Content-Type: application/x-www-form-urlencoded |
另外,根据下面的评论,您可能需要包含JSON标头
1 | Content-Type: application/json |
我也遇到了这个问题,这就是我解决问题的方式
webapi代码:
1 2 3 4 5 | public void Post([FromBody] dynamic data) { string value = data.value; /* do stuff */ } |
客户代码:
1 | $.post("webapi/address", { value:"some value" } ); |
我正在使用
1 2 3 | { "value":"test" } |
显然,当api参数为string类型时,上述错误是错误的。
因此,只需在api主体中的双引号中传递字符串即可:
1 | "test" |
尝试创建一个用作数据模型的类,然后发送一个具有与数据模型类的属性匹配的JSON对象。 (注意:我已经对此进行了测试,并且可以与我今天下载的最新MVC 4 RC 2012一起使用)。
1 2 3 4 5 6 7 8 9 | 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
1 | {"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参数,而单个复杂值则假定来自正文。它们确实具有
编辑:
有XML在体内起作用。默认的XML序列化程序已更改为DataContractSerializer,而不是XmlSerializer。将以下行放入我的Global.asax文件中可解决此问题(参考)
1 | GlobalConfiguration.Configuration.Formatters.XmlFormatter.UseXmlSerializer = true; |
经过一番尝试,我认为默认行为是正确的,没有什么可破解的。
唯一的窍门是:如果您的post方法参数是
1 2 3 4 5 6 | //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字符串没有外部双引号和转义内部引号,则应该能够将其解析为模型类(参数类型),例如
1 2 3 4 5 6 7 8 9 10 11 | 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" } |
我几分钟以来一直在寻找解决方案,所以,我将分享我的解决方案。
如果发布模型,则模型需要具有空/默认构造函数,否则显然无法创建模型。
重构时要小心。 ;)
这对我有用:
创建一个C#DTO类,为要从jQuery / Ajax传递的每个属性提供一个属性
1 2 3 4 5 | public class EntityData { public string Attr1 { get; set; } public string Attr2 { get; set; } } |
定义Web API方法:
1 2 3 | [HttpPost()] public JObject AddNewEntity([FromBody] EntityData entityData) { |
这样调用Web API:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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) { ... } }); |
对于那些像我一样遇到Swagger或Postman的问题的人,如果您在帖子中传递简单属性作为字符串,即使指定了" ContentType",您仍将获得null值。
仅通过:
我的价值
将作为空值进入控制器。
但是,如果您通过:
"我的价值"
该值将正确。
引号在这里有所不同。当然,这仅适用于Swagger和Postman。例如,在使用Angular的前端应用程序中,此问题应由框架自动解决。
我遇到了同样的问题,并发现将内容类型更改为" application / json"并不能解决问题。但是," application / json; charset = utf-8"有效。
我有一个类似的问题,其中Web API方法的请求对象始终为null。我注意到,由于控制器操作名称以" Get"为前缀,因此Web API将此视为HTTP GET而不是POST。重命名控制器动作后,它现在可以按预期工作。
在我的情况下,问题是参数是字符串而不是对象,我将参数更改为Newsoft.Json的JObject,它可以工作。
如果您确定已发送的JSON,则必须仔细跟踪API:
现在查看Debug输出,您可能会发现无效的
如果
没有人能猜出这样的例外:
1 | 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) |
加线
1 |
到Global.asax.cs中函数
使用Angular,我能够以这种格式传递数据:
1 2 | data: '=' + JSON.stringify({ u: $scope.usrname1, p: $scope.pwd1 }), headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8' } |
在Web API Controler中:
1 2 3 4 5 6 7 | [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数据:
1 | data: { PaintingId: 1, Title:"Animal show", Price: 10.50 } |
并且,在控制器中,接受这样的类类型:
1 2 3 4 5 6 | [HttpPost] public string POST(Models.PostModel pm) { .... } |
无论哪种方法,如果您在API中都有一个已建立的公共类,则发布JSON,否则发布'='+ JSON.stringify({..:...,..:...})
如果您为Xml Formatter或JSON Formatter使用DataContractSerializer,则需要摆脱它。
我的WebApiConfig文件中有这个:
1 2 3 4 5 6 7 8 9 10 11 | 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; } |
只需将
我知道这不是这个问题的答案,但是我在寻找问题的解决方案时遇到了它。
就我而言,没有绑定复杂类型,但是我没有进行POST,而是使用querystring参数进行GET。解决方法是将[FromUri]添加到arg:
1 2 3 4 5 6 7 | 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 } } |
我在Fiddler中遇到了同样的问题。我已经在请求标头中包含
我的请求正文也是一个普通字符串,在Fiddler中我写了:
解决:记住使用引号,从而表示一个字符串。也就是说,我通过编写
仔细检查您的数据类型。 dotnet模型联编程序不会将浮点数转换为整数(并且我假设其他相关概念)。这将导致整个模型被拒绝。
如果您有这样的json:
1 2 3 | { "shoeSize": 10.5 } |
但是您的C#模型看起来像这样:
1 2 3 | class Shoe{ public int shoeSize; } |
模型绑定器将拒绝该模型,并且您将获得null。
JSON.stringify(...)解决了我的问题
对于复杂类型,Web API尝试使用媒体类型格式化程序从消息正文中读取值。
请检查是否有任何装饰模型类的
删除该属性以查看它是否有效。这对我有用。
我参加聚会有点晚了,但是任何偶然发现使用控制器时传递的NULL值的人都只需在POST请求的前面添加" ="。
当我使用application / json Content-Type时,控制器还传递了一个NULL值。请注意下面的" application / x-www-form-urlencoded"内容类型。 API的返回类型为" application / json"。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | 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; } |
希望发布哪种类型的值都没有关系,只需将其括在引号中即可将其作为字符串获取。不适用于复杂类型。
javascript:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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#:
1 2 3 4 5 6 7 8 | public class NamedController : ApiController { [HttpPost] public int NamedMethod([FromBody] string value) { return value == null ? 1 : 0; } } |
对我来说最好的解决方案是使用完整的HTTP,如下所示:
1 2 3 4 5 6 7 8 9 | [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
我对此很晚了,但是遇到了类似的问题,经过一天在这里得到很多答案并获得背景的一天之后,我发现将一个或多个参数传递回Web API 2的最简单/轻巧的解决方案是如下:
假设您知道如何使用正确的路由来设置Web API控制器/操作(如果未参考):https://docs.microsoft.com/zh-cn/aspnet/web-api/overview/getting-started-with -aspnet-web-api /教程-第一个Web-api。
首先是Controller Action,此解决方案还需要Newtonsoft.Json库。
1 2 3 4 5 6 7 8 9 10 | [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
1 2 3 4 | 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,并确保仅名称
使用此方法,您可以将一个或多个参数以JSON结构发送到Web API,而无需在服务器端声明任何其他对象来处理复杂数据。 JObject还允许您动态地迭代传入的所有参数,从而在参数随时间变化时可以更轻松地进行扩展。希望这可以帮助像我一样挣扎的人。
我发现处理传递到MVC 6中的简单JSON对象的最简单方法是获取post参数的类型,例如NewtonSoft jObject:
1 2 3 4 | public ActionResult Test2([FromBody] jObject str) { return Json(new { message ="Test1 Returned:"+ str }); ; } |
我也遇到了将null作为参数的问题,但它与大型对象有关。原来,问题与IIS最大长度有关。可以在web.config中进行配置。
1 2 3 | <system.web> <httpRuntime targetFramework="4.7" maxRequestLength="1073741824" /> </system.web> |
我想知道为什么Web API抑制了错误并将空对象发送到我的API。我使用Microsoft.AspNet.WebApi.Tracing发现了错误。
在ASP.NET Core中遇到了类似的问题,另一个可能的原因是ASP.NET绑定(无提示)失败,原因是由于各种原因,例如发送null绑定到非null属性:
1 2 3 4 5 6 7 8 9 | { "prop1":1139357, "prop2":1139356, "items":[ {"key":"15","someprop":34,"notnullprop":null}, {"key":"16","someprop":34,"notnullprop":null}, {"key":"22","someprop":34,"notnullprop":null}] } |
在这种情况下,不会引发任何异常,并且整个模型将为null,即使这种情况发生在对象层次结构的深处。
希望这可以帮助。
在不同的评论和其他论坛中查找,我混合了一些代码片段,对于我来说,此代码有效...
...在控制器中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public HttpResponseMessage Post([FromBody] string jsonData) { HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, jsonData); try { string jsonString = jsonData.ToString(); JArray jsonVal = JArray.Parse(jsonString) as JArray; dynamic mylist= jsonVal; foreach (dynamic myitem in mylist) { string strClave=string.Empty; string strNum=string.Empty; string strStatus=string.Empty; strClave = myitem.clave; strNum=myitem.num; strStatus = myitem.status; } |
...在WebApiConfig.cs中包含此行,以避免[FromBody]变量中的空值var jsonFormatter = config.Formatters.OfType()。First();
1 2 3 4 5 6 7 8 9 | 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(); /*this line makes no more null when use [FromBody]*/ } |
....在客户端,重要的是在序列化数据之前连接等号(字符串json =" =" + SerialData;)
我正在使用的序列化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | System.Web.Script.Serialization.JavaScriptSerializer serializer = new System.Web.Script.Serialization.JavaScriptSerializer(); List<Dictionary<string, object>> rows = new List<Dictionary<string, object>>(); Dictionary<string, object> row; foreach (DataRow dr in DsCnx.Tables[0].Rows) { row = new Dictionary<string, object>(); foreach (DataColumn col in DsCnx.Tables[0].Columns) { row.Add(col.ColumnName, dr[col]); } rows.Add(row); } SerialData= serializer.Serialize(rows); PostRequest("http://localhost:53922/api/Demo", SerialData); |
这是我的PostRequest函数,这里使用的内容类型是httpWebRequest.ContentType =" application / x-www-form-urlencoded; charset = utf-8" ;:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | private static string PostRequest(string url, string SerialData) { string result = String.Empty; HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url); httpWebRequest.ContentType ="application/x-www-form-urlencoded; charset=utf-8"; httpWebRequest.Method ="POST"; using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream())) { string json ="=" + SerialData; streamWriter.Write(json); streamWriter.Flush(); streamWriter.Close(); } try { using (var response = httpWebRequest.GetResponse() as HttpWebResponse) { if (httpWebRequest.HaveResponse && response != null) { using (var reader = new StreamReader(response.GetResponseStream())) { result = reader.ReadToEnd(); } } } } catch (WebException e) { if (e.Response != null) { using (var errorResponse = (HttpWebResponse)e.Response) { using (var reader = new StreamReader(errorResponse.GetResponseStream())) { string error = reader.ReadToEnd(); result = error; } } } } return result.ToString(); } |
这是我在其中找到一个可供参考的代码示例的链接:
https://weblog.west-wind.com/posts/2012/Aug/30/Using-JSONNET-for-dynamic-JSON-parsing#jobject-and-jarray-in-aspnet-web-api
https://blog.codenamed.nl/2015/05/12/why-your-frombody-parameter-is-always-null/
如果在Postman的json查询中有此字符" ",则在json字符串值中需要字符" "时,应转义该字符。
例:
1 2 3 | { "path":"C:\\Users\\Test\\Documents\\test.txt" } |
在我的案例中,使用Newtonsoft的
例如:
1 2 3 4 5 6 7 8 9 10 11 12 | [HttpPost] [Route("MyRoute")] public IHttpActionResult DoWork(MyClass args) { ... } [JsonObject(MemberSerialization.OptOut)] public Class MyClass { ... } |
如果您放置[FromBody]批注,并且您有一个Dto对象作为方法的参数,但仍然无法获取数据,请开始查看DTO的属性和字段。
我遇到了同样的问题,我的DTO无效。我发现原因是这些属性之一指向了无法序列化的对象:(导致媒体格式化程序无法解析数据。因此该对象始终为null。
希望它也能帮助别人
问题是您的操作方法需要简单的类型,即字符串参数值。您提供的是一个对象。
有2个解决方案来解决您的问题。
创建一个具有" value"属性的简单类,然后将该类用作参数,在这种情况下,Web API模型绑定将从请求中读取JSON对象,并将其绑定到您的param对象" values"属性。
只需传递字符串值" test",它将起作用。
正确将正文中的单个参数传递给WebAPI可以使此代码
并将其付诸行动
关键是使用魔术字"值"。它也可以是int或某种原始类型。
无论内容类型还是标题更正
麻烦的是,此代码在mvc后操作中不起作用。
API:
1 2 3 4 5 | [HttpPost] public bool UpdateTicketStatus(Ticket t) { string Id=t.Id; } |
模型:
1 2 3 4 5 6 7 | public class Ticket { public int Id { get; set; } public string AssignedTo { get; set; } public string State { get; set; } public string History { get; set; } } |
使用Post man工具,将内容作为json发送,并带有原始数据,如下所示。有用
{
" Id":" 169248",
" AssignedTo":" xxxx",
"州":"委员会",
"历史记录":" test1"
}
请确保您已启用Cors。
1 2 3 4 | [EnableCors(origins:"*", headers:"*", methods:"*")] public class TicketController : ApiController { } |
该链接对我有帮助:http://encosia.com/using-jquery-to-post-frombody-parameters-to-web-api/
基本上,它说您应该为参数使用一个空名称:
1 2 3 4 5 | public string Post([FromBody]string myParameter){ ... } $.post("/api/dosomething", { '' :"myvalue" }); |