Skip to content

Instantly share code, notes, and snippets.

@nelsonprsousa
Last active January 29, 2022 18:19
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nelsonprsousa/2f59be5c93a22e9e2e7c49299e75f45d to your computer and use it in GitHub Desktop.
Save nelsonprsousa/2f59be5c93a22e9e2e7c49299e75f45d to your computer and use it in GitHub Desktop.
Useful to avoid multiple requests to the same Task<T> (e.g. an HTTP GET operation). You probably want to registered the loader as a scoped or singleton service. Bare in mind that GetOrAdd is *not* atomic, although you can use your loader safely since it is thread-safe (usage of Lazy<Task<T>> to avoid multiple operations to resolve Task<T>).
public abstract class BaseLoader<T> : IBaseLoader<T>
where T : class
{
private readonly ConcurrentDictionary<string, Lazy<Task<T?>>> cache = new();
public Task<T?> LoadAsync(string key, Func<Task<T?>> factory)
{
return cache.GetOrAdd(key, (_) => new Lazy<Task<T?>>(factory)).Value;
}
}
public class CategoriesLoader : BaseLoader<Category>, ICategoriesLoader
{
private const string CategoryCacheKey = "Category:{0}";
public Task<Category?> LoadAsync(byte id, CancellationToken cancellationToken)
{
var key = string.Format(CategoryCacheKey, id);
return LoadAsync(key, () => GetCategoryByIdTask());
}
}
public interface IBaseLoader<T>
where T : class
{
Task<T?> LoadAsync(string key, Func<Task<T?>> factory);
}
public interface ICategoriesLoader
{
Task<Category?> LoadAsync(byte id, CancellationToken cancellationToken);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment