I have a method called DownloadFileAsync(url, Func<RemoteFileResponse, Task> onDownloadFinished) which performs the following:
This feels dirty to me as I need to perform the download on a background thread but I can't await it because I want to be able to return the cached file right away. The problem is that I lose any exception context if I do this.
Some options I can think of:
Was wondering if anyone had any other suggestions of how I could do this?
Pseudo code for my method:
Task<IFile> async DownloadFileAsync(url, Func<RemoteFileResponse, Task> onDownloadFinished)
{
var cache = await CheckCacheAsync(url);
// don't await this so the callee can use the cached file right away
// instead return the download result on the download finished callback
DownloadUrlAndUpdateCache(url, onDownloadFinished);
return cache
}
If your cache is an in-memory cache, then it's easier to cache the tasks rather than their results:
ConcurrentDictionary<Url, Task<IFile>> cache = ...;
Task<IFile> DownloadFileAsync(url) // no async keyword
{
return cache.GetOrAdd(url, url => DownloadUrlAsync(url));
}
private async Task<IFile> DownloadUrlAsync(url)
{
... // actual download
}
Logically, the GetOrAdd is doing this (but in a thread-safe and more efficient manner):
if (cache.ContainsKey(url))
return cache[url];
cache[url] = DownloadUrlAsync(url);
return cache[url];
Note, however, that this will cache the complete task, so download exceptions are also cached.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With