无法从web api POST读取正文数据

时间:2012-08-17 14:27:02

标签: c# asp.net .net asp.net-web-api

我正在尝试从新的Asp.Net Web Api中的请求中提取一些数据。我有一个像这样的处理程序设置:

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);
    }
}

这是我的http请求:

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

问题在于无论我如何尝试从request.Content读取信息,它始终是空的。我试过了

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

以及

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

如果有效则无。我无法将数据从身体中取出。我在Windows 7上的IIS内部托管并使用Fiddler提交请求。我做错了什么?

6 个答案:

答案 0 :(得分:20)

问题在于,使用Web Api,主体只能读取一次。我运行了一个HTTP模块,它记录了请求的所有细节,并正在读取正文。

答案 1 :(得分:7)

这很难看,但是从最初的修补看来,你可以实际上替换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);
     }

我不知道这是好形式还是坏(可疑坏),但....它似乎工作并遵循模型我已经看到建议那些需要修改请求标题和内容“的方式”在“与DelegatingHandler。

您的里程可能会有很大差异。

答案 2 :(得分:6)

我的答案基于brmore的代码;

此功能可以安全地读取任何处理程序中的内容

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;
}

答案 3 :(得分:2)

这适合我。

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

答案 4 :(得分:0)

我有同样的问题,最后选择不在日志中写内容。 我正在记录Content-Type和Content-Length。

但是,尽可能在日志中写下所有内容总是一个好主意。

但似乎与WebApi目前我们无法实现这一目标。

答案 5 :(得分:0)

您可以先创建提供程序。 MultipartMemoryStreamProvider() 然后Request.Content.ReadAsMultipartAsync(provider); 然后阅读内容

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);
    }
}