title: Asynchronous Base64 downloadstream to file
body: <p>I'm trying to develop a .NET app which will communicate with a .NET Core Server app (which I did not develop). The main goal is to download a file. Since the client app will have a WPF gui, the whole download should happen asynchronously.</p>
  
  <p>From reading the server app's API I know, that the repsonse to my request is a Base64-encoded String containing the contents of a file.</p>
  
  <p>What I wanted to do, is to async send a request, take its response-stream, async read from that stream to a charArray, base64-decode, async write to file (see code below).</p>
  
  <p>But Convert.FromBase64CharArray most often fails with an exception</p>
  
  <blockquote>
    <p>invalid length for a base-64 char array or string</p>
  </blockquote>
  
  <p>Occasionally this one succeeds but the download ends prematurely (downloadedLength &lt; totalLength)</p>
  
  <p>It seems, as if the connection was closed too early, but I'm not entirly sure whether that's true. </p>
  
  <p>What I tried to resolve this issue so far:</p>
  
  <ul>
  <li>Using streamReader.ReadToEndAsync(), decode the complete string, async write: worked, but to download 115MB around 600MB RAM were used</li>
  <li>Make the block of { read, decode, write } async instead of async read, decode, async write: no improvement</li>
  <li>No async at all: fails sometimes, but not as often as the async version</li>
  <li>Use FromBase64Transform::TransformBlock instead of Convert.FromBase64CharArray: didn't finish the download in reasonable time, since inputBlockSize is set fix to 1Byte (Downloading about 115MB)</li>
  <li>Communicating through an SSH tunnel to omit the Apache Server: Download didn't even start</li>
  <li>Having client and server running on the same machine: seemed to work fine</li>
  </ul>
  
  <p>Some specs:</p>
  
  <ul>
  <li>Client: Windows 7 x64, .NET 4.6.1</li>
  <li>Server: Ubuntu 16.04, Apache 2.4, .NET Core 2.1.4</li>
  </ul>
  
  <p>And finally: the Code</p>
  
  <p>The function that requests the file:</p>
  
  <pre><code>private async Task&lt;WebResponse&gt; 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;
  }
  </code></pre>
  
  <p>The function that handles the reponse:</p>
  
  <pre><code>public async Task&lt;string&gt; 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 &lt; 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;
          }
      }
  }
  </code></pre>
  
  <p>Any ideas what could cause the error?</p>
  
  <p><strong>EDIT:</strong></p>
  
  <p>Ok, I tried to implement the solution Fildor proposed. Since I do not delete the decoded contents of the secondary buffer, more memory is needed now to perform the download. But I could omit the StreamReader and read from the Stream directly. This lead to another exception:</p>
  
  <blockquote>
    <p>Unable to read data from the transport connection: The connection was closed</p>
  </blockquote>
  
  <p>No matter whether synchronously or asnychronously. Seems to be a proof for my first suspicion. But still I don't know how to solve this problem.</p>