我正在尝试实现此代码示例,但得到一个
HttpRequestException
-“将内容复制到流时出错。”当调用 ReadAsStringAsync()
方法时。内部异常是“无法访问已处置的对象”。我正在使用 Fiddler 来发出请求。我不明白。有人可以解释为什么我会遇到此异常并提供解决方案吗?
Web Api 方法:
public async Task<HttpResponseMessage> Post(HttpRequestMessage request)
{
try
{
var jsonString = await request.Content.ReadAsStringAsync();
}
catch (Exception ex)
{
throw;
}
return new HttpResponseMessage(HttpStatusCode.Created);
}
提琴手(POST):
User-Agent: Fiddler
Host: localhost:23567
Content-Length: 18
Content-Type: application/json; charset=utf-8
Body{"Test":1}
编辑:
我有线索,但需要验证。在 Web Api 控制器上,我有一个
ActionFilterAttribute
并且在其 OnActionExecuting
覆盖中,有这一行:
public override async void OnActionExecuting(HttpActionContext actionContext)
{
// omitted code
actionContext.Request.Content.ReadAsStreamAsync();
}
会不会因为内容已在此处阅读,所以无法再次使用?如果是这样,我怎样才能在方法中使其可用?这里的Content和HttpRequestMessage一样吗? 这可能包含答案。
只是一个猜测,应该作为评论发布,但我想包含一个代码片段:
也许您在
Post
块内调用 using
函数,但不要使用 await
。
using (HttpRequestMessage request = ...)
{
// Maybe you use this:
Post(request);
// Instead of this
var response = await Post(request);
}
或者您没有正确处理旧连接。
另外,尝试将
HttpVersion.Version10
添加到您的请求中,这会将标头请求从 Connection: keep-alive
更改为 Connection: close
,这在某些情况下您重用主机时可能会导致异常(搜索更多信息)
request.Version = HttpVersion.Version10;
var jsonString = await request.Content.ReadAsStringAsync();
我解决了这个问题,我的问题是响应是在 gzip 中:
var handler = new HttpClientHandler();
if (handler.SupportsAutomaticDecompression)
{
handler.AutomaticDecompression = DecompressionMethods.GZip |
DecompressionMethods.Deflate;
}
client = new HttpClient(handler);
var content = new FormUrlEncodedContent(valoresPost);
var response = await client.PostAsync(url, content);
var contenidoPdf = await response.Content.ReadAsByteArrayAsync();
因为控制器的
ActionFilterAttribute's
OnActionExecuting
方法正在调用 ReadAsStreamAsync
,所以无法再次读取内容。我将 ReadAsStreamAsync
更改为 ReadAsStringAsync
并且请求的内容在控制器中可用。显然,ReadAsStringAsync 缓冲了内容,因此它仍然可用。这个链接提供了答案。
我希望这篇(迟来的)帖子有一天能对某人有所帮助......
简而言之:接受的答案建议将整个文件作为字符串(而不是流)读取,以绕过读取问题
但是...将文件作为字符串读取并不是一个好主意
我发现用 MultipartMemoryStreamProvider 替换 MultipartFormDataStreamProvider 效果很好 - 并且可以让您根据需要读取上传的文件
我的代码(至少是相关部分)
[HttpPost]
[Route("upload/file")] // you may replace this route to suit your api service
public async Task<IHttpActionResult> Upload()
{
if (!Request.Content.IsMimeMultipartContent("form-data"))
{
return BadRequest("Unsupported media type");
}
try
{
var provider = new MultipartMemoryStreamProvider();
await Request.Content.ReadAsMultipartAsync(provider);
if (provider.Contents.Count == 0) return InternalServerError(new Exception("Upload failed"));
var file = provider.Contents[0]; // if you handle more then 1 file you can loop provider.Contents
var buffer = await file.ReadAsByteArrayAsync();
// .. do whatever needed here
return Ok();
}
catch (Exception ex)
{
return BadRequest(ex.GetBaseException().Message);
}
}
我正在添加到对话中,因为我在不同的上下文中遇到了这个错误。对我来说,我的网络应用程序有一个对单独 API 的现有调用。它之前可以工作,然后停止了,我收到了这个错误,但无法找出原因。结果是我的实体框架中的循环引用,本质上是两个不应该存在的对象之间的导航属性。它并没有破坏 API,因为我假设 EF 有一个默认的深度配置,导航属性将填充该深度以防止堆栈溢出,但它一定会压垮接收端的流并导致连接超时。
我在某些机器上遇到此错误,而在其他机器上则没有,奇怪的是,机器上安装了 Fiddler 似乎会导致该错误,而运行 fiddler 可以解决该错误。
PC 上没有安装 fiddler 的人不会发生这种情况。
这对我们来说不是代码问题,而是其他问题