C# 无法读取 ASP.NET WebApi 控制器中的 Request.Content
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10127803/
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 Request.Content in ASP.NET WebApi controller
提问by mcintyre321
I am writing a proxy using WebApi in a TransferMode.Streamed HttpSelfHostConfiguration exe.
我正在 TransferMode.Streamed HttpSelfHostConfiguration exe 中使用 WebApi 编写代理。
When I use fiddler to post to my ApiController, for some reason I cannot read the Request.Content - it returns "" even if I have POSTed data
当我使用 fiddler 发布到我的 ApiController 时,由于某种原因我无法读取 Request.Content - 即使我发布了数据,它也会返回 ""
public class ApiProxyController : ApiController
{
public Task<HttpResponseMessage> Post(string path)
{
return Request.Content.ReadAsStringAsync().ContinueWith(s =>
{
var content = new StringContent(s.Result); //s.Result is ""
CopyHeaders(Request.Content.Headers, content.Headers);
return Proxy(path, content);
}).Unwrap();
}
private Task<HttpResponseMessage> Proxy(string path, HttpContent content)
{
...
}
}
Here is my web request
这是我的网络请求
POST http://localhost:3001/api/values HTTP/1.1
Host: localhost:3001
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Content-Type: application/json
Content-Length: 26
{ "text":"dfsadfsadfsadf"}
What I am doing wrong? Why is s.Result coming back as the empty string rather than the raw json?
我做错了什么?为什么 s.Result 作为空字符串而不是原始 json 返回?
采纳答案by mcintyre321
I got this working in the end by inheriting from the base interface instead of ApiController - I think the ApiController was modelbinding which was eating the response
我最终通过从基本接口而不是 ApiController 继承来完成这项工作 - 我认为 ApiController 是模型绑定,它正在吞噬响应
edit: The right thing for building a proxy is a MessageHandler, not an ApiController
编辑:构建代理的正确方式是 MessageHandler,而不是 ApiController
回答by David Peden
Try replacing ReadAsStringAsync()with ReadAsAsync<string>().
尝试替换ReadAsStringAsync()为ReadAsAsync<string>().
回答by JeffR
I too struggled with this. ReadAsStringAsyncand ReadAsAsyncreturn a task object. Referencing the Resultproperty returns the content. It may be referencing the Result property causes the async read request to block.
我也为此苦苦挣扎。ReadAsStringAsync并ReadAsAsync返回一个任务对象。引用该Result属性返回内容。它可能引用 Result 属性导致异步读取请求阻塞。
Example:
例子:
string str = response.Content.ReadAsStringAsync().Result;
回答by Gertjan
You should use a complex type for your argument and then in the body use some json like
您应该为您的参数使用复杂类型,然后在正文中使用一些 json,例如
{ path: "c:..." }
{路径:“c:...”}
Als use the
也使用
Content-Type: application/json; charset=UTF-8
内容类型:应用程序/json;字符集=UTF-8
header in your post request so that the web api knows that json is contained in the body
在您的帖子请求中添加标头,以便 Web api 知道 json 包含在正文中
回答by EverPresent
I believe you are right about the ApiController eating the Request.Content. The "Request" object that you see in the ApiController is actually of type System.Net.Http.HttpRequestMessage. I was able to work around this issue but backing up to the System.Web.HttpRequest object like such:
我相信您对 ApiController 吃 Request.Content 的看法是正确的。您在 ApiController 中看到的“Request”对象实际上是 System.Net.Http.HttpRequestMessage 类型。我能够解决这个问题,但像这样备份到 System.Web.HttpRequest 对象:
Dim content as string
If HttpContext.Current.Request.InputStream.CanSeek Then
HttpContext.Current.Request.InputStream.Seek(0, IO.SeekOrigin.Begin)
End If
Using reader As New System.IO.StreamReader(HttpContext.Current.Request.InputStream)
content = reader.ReadToEnd()
End Using
I don't know if the seek rewind is necessary but I put it in just in case.
我不知道是否需要搜索倒带,但我把它放在以防万一。
回答by JJ_Coder4Hire
This signature for post eats the post data:
这个帖子签名会吃掉帖子数据:
public HttpResponseMessage Post([FromBody]string postdata)
change it to:
将其更改为:
public HttpResponseMessage Post()
then this call works fine to get the post data:
那么这个调用可以很好地获取发布数据:
string str = response.Content.ReadAsStringAsync().Result;
Tested it my self. use the first signature, str is empty, use the second str has post data!
我自己测试了一下。使用第一个签名,str为空,使用第二个str有post数据!
回答by Richard Hauer
I realise this is old, and has been answered, but for what it's worth, the reason you can't use ReadAsStringAsync()isn't because it 'eats the data' as has been suggested, it's because the content is being processed as a stream and since the data has been consumed by the message formatter the Position of the stream is already at the end.
我意识到这是旧的,并且已经得到了回答,但是就其价值而言,您不能使用的原因ReadAsStringAsync()不是因为它像建议的那样“吃掉数据”,而是因为内容正在作为流处理并且由于数据已被消息格式化程序消耗,因此流的位置已经在末尾。
In order to use ReadAsStringAsync()you first need to reset the content stream Position to the beginning.
为了使用,ReadAsStringAsync()您首先需要将内容流位置重置为开头。
I do it like this: response.RequestMessage.Content.ReadAsStreamAsync().Result.Seek( 0, System.IO.SeekOrigin.Begin )because I only have the HttpResponseMessage, but if you have direct access to the HttpRequestMessage (as you do inside the Controller) you can use Request.Content.ReadAsStreamAsync().Result.Seek( 0, System.IO.SeekOrigin.Begin )which is functionally equivalent I suppose.
我是这样做的:response.RequestMessage.Content.ReadAsStreamAsync().Result.Seek( 0, System.IO.SeekOrigin.Begin )因为我只有 HttpResponseMessage,但是如果您可以直接访问 HttpRequestMessage(就像您在控制器中所做的那样),您可以使用Request.Content.ReadAsStreamAsync().Result.Seek( 0, System.IO.SeekOrigin.Begin )我认为在功能上等效的。
Late Edit
后期编辑
Reading async streams with Resultas above will cause deadlocks and blocked threads under a number of circumstances. If you have to read from an async stream in a synchronous way, it's better to use the form:
Result在许多情况下,使用上述读取异步流将导致死锁和线程阻塞。如果您必须以同步方式从异步流中读取,最好使用以下形式:
new TaskFactory( CancellationToken.None,
TaskCreationOptions.None,
TaskContinuationOptions.None,
TaskScheduler.Default )
.StartNew<Task<TResult>>( func )
.Unwrap<TResult>()
.GetAwaiter()
.GetResult();
where funcis the async action you want to run, so in this case it would be something like async () => { await Request.Content.ReadAsStreamAsync(); }… in this way you can put the async parts of the method inside the StartNewpart and properly unwrap any exceptions that happen when marshalling back to your synchronous code.
func您要运行的异步操作在哪里,因此在这种情况下,它类似于async () => { await Request.Content.ReadAsStreamAsync(); }……通过这种方式,您可以将方法的异步部分放在该StartNew部分中,并正确解包在编组回同步代码时发生的任何异常。
Better still, make the whole stack async.
更好的是,使整个堆栈异步。
回答by HGMamaci
- Request.Content.ReadAsStreamAsync().Result.Seek( 0, System.IO.SeekOrigin.Begin)
- new System.IO.StreamReader(Request.Content.ReadAsStreamAsync().Result).ReadToEnd()
- Request.Content.ReadAsStreamAsync().Result.Seek(0, System.IO.SeekOrigin.Begin)
- new System.IO.StreamReader(Request.Content.ReadAsStreamAsync().Result).ReadToEnd()
回答by Soma Mbadiwe
This late addition to the answers here show how to read the POST data from WebAPI:
此处对答案的最新补充显示了如何从 WebAPI 读取 POST 数据:
string postData;
using (var stream = await request.Content.ReadAsStreamAsync())
{
stream.Seek(0, SeekOrigin.Begin);
using (var sr = new StreamReader(stream))
{
postData = await sr.ReadToEndAsync();
}
}

