C# 无法从 web api POST 读取正文数据
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12007689/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Cannot read body data from web api POST
提问by Micah
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:
我正在尝试从新的 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);
}
}
This is my http request:
这是我的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
the problem is that no matter how I try to read the info from request.Contentit's always empty. I've tried
问题是,无论我如何尝试从中读取信息,request.Content它始终是空的。我试过了
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?
如果有效,则没有。我无法从身体中取出数据。我在 Windows 7 上的 IIS 内托管并使用 Fiddler 提交请求。我究竟做错了什么?
采纳答案by Micah
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.
问题在于,使用 Web Api 时,主体只能被读取一次。我有一个 HTTP 模块正在运行,它记录请求的所有详细信息并通读正文。
回答by Sando
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.
但似乎目前我们无法使用 WebApi 实现这一点。
回答by brmore
It's ugly, but you it seems from initial tinkering that you can, in fact, replace the Content in DelegatingHandler ...
这很丑陋,但是从最初的修补看来,您实际上可以替换 DelegatingHandler 中的 Content ...
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.
您的里程可能会有很大差异。
回答by ulmer-morozov
I based my answer on brmore's code;
我的回答基于 brmore 的代码;
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;
}
回答by Johnny Chu
You can create a provider first. MultipartMemoryStreamProvider()then Request.Content.ReadAsMultipartAsync(provider);
then read the content
您可以先创建一个提供程序。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);
}
}
回答by Barbaros Alp
This works for me.
这对我有用。
[HttpPost]
public IHttpActionResult Index(HttpRequestMessage request)
{
var form = request.Content.ReadAsFormDataAsync().Result;
return Ok();
}

