In this article, you'll learn how to use the Task.FromResult method to retrieve the results of asynchronous download operations that are held in a cache. The FromResult method returns a finished Task<TResult> object that holds the provided value as its Result property. This method is useful when you perform an asynchronous operation that returns a Task<TResult> object, and the result of that Task<TResult> object is already computed.

## Example

The following example downloads strings from the web. It defines the DownloadStringAsync method. This method downloads strings from the web asynchronously. This example also uses a ConcurrentDictionary<TKey,TValue> object to cache the results of previous operations. If the input address is held in this cache, DownloadStringAsync uses the FromResult method to produce a Task<TResult> object that holds the content at that address. Otherwise, DownloadStringAsync downloads the file from the web and adds the result to the cache.

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;

{
private static readonly HttpClient s_httpClient = new();

{
{
}

{

return content;
});
}

{
string[] urls = new[]
{
"https://docs.microsoft.com/aspnet/core",
"https://docs.microsoft.com/dotnet",
"https://docs.microsoft.com/dotnet/architecture/dapr-for-net-developers",
"https://docs.microsoft.com/dotnet/azure",
"https://docs.microsoft.com/dotnet/desktop/wpf",
"https://docs.microsoft.com/dotnet/devops/create-dotnet-github-action",
"https://docs.microsoft.com/dotnet/machine-learning",
"https://docs.microsoft.com/xamarin",
"https://dotnet.microsoft.com/",
"https://www.microsoft.com"
};

Stopwatch stopwatch = Stopwatch.StartNew();

static void StopAndLogElapsedTime(
{
stopwatch.Stop();

long elapsedMs = stopwatch.ElapsedMilliseconds;

Console.WriteLine(
$"Attempt number: {attemptNumber}\n" +$"Retrieved characters: {charCount:#,0}\n" +
$"Elapsed retrieval time: {elapsedMs:#,0} milliseconds.\n"); } await Task.WhenAll(downloads).ContinueWith( downloadTasks => StopAndLogElapsedTime(1, stopwatch, downloadTasks)); // Perform the same operation a second time. The time required // should be shorter because the results are held in the cache. stopwatch.Restart(); downloads = urls.Select(DownloadStringAsync); await Task.WhenAll(downloads).ContinueWith( downloadTasks => StopAndLogElapsedTime(2, stopwatch, downloadTasks)); } // Sample output: // Attempt number: 1 // Retrieved characters: 754,585 // Elapsed retrieval time: 2,857 milliseconds. // Attempt number: 2 // Retrieved characters: 754,585 // Elapsed retrieval time: 1 milliseconds. }  Imports System.Collections.Concurrent Imports System.Net.Http Module Snippets Class DownloadCache Private Shared ReadOnly s_cachedDownloads As ConcurrentDictionary(Of String, String) = New ConcurrentDictionary(Of String, String)() Private Shared ReadOnly s_httpClient As HttpClient = New HttpClient() Public Function DownloadStringAsync(address As String) As Task(Of String) Dim content As String = Nothing If s_cachedDownloads.TryGetValue(address, content) Then Return Task.FromResult(Of String)(content) End If Return Task.Run( Async Function() content = Await s_httpClient.GetStringAsync(address) s_cachedDownloads.TryAdd(address, content) Return content End Function) End Function End Class Public Sub StopAndLogElapsedTime( attemptNumber As Integer, stopwatch As Stopwatch, downloadTasks As Task(Of String())) stopwatch.Stop() Dim charCount As Integer = downloadTasks.Result.Sum(Function(result) result.Length) Dim elapsedMs As Long = stopwatch.ElapsedMilliseconds Console.WriteLine($"Attempt number: {attemptNumber}{vbCrLf}" &
$"Retrieved characters: {charCount:#,0}{vbCrLf}" &$"Elapsed retrieval time: {elapsedMs:#,0} milliseconds.{vbCrLf}")
End Sub

Sub Main()
Dim urls As String() = {
"https://docs.microsoft.com/aspnet/core",
"https://docs.microsoft.com/dotnet",
"https://docs.microsoft.com/dotnet/architecture/dapr-for-net-developers",
"https://docs.microsoft.com/dotnet/azure",
"https://docs.microsoft.com/dotnet/desktop/wpf",
"https://docs.microsoft.com/dotnet/devops/create-dotnet-github-action",
"https://docs.microsoft.com/dotnet/machine-learning",
"https://docs.microsoft.com/xamarin",
"https://dotnet.microsoft.com/",
"https://www.microsoft.com"
}
Dim stopwatch As Stopwatch = Stopwatch.StartNew()
End Sub).Wait()

stopwatch.Restart()
End Sub).Wait()
End Sub
' Sample output:
'     Attempt number 1
'     Retrieved characters: 754,585
'     Elapsed retrieval time: 2,857 milliseconds.
'
'     Attempt number 2
'     Retrieved characters: 754,585
'     Elapsed retrieval time: 1 milliseconds.
End Module


In the preceding example, the first time each url is downloaded, its value is stored in the cache. The FromResult method enables the DownloadStringAsync method to create Task<TResult> objects that hold these pre-computed results. Subsequent calls to download the string return the cached values, and is much faster.