Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/305.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 异步Base64下载流到文件_C#_Asynchronous_Stream_Webclient Download - Fatal编程技术网

C# 异步Base64下载流到文件

C# 异步Base64下载流到文件,c#,asynchronous,stream,webclient-download,C#,Asynchronous,Stream,Webclient Download,我正在尝试开发一个.NET应用程序,它将与一个.NET核心服务器应用程序(我没有开发)通信。主要目标是下载一个文件。因为客户端应用程序将有一个WPF gui,所以整个下载应该异步进行 通过阅读服务器应用程序的API,我知道请求的响应是一个包含文件内容的Base64编码字符串 我想做的是异步发送一个请求,获取它的响应流,从该流异步读取一个字符,base64解码,异步写入文件(见下面的代码) 但是Convert.FromBase64CharArray通常会出现异常而失败 base-64字符数组或字符

我正在尝试开发一个.NET应用程序,它将与一个.NET核心服务器应用程序(我没有开发)通信。主要目标是下载一个文件。因为客户端应用程序将有一个WPF gui,所以整个下载应该异步进行

通过阅读服务器应用程序的API,我知道请求的响应是一个包含文件内容的Base64编码字符串

我想做的是异步发送一个请求,获取它的响应流,从该流异步读取一个字符,base64解码,异步写入文件(见下面的代码)

但是Convert.FromBase64CharArray通常会出现异常而失败

base-64字符数组或字符串的长度无效

有时,此操作会成功,但下载过早结束(downloadedLength 看起来,好像连接关闭得太早了,但我不完全确定这是不是真的

到目前为止,我试图解决的问题是:

  • 使用streamReader.ReadToEndAsync()对完整字符串进行解码,async write:worked,但下载115MB时使用了大约600MB的RAM
  • 使{read,decode,write}块异步,而不是异步读取,解码,异步写入:无改进
  • 完全没有异步:有时会失败,但不像异步版本那样频繁
  • 使用FromBase64Transform::TransformBlock而不是Convert。FromBase64CharArray:未在合理的时间内完成下载,因为inputBlockSize设置为fix 1字节(下载约115MB)
  • 通过SSH隧道进行通信以忽略Apache服务器:下载甚至没有启动
  • 让客户机和服务器在同一台机器上运行:似乎工作正常
一些规格:

  • 客户端:Windows 7 x64、.NET 4.6.1
  • 服务器:Ubuntu 16.04、Apache 2.4、.NET Core 2.1.4
最后:代码

请求文件的函数:

private async Task<WebResponse> DoGetRequestAsync(string requestString)
{
    var completeRequestUrl = $"{_options.StoreUrl}/api/{requestString}";

    try
    {
        RequestStarted?.Invoke(true);

        var request = (HttpWebRequest)WebRequest.Create(completeRequestUrl);

        request.ContentType = "text/plain";
        request.Method = "GET";
        var response = await request.GetResponseAsync();

        RequestFinished?.Invoke(true);

        return response;
    }
    catch (Exception e)
    {
        Console.WriteLine($"ERROR: {e.Message}");
    }

    return null;
}
专用异步任务DoGetRequestAsync(字符串请求字符串)
{
var completeRequestUrl=$“{u options.StoreUrl}/api/{requestString}”;
尝试
{
RequestStarted?.Invoke(true);
var-request=(HttpWebRequest)WebRequest.Create(completeRequestUrl);
request.ContentType=“text/plain”;
request.Method=“GET”;
var response=wait request.GetResponseAsync();
RequestFinished?.Invoke(true);
返回响应;
}
捕获(例外e)
{
WriteLine($“错误:{e.Message}”);
}
返回null;
}
处理响应的函数:

public async Task<string> DownloadPackage(string vendor, string package)
{
    // declaring some vars

    using (var response = await DoGetRequestAsync(requestString))
    {
        var totalLength = response.ContentLength;
        var downloadedLength = 0;
        var charBuffer = new char[4 * 1024];

        try
        {
            using (var stream = response.GetResponseStream())
            {
                if (stream != null)
                {
                    using (var reader = new StreamReader(stream))
                    using (var fStream = File.Create(filename))
                    {
                        while (!reader.EndOfStream)
                        {
                            var readBytes = await reader.ReadAsync(charBuffer, 0, charBuffer.Length);
                            var decoded = Convert.FromBase64CharArray(charBuffer, 0, readBytes);

                            await fStream.WriteAsync(decoded, 0, decoded.Length);

                            downloadedLength += readBytes;
                            DownloadProgress?.Invoke((float)downloadedLength / totalLength * 100.0f);
                        }
                    }
                }
            }

            if (downloadedLength < totalLength)
            {
                throw new Exception($"Download failed due to a network error. Downloaded {downloadedLength} Bytes.");
            }

            // some follow-up stuff

            return filename;
        }
        catch (Exception e)
        {
            Console.WriteLine("Error!");
            Console.WriteLine(e.Message);
            throw;
        }
    }
}
公共异步任务下载包(字符串供应商,字符串包)
{
//申报一些VAR
使用(var响应=等待DoGetRequestAsync(请求字符串))
{
var totalLength=响应.ContentLength;
var downloadedLength=0;
var charBuffer=新字符[4*1024];
尝试
{
使用(var stream=response.GetResponseStream())
{
if(流!=null)
{
使用(变量读取器=新的流读取器(流))
使用(var fStream=File.Create(文件名))
{
而(!reader.EndOfStream)
{
var readBytes=await reader.ReadAsync(charBuffer,0,charBuffer.Length);
var decoded=Convert.FromBase64CharArray(charBuffer,0,readBytes);
等待fStream.WriteAsync(已解码,0,已解码.长度);
downloadedLength+=readBytes;
下载进度?.Invoke((浮动)下载长度/总长度*100.0f);
}
}
}
}
if(下载长度<总长度)
{
抛出新异常($“由于网络错误,下载失败。已下载{downloadedLength}字节。”);
}
//一些后续的东西
返回文件名;
}
捕获(例外e)
{
控制台。WriteLine(“错误!”);
控制台写入线(e.Message);
投掷;
}
}
}
你知道是什么导致了这个错误吗

编辑:

好的,我试着实施费尔多提出的解决方案。因为我没有删除辅助缓冲区的解码内容,所以现在需要更多内存来执行下载。但是我可以省略StreamReader,直接从流中读取。这导致了另一个例外:

无法从传输连接读取数据:连接已关闭


无论是同步还是同步。似乎是我第一次怀疑的证据。但我仍然不知道如何解决这个问题。

与问题无关:我不会将任务异步和事件混合使用。要报告进度,请使用其他工具(如curl)尝试下载是否一致成功?也许是你的网络在某个地方有一些脆弱的连接?服务器在下载或类似的东西时也不会达到100%的CPU吗?@Fildor:只是尝试了wget for Windows。下载成功了好几次。服务器显示大约12%的CPU使用率。网络和服务器似乎是一个有趣的想法。我要试试看。advanceAn API中仅支持将文件生成为base 64编码字符串的Thx被破坏。与开发人员讨论支持本机二进制下载的问题,这对你们两人来说都应该是比较少的工作。