Post参数始终为空
从WebAPI升级到RC后,我在WebAPI上调用POST时遇到了一些很奇怪的问题。 我甚至回到了在新项目上生成的基本版本。 所以:
public void Post(string value) { }
并从小提琴手打电话来:
Header: User-Agent: Fiddler Host: localhost:60725 Content-Type: application/json Content-Length: 29 Body: { "value": "test" }
当我debugging时,string“值”永远不会被分配给。 它只是总是NULL。 任何人有这个问题?
(我第一次看到更复杂types的问题)
这个问题不仅仅局限于ASP.NET MVC 4,RC安装后新的ASP.NET MVC 3项目也会出现同样的问题
既然你只有一个参数,你可以尝试使用[FromBody]
属性来装饰它,或者改变方法来接受一个值作为属性的DTO,正如我在这里所build议的那样: MVC4 RC WebApi参数绑定
更新:官方ASP.NET网站今天更新了一个很好的解释: http : //www.asp.net/web-api/overview/working-with-http/sending-html-form-data,-part-1
简而言之,当在主体中发送一个简单的types时,只发送前缀为等号(=)的值,例如body:
=test
今天我一直在挠头。
我的解决scheme是将[FromBody]
更改为HttpRequestMessage
,实质上移动了HTTP堆栈。
在我的情况下,我正在发送数据通过压缩JSON然后base64'd的电线。 所有这一切从一个Android应用程序。
我的web端点的原始签名看起来像这样(使用[FromBody]
):
我对这个问题的修复是恢复使用HttpRequestMessage
作为我的端点的签名。
然后,您可以使用以下这行代码访问发布数据:
这可以工作,并允许您访问原始的原始数据。 你不必在小提琴手的string开始处加上=号,或者改变内容types。
顺便说一下,我首先尝试了上面的答案之一,将内容types更改为:“Content-Type:application / x-www-form-urlencoded”。 对于原始数据,这是不好的build议,因为它会去掉+字符。
所以一个像这样开始的base64string:“MQ0AAB + LCAAAAAA”就像这样“MQ0AAB LCAAAAAA”! 不是你想要的。
使用HttpRequestMessage
另一个好处是你可以从你的端点访问所有的http头文件。
我刚刚发生这种情况使用提琴手。 问题是我没有指定Content-Type
。
尝试在您的POST请求中包含Content-Type
的标题。
Content-Type: application/x-www-form-urlencoded
或者,根据下面的注释,您可能需要包含JSON标头
Content-Type: application/json
我也遇到了这个问题,这就是我解决问题的方法
webapi代码:
public void Post([FromBody] dynamic data) { string value = data.value; /* do stuff */ }
客户代码:
$.post( "webapi/address", { value: "some value" } );
尝试创build一个类作为数据模型,然后发送一个JSON对象,其属性与您的数据模型类的属性匹配。 (注意:我已经testing了这个版本,它可以和我刚刚下载的最新的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主体中发送,content-type是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" }
我相信你必须创build一个数据模型类的原因是因为简单的值被假定为来自url参数,并且假定一个复数值来自于body。 他们有[FromBody]
和[FromUrl]
属性,但使用[FromBody] string value
仍然不适用于我。 似乎他们仍然在研究大量的错误,所以我相信这一点在将来会改变。
编辑:得到的XML在身体工作。 默认的XML序列化器改为DataContractSerializer而不是XmlSerializer。 把我的Global.asax文件中的以下行解决了这个问题( 参考 )
GlobalConfiguration.Configuration.Formatters.XmlFormatter.UseXmlSerializer = true;
我正在使用Postman
,我也犯了同样的错误。传递value
json对象,而不是string
{ "value": "test" }
当api参数是stringtypes的时候,显然上面的错误是错误的。
所以,只需在双引号中的string在api身体:
"test"
我正在寻找解决这个问题几分钟,所以我会分享我的解决scheme。
如果你发布一个模型,你的模型需要有一个空的/默认的构造函数,否则显然不能创build模型。 重构时要小心。 ;)
我有同样的问题,发现当更改内容types为“application / json”没有解决问题。 然而“application / json; charset = utf-8”工作。
我有一个类似的问题,我的Web API方法的请求对象始终为空。 我注意到,由于控制器操作名称的前缀为“Get”,Web API将此视为HTTP GET而不是POST。 重命名控制器动作后,现在按预期工作。
在我的情况下,问题是参数是一个string,而不是一个对象,我改变了参数为JOBject的Newsoft.Json和它的作品。
这对我工作:
-
创build一个C#DTO类,为每个要从jQuery / Ajax传递的属性提供一个属性
public class EntityData { public string Attr1 { get; set; } public string Attr2 { get; set; } }
-
定义web api方法:
[HttpPost()] public JObject AddNewEntity([FromBody] EntityData entityData) {
-
这样调用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) { ... } });
添加线
ValueProviderFactories.Factories.Add(new JsonValueProviderFactory());
在ASP.NET MVC3中为Global.asax.cs中的protected void Application_Start()
修复了类似的问题。
借助Angular,我能够以这种格式传递数据:
data: '=' + JSON.stringify({ u: $scope.usrname1, p: $scope.pwd1 }), headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8' }
而在Web API控制器中:
[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 }
而且,在控制器中,接受这样一个类的types:
[HttpPost] public string POST(Models.PostModel pm) { .... }
无论哪种方式工作,如果你有在API中build立的公共类,然后张贴JSON,否则后'='+ JSON.stringify({..:…,..:…})
如果您正在为您的Xml格式化程序或JSON格式化程序使用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;
和我的input参数不是null了。 感谢“Despertar”给我一个线索。
我知道这不是对这个问题的回答,但是当我寻找解决scheme时遇到了这个问题。
在我的情况下,复杂types没有被绑定,但我没有做一个POST,我正在做一个GET查询string参数。 解决方法是将[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 } }
我在提琴手中也有同样的问题。 我已经有了Content-Type: application/json; charset=utf-8
请求头中的Content-Type: application/json; charset=utf-8
或Content-Type: application/json
。
我的请求身体也是一个普通的string,在小提琴手我写了: {'controller':'ctrl'}
。 这使得我的POST方法中的string参数为null
。
修复 :请记住使用引号,从而指示一个string。 也就是说,我通过写"{'controller':'ctrl'}"
。 (注意:在编写JSON的时候,一定要用撇号或者像下面这样引号: "{\"controller\":\"ctrl\"}"
)。
我发现处理传递给MVC 6的简单JSON对象的最简单的方法是获取像NewtonSoft jObject这样的post参数的types:
public ActionResult Test2([FromBody] jObject str) { return Json(new { message = "Test1 Returned: "+ str }); ; }
如果你确定你发送的JSON,那么你必须仔细地跟踪你的API:
- 安装
Microsoft.AspNet.WebApi.Tracing
包 - 添加
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)
对于复杂types,Web API尝试使用媒体格式化程序从消息正文中读取值。
请检查是否有任何装饰你的模型类的[Serializable]
属性。
删除属性,看它是否工作。 这对我有效。
对于像Swagger或Postman一样的问题,如果你在post中传递一个简单的属性作为string,即使指定了“ContentType”,你仍然会得到一个空值。
传递只是:
myvalue的
将作为null进入控制器。
但是,如果你通过:
“myvalue的”
价值会得到正确的。
报价在这里有所不同。 当然,这只适用于Swagger和Postman。 例如,在使用Angular的Frontend应用程序中,应该由框架自动解决。
我对聚会有点晚了,但是任何在使用控制器时都经过了NULL值的人只要在你的POST请求的前面添加“=”即可。
当我使用application / json Content-Type时,控制器也传递了一个NULL值。 请注意下面的“application / x-www-form-urlencoded”Content-Type。 然而,API的返回types是“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; }
正确的将正文中的单个parameter passing给WebAPI运行此代码$.post(url, { '': productId }
并捕捉它在行动[HttpPost] public ShoppingCartAddRemoveViewModel Delete([FromBody]string value)
关键是使用魔术字“价值”。 它也可能是int或者一些原始types。 不pipe是内容types还是标题更正乱码是这个代码在mvc post操作中不起作用。
对我来说最好的解决scheme是完整的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; }
然后将string反序列化到您期望在post正文中的对象。 对我来说,WS_OpenSession是一个包含sessionid,user和key的类。
你可以从那里使用param对象并访问它的属性。
非常非常有效。
我确实说来自这个url:
不pipe你希望发布什么types的值,只要把它放在引号内就可以得到它的string。 不适用于复杂的types。
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; } }
问题是你的动作方法期待一个简单的types,即一个string参数值。 你提供的是一个对象。
有两个解决你的问题。
-
使用“ value ”属性创build一个简单的类,然后使用该类作为参数,在这种情况下,Web API模型绑定将从请求中读取JSON对象,并将其绑定到您的param对象的“values”属性。
-
只要通过string值“ testing ”,它会工作。
如果你把[FromBody]注解,你有一个Dto对象作为你的方法的参数,仍然无法获取数据通过,开始寻找你的DTO的属性和领域。
我有同样的问题,我的DTO是空的。 我发现原因是其中一个属性指向了一个无法序列化的对象 :(这将导致媒体格式化器无法parsing数据,因此该对象总是空的,希望它也能帮助其他人
仔细检查你的数据types。 dotnet模型联编程序不会将浮点数转换为整数(我假设其他相关的概念)。 这将导致整个模型被拒绝。
如果你有这样的json:
{ "shoeSize": 10.5 }
但是你的c#模型看起来像这样:
class Shoe{ public int shoeSize; }
模型联编程序将拒绝该模型,您将得到空值。
在我的情况下,用Newtonsoft中的[JsonObject(MemberSerialization.OptOut)]
属性来装饰参数类就行了。
例如:
[HttpPost] [Route("MyRoute")] public IHttpActionResult DoWork(MyClass args) { ... } [JsonObject(MemberSerialization.OptOut)] public Class MyClass { ... }
API:
[HttpPost] public bool UpdateTicketStatus(Ticket t) { string Id=t.Id; }
模型:
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”,“State”:“Committed”,“History”:“test1”}
请确保您已启用Cors。
[EnableCors(origins: "*", headers: "*", methods: "*")] public class TicketController : ApiController { }
这个链接帮助了我: http : //encosia.com/using-jquery-to-post-frombody-parameters-to-web-api/
基本上它说你应该使用一个空的名字作为参数:
public string Post([FromBody]string myParameter){ ... } $.post("/api/dosomething", { '' : "myvalue" });