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

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

public class MyTestHandler : DelegatingHandler { protected override System.Threading.Tasks.Task 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 

以及

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

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

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

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

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

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

我的答案基于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; } 

这对我有用。

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

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

但是,尽可能在日志中编写所有内容始终是个好主意。

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

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

 public async Task 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(); 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); } }