3

我正在制作一个 .Net Web API 应用程序,其中以下代码正在调用我的不同 c# 应用程序以下载文件,然后将其保存在磁盘上。有时一切正常,我得到了文件,但有时下面的代码无法读取流,我可以在我的其他应用程序中看到远程连接关闭异常。

public async Task<string> GetFilePathAsync(TestModel model)
{
    string filePath = string.Empty;
    var response = await cgRequestHelper.DownloadAsync(model);  

    if (response.IsSuccessStatusCode)
    {                    
        filePath = await SaveCgStreamAsync(cgResponse, serviceModel.FileName);
    }
    return filePath;
}

public async Task<HttpResponseMessage> DownloadAsync(TestModel model)
{            
    if (model == null)
        throw new ArgumentNullException("model");
    if (string.IsNullOrEmpty(model.Url))
        throw new ArgumentNullException("Url");
    if (model.Headers == null)
        throw new ArgumentNullException("Headers");

    HttpResponseMessage response;
    using (HttpClient httpClient = new HttpClient())
    {
        foreach (var header in model.Headers)
        {
            httpClient.DefaultRequestHeaders.Add(header.Key, header.Value);
        }
        response = await httpClient.GetAsync(model.Url, HttpCompletionOption.ResponseHeadersRead); 
    }
    return response;            
}        

public async Task<string> SaveCgStreamAsync(HttpResponseMessage response, string fileName)
{
    if (response == null)
        throw new ArgumentNullException("response");
    if (string.IsNullOrEmpty(fileName))
        throw new ArgumentNullException("fileName");

    var filePath = _CreateTemporaryLocation(fileName);
    Stream cgStream = null;
    Stream fileStream = null;
    try
    {
        cgStream =  await response.Content.ReadAsStreamAsync();
        fileStream = File.Open(filePath, FileMode.Create);
        await cgStream.CopyToAsync(fileStream);
    }
    catch(Exception e)
    {
        throw;
    }
    finally
    {
        if(cgStream != null)
            cgStream.Dispose();
        if(fileStream != null)
            fileStream.Dispose();
    }

    return filePath;            
}

我在 Global.asax.cs 中设置了 ServicePointManager.DefaultConnectionLimit = 1000

在我当前的应用程序中,“等待 cgStream.CopyToAsync(fileStream);”出现异常 尝试读取 cgStream 时的行。例外是“无法访问已关闭的流”。with null InnerException 另一个应用程序异常是: System.Web.HttpException:远程主机关闭了连接。错误代码为 0x800703E3。在 System.Web.Hosting.IIS7WorkerRequest.RaiseCommunicationError(Int32 结果,布尔 throwOnDisconnect) 在 System.Web.Hosting.IIS7WorkerRequest.ExplicitFlush() 在 System.Web.HttpResponse.Flush(Boolean finalFlush,布尔异步)

平均而言,10 个请求中有 1 个因上述错误而失败。由于它是随机的并且并不总是失败,因此很难解决问题。

上面的代码是在以下网站的帮助下编写的:http ://www.tugberkugurlu.com/archive/efficiently-streaming-large-http-responses-with-httpclient

感谢您提供与此问题相关的任何帮助!

谢谢

4

3 回答 3

8

我在代码中发现了问题:问题是我在“使用”中初始化 HttpClient 对象,并在使用范围之外使用它的响应。这将释放 HttpClient 对象,从而中断远程连接,这就是我无法流式传输内容的原因。随机行为是因为我们不知道对象何时会被释放,有时它不会在流式传输之前被释放,有时它会。

于 2016-10-31T21:40:12.370 回答
0

我会尝试Stream.CopyTo,但只是为了让您知道我之前尝试过以下代码,后来将其更改为CopyToAsync

public async Task<string> GetFilePathAsync(TestModel model)
    {
        string filePath = string.Empty;
        var response = await cgRequestHelper.DownloadAsync(model);  

        if (response.IsSuccessStatusCode)
        {                   
            Stream cgStream = await response.Content.ReadAsStreamAsync();
            filePath = SaveCgStream(cgStream , model.FileName);
        }
        return filePath;
    }

    public string SaveCgStream(Stream cgStream, string fileName)
        {
            if (response == null)
                throw new ArgumentNullException("response");
            if (string.IsNullOrEmpty(fileName))
                throw new ArgumentNullException("fileName");

            const int CHUNK_SIZE = 40000;
            var filePath = _CreateTemporaryLocation(fileName);
            var fileStream = File.Create(filePath, CHUNK_SIZE);

            int bytesRead;
            var buffer = new byte[CHUNK_SIZE];
            bool isReadStarted = false;
            try
            {
                do
                {
                    bytesRead = cgStream.Read(buffer, 0, CHUNK_SIZE);
                    if (bytesRead > 0)
                    {
                        isReadStarted = true;
                        fileStream.Write(buffer, 0, bytesRead);
                    }
                } while (bytesRead > 0);
            }
            catch (Exception e)
            {
                throw e;
            }
            finally
            {
                fileStream.Close();
            }
            return filePath;
        }

我在这bytesRead = cgStream.Read(buffer, 0, CHUNK_SIZE);条线上遇到了同样的错误。你还觉得有CopyToAsync问题吗?我对此表示怀疑,因为当我设置断点时,我可以看到流不可读,因为 Read 属性甚至在进入CopyToAsync方法之前都是错误的。

我尝试CopyToCopyToAsync,但没有帮助。截屏:

在此处输入图像描述

于 2016-10-31T18:49:11.373 回答
0

根据文档,Stream.CopyToAsync是异步的。这意味着它不会阻塞调用者(您的方法),它将继续在 finally 块中处理流。换句话说,你有一个竞争条件。切换到Stream.CopyTo,你应该很高兴。

于 2016-10-31T18:38:14.267 回答