Web Api 请求抛出“将内容复制到流时出错。”

问题描述 投票:0回答:6

我正在尝试实现此代码示例,但得到一个

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一样吗? 可能包含答案。

c# asp.net-web-api
6个回答
8
投票

只是一个猜测,应该作为评论发布,但我想包含一个代码片段:

也许您在

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

3
投票

我解决了这个问题,我的问题是响应是在 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();
             

2
投票

因为控制器的

ActionFilterAttribute's
OnActionExecuting
方法正在调用
ReadAsStreamAsync
,所以无法再次读取内容。我将
ReadAsStreamAsync
更改为
ReadAsStringAsync
并且请求的内容在控制器中可用。显然,ReadAsStringAsync 缓冲了内容,因此它仍然可用。这个链接提供了答案。


2
投票

我希望这篇(迟来的)帖子有一天能对某人有所帮助......

简而言之:接受的答案建议将整个文件作为字符串(而不是流)读取,以绕过读取问题

但是...将文件作为字符串读取并不是一个好主意

我发现用 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);
        }
    }

1
投票

我正在添加到对话中,因为我在不同的上下文中遇到了这个错误。对我来说,我的网络应用程序有一个对单独 API 的现有调用。它之前可以工作,然后停止了,我收到了这个错误,但无法找出原因。结果是我的实体框架中的循环引用,本质上是两个不应该存在的对象之间的导航属性。它并没有破坏 API,因为我假设 EF 有一个默认的深度配置,导航属性将填充该深度以防止堆栈溢出,但它一定会压垮接收端的流并导致连接超时。


0
投票

我在某些机器上遇到此错误,而在其他机器上则没有,奇怪的是,机器上安装了 Fiddler 似乎会导致该错误,而运行 fiddler 可以解决该错误。

PC 上没有安装 fiddler 的人不会发生这种情况。

这对我们来说不是代码问题,而是其他问题

© www.soinside.com 2019 - 2024. All rights reserved.