3

I'm currently writing an component where I already have a synchronous method to download files from a server. Here's the signature:

public Stream DownloadFile(IData data)

Now I wanted to have an async version of this method and tried this:

 public async Task<Stream> DownloadFileAsync(IData data)
 {
    Stream stream = null;
    await Task.Run(() =>
    {
      DownloadFile(data);
    });
    return stream;
 }

But resharper is showing me a squiggle line under return stream; "expression is always null". Can somebody tell me what is wrong with my code?

What I want to do is run the DownloadFile method in background and return controlflow to the caller.

EDIT: here is the DownloadFile method:

var ms = new MemoryStream();

  using (var dtService = new DataTransferService(mConnectionInfo))
  {
    int bytesRead;
    do
    {
      var buffer = new byte[data.ChunkSize];
      bytesRead = dtService.Read(data, buffer);

      if (bytesRead == 0)
      {
        break;
      }

      data.Offset += bytesRead;
      ms.Write(buffer, 0, buffer.Length);
    } while (bytesRead > 0);
  }


  return ms;

Thanks

user3292642
  • 711
  • 2
  • 8
  • 32
  • You don't store the stream and return it you only return this: `Stream stream = null;` which is null – EpicKip Nov 15 '17 at 09:49
  • 2
    Possible duplicate of [How to call asynchronous method from synchronous method in C#?](https://stackoverflow.com/questions/9343594/how-to-call-asynchronous-method-from-synchronous-method-in-c) – Liam Nov 15 '17 at 09:51
  • 4
    what your trying to do is the sync over async anti pattern, [don't do this](http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html). the whole point of async is that you should implement it everywhere. – Liam Nov 15 '17 at 09:52
  • `Task.Run(downloadSomething)` probably is a mistake. Post `DownloadFile()` and then we can see if it can be made async. – H H Nov 15 '17 at 10:06
  • @HenkHolterman thanks and check my edit :) – user3292642 Nov 15 '17 at 10:10
  • That doesn't help, I don't know what DataTransferService is. But by the looks of it, forget about making this async. You would only be telling a lie. – H H Nov 15 '17 at 10:38

3 Answers3

4

Best option would be to rewrite the DownloadFile() method using async I/O, for instance with HttpClient.

Making the current DownloadFile() async with a wrapper is pointless.
If you are stuck between a requirement and the given infrastructure then just fake it while doing the least amount of damage:

public Task<Stream> DownloadFileAsync(IData data)  // not 'async', just Task<>
{
    return Task.FromResult(DownloadFile(data));
}
H H
  • 263,252
  • 30
  • 330
  • 514
  • Thanks, I think I got it now. If I were using some .net mechanism to communicate with built in async methods, I could implement my own async method, which will call something like `HttpClient.AnyAsyncMethod`. But in this case the `DataTransferService` will call some proxy to get data from the server, which doesn't expose any async methods. So exposing an async method for me doesn't make any sense, and I will go with your solution and just return a `Task`, right? – user3292642 Nov 15 '17 at 11:38
  • If you really need an async version then yes, wrap it with FromResult(). Also see [Don't Use Task.Run in the Implementation](https://blog.stephencleary.com/2013/11/taskrun-etiquette-examples-dont-use.html) – H H Nov 15 '17 at 11:49
2

Because you return stream variable, and it's null :)

Just return your Task

public async Task<Stream> DownloadFileAsync(IData data)
{
    return await Task.Run(() => DownloadFile(data));
}
Backs
  • 24,430
  • 5
  • 58
  • 85
0

You forgot to actually assign the stream variable:

public async Task<Stream> DownloadFileAsync(IData data)
 {
    Stream stream = null;
    await Task.Run(() =>
    {
      // VVV
      stream = DownloadFile(data);
    });
    return stream;
 }
nvoigt
  • 75,013
  • 26
  • 93
  • 142