using System.Diagnostics;
using System.Threading.Tasks;
using System.Collections.Concurrent;
var keys = new string[] { "a", "b", "error", "b", "a" };
foreach (var key in keys)
var sw = new Stopwatch();
var ret = await GetFromCacheOrDbAsync(key);
Console.WriteLine($"result: {ret}, in {sw.Elapsed}");
Console.WriteLine($"exception: {ex.Message}, in {sw.Elapsed}");
static ConcurrentDictionary<string, string> cache = new ConcurrentDictionary<string, string>();
static Task<string> GetFromCacheOrDbAsync(string key)
if (cache.TryGetValue(key, out string value))
return Task.FromResult(value);
return GetFromDbAsync(key).ContinueWith((task) =>
task.Exception?.Flatten().Handle(ex => throw ex);
cache.TryAdd(key, task.Result);
static async Task<string> GetFromDbAsync(string key)
throw new Exception(key);