自从升级到RC for WebAPI后,我在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"
}
调试时,永远不会分配字符串“value”。它总是为NULL。 谁有这个问题?
(我第一次看到更复杂类型的问题)
问题不仅仅是绑定到ASP.NET MVC 4,RC安装后新的ASP.NET MVC 3项目也会出现同样的问题
答案 0 :(得分:99)
今天我一直在摸不着头脑。
我的解决方案是将[FromBody]
更改为HttpRequestMessage
,从根本上提升HTTP堆栈。
在我的情况下,我通过线路发送数据,这是拉链json,然后是base64' d。这一切都来自Android应用程序。
我的网络端点的原始签名如下所示(使用[FromBody]
):
我对此问题的解决方法是恢复使用HttpRequestMessage
作为我的端点的签名。
然后,您可以使用以下代码行访问帖子数据:
这可以使用并允许您访问原始未触及的帖子数据。你不必乱搞小提琴手在你的字符串的开头添加一个=符号或更改内容类型。
顺便说一句,我首先尝试按照上面的一个答案将内容类型更改为:" Content-Type:application / x-www-form-urlencoded"。对于原始数据,这是一个糟糕的建议,因为它剥离了+字符。
所以一个base64字符串就像这样开始:" MQ0AAB + LCAAAAAA"像这样结束" MQ0AAB LCAAAAAA"!不是你想要的。
使用HttpRequestMessage
的另一个好处是您可以访问端点中的所有http标头。
答案 1 :(得分:97)
由于您只有一个参数,您可以尝试使用[FromBody]
属性进行装饰,或者更改方法以接受带有值作为属性的DTO,正如我在此处所建议的那样:MVC4 RC WebApi parameter binding
更新:官方的ASP.NET网站今天更新了一个很好的解释:https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/sending-html-form-data-part-1
简而言之,当在正文中发送单个简单类型时,只发送前缀为等号(=)的值,例如:体:
=test
答案 2 :(得分:70)
我刚刚使用Fiddler发生了这种情况。问题是我没有指定Content-Type
。
尝试在POST请求中包含Content-Type
的标头。
Content-Type: application/x-www-form-urlencoded
或者,根据下面的评论,您可能需要包含JSON标头
Content-Type: application/json
答案 3 :(得分:53)
我也遇到过这个问题,这就是我解决问题的方法
webapi代码:
public void Post([FromBody] dynamic data)
{
string value = data.value;
/* do stuff */
}
客户代码:
$.post( "webapi/address", { value: "some value" } );
答案 4 :(得分:34)
我正在使用Postman
并且我犯了同样的错误。将value
作为json对象而不是字符串传递
{
"value": "test"
}
当api参数的类型为字符串时,显然上面的 错误 。
所以,只需在api正文中用双引号传递字符串:
"test"
答案 5 :(得分:18)
尝试创建一个类作为数据模型,然后发送一个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主体中发送,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" }
我认为您必须创建数据模型类的原因是因为假设简单值来自url参数,并且假定单个复杂值来自正文。它们确实具有[FromBody]
和[FromUrl]
属性,但使用[FromBody] string value
仍然无效。好像他们仍然在制造很多错误,所以我相信这将在未来发生变化。
修改强> 让XML在正文中工作。默认的XML序列化程序已更改为DataContractSerializer而不是XmlSerializer。将以下行放在我的Global.asax文件中修复了此问题(reference)
GlobalConfiguration.Configuration.Formatters.XmlFormatter.UseXmlSerializer = true;
答案 6 :(得分:13)
经过一些尝试,我认为默认行为是正确的,没有什么可以破解的。
唯一的诀窍是:如果你的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"
}
答案 7 :(得分:11)
我现在正在寻找这个问题的解决方案几分钟,所以我会分享我的解决方案。
如果发布模型,模型需要有一个空/默认构造函数,否则显然不能创建模型。 重构时要小心。 ;)
答案 8 :(得分:6)
对于那些与我一样有 Swagger 或 Postman 相同问题的人,如果您在帖子中传递一个简单属性作为字符串,即使使用& #34;的ContentType&#34;如果指定,你仍然会得到一个空值。
仅传递:
myvalue的
将控制器作为空值。
但如果你通过:
<强>&#34; myvalue的&#34; 强>
价值将会正确。
报价在这里有所不同。当然,这只适用于Swagger和Postman。例如,在使用Angular的前端应用程序中,这应该由框架自动解决。
答案 9 :(得分:6)
这对我有用:
创建一个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) {
...
}
});
答案 10 :(得分:5)
我有同样的问题,发现将内容类型更改为“application / json”时没有解决问题。但是“application / json; charset = utf-8”有效。
答案 11 :(得分:4)
我遇到类似的问题,我的Web API方法的请求对象始终为null。我注意到,由于控制器操作名称以“Get”为前缀,因此Web API将其视为HTTP GET而不是POST。重命名控制器操作后,它现在可以按预期工作。
答案 12 :(得分:3)
在我的情况下,问题是参数是一个字符串而不是一个对象,我将参数更改为Newsoft.Json的JObject,它可以工作。
答案 13 :(得分:2)
使用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,否则发布&#39; =&#39; + JSON.stringify({..:...,..:...})
答案 14 :(得分: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;
,我的输入参数就不再为空了。感谢&#39; Despertar&#39;给我一个线索。
答案 15 :(得分:2)
如果您确定已发送的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)
答案 16 :(得分:2)
添加行
ValueProviderFactories.Factories.Add(new JsonValueProviderFactory());
到Global.asax.cs中函数protected void Application_Start()
的末尾,在ASP.NET MVC3中修复了类似的问题。
答案 17 :(得分:1)
我已经很晚了,但是遇到了类似的问题,在经过一天的大量答案并获得背景后,我找到了最简单/轻量级的解决方案,将一个或多个参数传回Web API 2行动如下:
这假定您知道如何使用正确的路由设置Web API控制器/操作,如果不是,请参阅:https://docs.microsoft.com/en-us/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。 / p>
通过这种方式,您可以在JSON结构中向Web API发送一个或多个参数,并且您无需在服务器端声明任何额外的对象来处理复杂数据。 JObject还允许您动态迭代传入的所有参数,以便在参数随时间变化时实现更轻松的可伸缩性。希望这可以帮助那些像我一样苦苦挣扎的人。
答案 18 :(得分:1)
我遇到了将null作为参数的问题,但它与大对象有关。原来这个问题与IIS最大长度有关。它可以在web.config中配置。
<system.web>
<httpRuntime targetFramework="4.7" maxRequestLength="1073741824" />
</system.web>
我想知道为什么Web API会抑制错误并将空对象发送到我的API。我使用Microsoft.AspNet.WebApi.Tracing找到了错误。
答案 19 :(得分: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;
}
}
答案 20 :(得分:1)
我在聚会上有点晚了,但是在使用控制器时偶然发现NULL值的人只需添加&#34; =&#34;在POST请求的前面。
当我使用 application / json Content-Type时,控制器也传递了NULL值。注意&#34; application / x-www-form-urlencoded&#34;内容类型如下。然而,来自API的返回类型是&#34; application / json&#34;。
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;
}
答案 21 :(得分:1)
对于复杂类型,Web API尝试使用媒体类型格式化程序从邮件正文中读取值。
请检查您是否有任何[Serializable]
属性装饰您的模型类。
删除属性以查看其是否有效。这对我有用。
答案 22 :(得分:1)
我发现处理简单JSON对象的最简单方法是传递给MVC 6,它获取了像NewtonSoft jObject这样的post参数的类型:
public ActionResult Test2([FromBody] jObject str)
{
return Json(new { message = "Test1 Returned: "+ str }); ;
}
答案 23 :(得分:1)
我知道这不是这个问题的答案,但我在寻找问题的解决方案时遇到过它。
在我的情况下,复杂类型没有绑定但是我没有进行POST,我正在使用查询字符串参数进行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
}
}
答案 24 :(得分:1)
我在Fiddler遇到了同样的问题。我在请求标头中已经有Content-Type: application/json; charset=utf-8
或Content-Type: application/json
。
我的请求正文也是一个普通的字符串,而在Fiddler我写过:{'controller':'ctrl'}
。这使我的POST方法中的字符串参数为null
。
修复:记得使用引号,从而指示一个字符串。也就是说,我通过编写"{'controller':'ctrl'}"
来修复它。 (注意:在编写JSON时,要么确保使用撇号,要么转义引号,如下所示:"{\"controller\":\"ctrl\"}"
)。
答案 25 :(得分: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对象并访问其属性。
非常有效。
我确实说过来自这个网址:
答案 26 :(得分:0)
问题是你的action方法期望一个简单的类型,即字符串参数值。你提供的是一个对象。
您的问题有两种解决方案。
使用&#34; 值&#34;创建一个简单的类属性然后使用该类作为参数,在这种情况下,Web API模型绑定将从请求中读取JSON对象并将其绑定到您的param对象&#34; values&#34;属性。
只需传递字符串值&#34; 测试&#34;,就可以了。
答案 27 :(得分:0)
如果您放置[FromBody]注释并且您有一个Dto对象作为方法的参数但仍无法获取数据,请开始查看DTO的属性和字段。
我遇到了同样的问题,我的DTO无效。我发现原因之一是其中一个属性指向无法序列化的 对象 :(这会导致媒体格式化程序无法解析数据。因此对象始终为null。 希望它也能帮助别人
答案 28 :(得分:0)
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”, “国”:“承诺”, “历史”:“测试1” }
请确保您已启用Cors。
[EnableCors(origins: "*", headers: "*", methods: "*")]
public class TicketController : ApiController
{
}
答案 29 :(得分:0)
仔细检查您的数据类型。 dotnet模型绑定器不会将浮点数转换为整数(我假设其他相关概念)。这将导致整个模型被拒绝。
如果你有这样的json:
{
"shoeSize": 10.5
}
但您的c#模型如下所示:
class Shoe{
public int shoeSize;
}
模型绑定器将拒绝该模型,您将获得null。
答案 30 :(得分:0)
在我的案例中,用Newtonsoft的[JsonObject(MemberSerialization.OptOut)]
属性来装饰参数类就可以了。
例如:
[HttpPost]
[Route("MyRoute")]
public IHttpActionResult DoWork(MyClass args)
{
...
}
[JsonObject(MemberSerialization.OptOut)]
public Class MyClass
{
...
}
答案 31 :(得分:0)
将正文中的单个参数传递给WebAPI可以使用此代码$.post(url, { '': productId }
并在行动[HttpPost] public ShoppingCartAddRemoveViewModel Delete([FromBody]string value)
关键是使用魔术词'价值'。它也可以是int或某种原始类型。 无论内容类型还是标题更正 混乱是这个代码在mvc post action中不起作用。
答案 32 :(得分:0)
如果你有这个角色&#39; \&#39;在Postman的json查询中,如果你需要字符&#39; \&#39;在json字符串值中。
示例:
mum -> #u#
dad -> #a#
Swiss -> #wi## //also if it is UpperCase
Albert -> Albert //no letter is like the first
答案 33 :(得分:0)
希望这会有所帮助。
在不同的评论和其他论坛中,我混合了一些代码片段,对于我来说,此代码有效...
...在控制器中
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();
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]*/
}
....在客户端,重要的是在序列化数据之前连接等号( string json =“ =” + SerialData; )
我正在使用
进行序列化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”; :
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://blog.codenamed.nl/2015/05/12/why-your-frombody-parameter-is-always-null/
答案 34 :(得分:0)
遇到了与ASP.NET Core类似的问题,另一个可能的原因是ASP.NET绑定(无提示)失败,原因是由于各种原因,例如将null绑定到非null属性:
{
"prop1":1139357,
"prop2":1139356,
"items":[
{"key":"15","someprop":34,"notnullprop":null},
{"key":"16","someprop":34,"notnullprop":null},
{"key":"22","someprop":34,"notnullprop":null}]
}
在这种情况下,不会发生异常,并且整个模型将为空,即使这种情况发生在对象层次结构的深处。
答案 35 :(得分:0)
JSON.stringify(...)解决了我的问题
答案 36 :(得分:0)
我知道OP最初发送的是单个字符串,但为将来参考,值得注意的是,格式错误的JSON也将以null
的形式到达post方法中。在我的情况下,两个属性之间缺少逗号会导致本来很好的中断。
答案 37 :(得分:0)
我在此线程中尝试了许多答案,但没有一个对我有用。然后我遇到了类似帖子的答案:https://stackoverflow.com/a/40853424/2120023,其中他提到了HttpContext.Request.Body
,因此进行了另一次搜索,我发现了这个https://stackoverflow.com/a/1302851/2120023,这给了我HttpContext.Current
,所以我终于明白了使用以下方式工作:
HttpContext.Current.Request.Form.Get("value");
我从邮递员的请求:
curl --location --request POST 'https://example.com/token' --header 'Content-Type: application/x-www-form-urlencoded' --data-urlencode 'value=test'
答案 38 :(得分:0)
有一天我遇到了和你一样的问题,就我而言,问题是,我用作 json 容器的类没有 get 和 set 定义,所以 API 不知道如何将 JSON 数据填充到实例中。
我的示例 json 类是 .
public class Usuario
{
public int id { get; set; }
public string nombre { get; set; }
}
正如你所看到的,你分别有 get 和 set,所以它会填满。
如果您删除它们,您将获得创建该类的空实例的帖子。
答案 39 :(得分:-3)
此链接帮助了我:http://encosia.com/using-jquery-to-post-frombody-parameters-to-web-api/
基本上它说你应该为参数使用一个空名称:
public string Post([FromBody]string myParameter){
...
}
$.post("/api/dosomething", { '' : "myvalue" });