Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot read body data from web api POST

I'm trying to extract some data out of a request in the new Asp.Net Web Api. I have a handler setup like this:

public class MyTestHandler : DelegatingHandler
{
    protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    {
        if (request.Content.IsFormData())
        {
            request.Content.ReadAsStreamAsync().ContinueWith(x => {
                var result = "";
                using (var sr = new StreamReader(x.Result))
                {
                    result = sr.ReadToEnd();
                }
                Console.Write(result);
            });
        }

        return base.SendAsync(request, cancellationToken);
    }
}

This is my http request:

POST http://127.0.0.1/test HTTP/1.1
Connection: Keep-Alive
Content-Length: 29
Content-Type: application/x-www-form-urlencoded
Expect: 100-continue
Host: 127.0.0.1

my_property=my_value

the problem is that no matter how I try to read the info from request.Content it's always empty. I've tried

request.Content.ReadAsStreamAsync
request.Content.ReadAsFormDataAsync
request.Content.ReadAs<FormDataCollection>

as well as

    [HttpGet,HttpPost]
    public string Index([FromBody]string my_property)
    {
        //my_property == null
        return "Test";
    }

None if it works. I cannot get the data out of the body. I'm hosting inside IIS on Windows 7 and using Fiddler to submit the request. What am I doing wrong?

like image 610
Micah Avatar asked Aug 17 '12 14:08

Micah


2 Answers

The problem is that with the Web Api the body can only be read once. I had an HTTP module running that was logging all the details of the request and was reading through the body.

like image 189
Micah Avatar answered Oct 14 '22 08:10

Micah


It's ugly, but you it seems from initial tinkering that you can, in fact, replace the Content in DelegatingHandler ...

protected override Task SendAsync(
          HttpRequestMessage request,
          CancellationToken cancellationToken)
      {                    
          Stream stream = new MemoryStream();

          request.Content.ReadAsStreamAsync().Result.CopyTo(stream);
          stream.Seek(0,SeekOrigin.Begin);

          // copy off the content "for later"
          string query = new StreamReader(stream).ReadToEnd();
          stream.Seek(0,SeekOrigin.Begin);

          // if further processing depends on content type
          // go ahead and grab current value
          var contentType = request.Content.Headers.ContentType;

          request.Content = new StreamContent(stream);
          request.Content.Headers.ContentType = contentType;

          return base.SendAsync(request, cancellationToken);
     }

I have no idea if this is good form or bad (suspect bad), but .... it seems to work and follows model I've seen recommended for those that need to modify request headers and content "on the way in" with a DelegatingHandler.

Your mileage may vary substantially.

like image 30
brmore Avatar answered Oct 14 '22 08:10

brmore