简体   繁体   中英

WebAPI [FromBody] always null

I received a request like this.

POST /API/Event?EventID=15&UserID=1&Severity=5&DeptID=1&FlowTag=CE HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: localhost:8088
Content-Length: 9
Expect: 100-continue
Connection: Keep-Alive


HTTP/1.1 100 Continue


Desc=test

And my WebAPI interface is like this:

[Route("API/Event"), HttpPost]
public IHttpActionResult StationCreateWorkItem(long EventID, long UserID, int Severity,
    long DeptID, string FlowTag, [FromBody] string Desc)

However, my Desc parameter is always NULL. May I know how can I retrieve the body content if there is no way for me to use [FromBody] in WebAPI (OWIN)

Sorry, I can't change the incoming message, because it was developed by another company.

By default, Web API uses the following rules to bind parameters:

  • If the parameter is a "simple" type, Web API tries to get the value from the URI.
  • Simple types include the .NET primitive types ( int , bool , double , and so forth), plus TimeSpan , DateTime , Guid , decimal , and string , plus any type with a type converter that can convert from a string.
  • For complex types, Web API tries to read the value from the message body, using a media-type formatter.
  • If you have a primitive type in the URI or if you have a complex type in the body, then you don't have to add any attributes (neither [FromBody] nor [FromUri] ).
  • At most, one parameter is allowed to read from the message body. So this will not work:

     public HttpResponseMessage Post([FromBody] int id, [FromBody] string name) { ... }

Parameter Binding in ASP.NET Web API (MSDN)

How WebAPI does Parameter Binding (MSDN)

Now the solution:

POST /API/Event?EventID=15&UserID=1&Severity=5&DeptID=1&FlowTag=CE HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: localhost:8088
Content-Length: 9
Expect: 100-continue
Connection: Keep-Alive

HTTP/1.1 100 Continue

=test

removed Desc

Well, you may want to do this for raw string data. If you use HTTPClient.PostAsync , you need to use HttpRequest /response instead of [FromBody] , like so:

[Route("value"), HttpPost]
public HttpResponseMessage Post(HttpRequestMessage value)
{
    var res = value.Content.ReadAsStringAsync().Result;
    return null;
}

HttpClient client = new HttpClient();
var content = new StringContent("boe");
var result = client.PostAsync(baseAddress + "api/value", content).Result;

The trick is the async part, and your [FromBody] is null, as it is a async post. You still need to read the data out of the request.

On the other hand, if you want "DTO" complex types, you can use the [FromBody] construction like so:

public class SomeDto
{
    public string Name { get; set; }
}

[Route("somedto"), HttpPost]
public void PostDto([FromBody]SomeDto value)
{

}

You call it like this:

var requestJson = JsonConvert.SerializeObject(new SomeDto() { Name = "1" });
var content = new StringContent(requestJson);
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
result = client.PostAsync(baseAddress + "api/somedto", content).Result;

Lastly, you may want to use these:

[Route("valueparam/{value}"), HttpGet]
public void PostWithParam([FromUri]string value)
{
}
result = client.GetAsync(baseAddress + "api/valueparam/1").Result;

And:

[Route("valueparamfrombody"), HttpPost]
public void PostWithParam2([FromBody] JObject value1)
{
}


var req = new
{
   value1 = "1"
};
var obj = JsonConvert.SerializeObject(req);
content = new StringContent(obj);
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");            
result = client.PostAsync(baseAddress + "api/valueparamfrombody", content).Result;

In my case , my model has a Guid? property, I send an empty string, so the parsing is failed and I get null .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM