Micah
Micah

Reputation: 116090

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?

Upvotes: 14

Views: 28084

Answers (6)

Barbaros Alp
Barbaros Alp

Reputation: 6434

This works for me.

[HttpPost]
public IHttpActionResult Index(HttpRequestMessage request)
{
    var form = request.Content.ReadAsFormDataAsync().Result;
    return Ok();
}

Upvotes: 2

Johnny Chu
Johnny Chu

Reputation: 929

You can create a provider first. MultipartMemoryStreamProvider() then Request.Content.ReadAsMultipartAsync(provider); then read the content

public async Task<IHttpActionResult> Post(int id, string type)
{
    // Check if the request contains multipart/form-data.
    if(!Request.Content.IsMimeMultipartContent("form-data"))
        return BadRequest("Unsupported media type");

    try
    {
        var azureManager = new AzureManager();
        var imageManager = new ImageManager();
        var provider = new MultipartMemoryStreamProvider();

        await Request.Content.ReadAsMultipartAsync(provider);

        var assets = new List<Asset>();
        foreach (var file in provider.Contents)
        {
            var stream = await file.ReadAsStreamAsync();
            var guid = Guid.NewGuid();
            string blobName = guid.ToString();

            await azureManager.UploadAsync(blobName, stream);

            var asset = new Asset
            {
                PropertyId = id,
                FileId = guid,
                FileName = file.Headers.ContentDisposition.FileName.Trim('\"').ToLower(),
                FileSize = file.Headers.ContentLength ?? 0,
                MimeType = file.Headers.ContentType.MediaType.ToLower()
            };

            if (type == "photos")
            {
                asset.Type = AssetType.Photo;

                // Resize and crop copies to 16:9
                using (MemoryStream thumb = imageManager.ResizeImage(stream, 320, 180))
                {
                    await azureManager.UploadAsync(blobName, thumb, BlobContainers.Thumbs);
                }
                using (MemoryStream photo = imageManager.ResizeImage(stream, 1024, 576))
                {
                    await azureManager.UploadAsync(blobName, photo, BlobContainers.Photos);
                }
            }
            else
                asset.AssumeType();

            assets.Add(asset);
        }

        db.Assets.AddRange(assets);
        await db.SaveChangesAsync();

        return Ok(new { Message = "Assets uploaded ok", Assets = assets });
    }
    catch (Exception ex)
    {
        return BadRequest(ex.GetBaseException().Message);
    }
}

Upvotes: 0

ulmer-morozov
ulmer-morozov

Reputation: 1315

I based my answer on brmore's code;

This function can safe read content in any handler

private string SafeReadContentFrom(HttpRequestMessage request)
{
     var contentType = request.Content.Headers.ContentType;
     var contentInString = request.Content.ReadAsStringAsync().Result;
     request.Content = new StringContent(contentInString);
     request.Content.Headers.ContentType = contentType;
     return contentInString;
}

Upvotes: 6

brmore
brmore

Reputation: 896

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.

Upvotes: 7

Sando
Sando

Reputation: 667

I had the same issue and finally chose not to write content in the logs. I am living with logging Content-Type and Content-Length.

But it is always a good idea to write all the content in the logs as far as possible.

But seems like with WebApi presently we cannot achieve this.

Upvotes: 0

Micah
Micah

Reputation: 116090

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.

Upvotes: 20

Related Questions