How to create a key for Caching

121 Views Asked by At

I have Query Repository

public interface IQueryRepository<T> where T : BaseEntity
{
    Task<IReadOnlyList<TRes>> ListAsync<TRes>(ISpecification<T> spec,
        CancellationToken cancellationToken = default);
    Task<T> FirstOrDefaultAsync(ISpecification<T> spec, CancellationToken cancellationToken = default);
    Task<TRes> FirstOrDefaultAsync<TRes>(ISpecification<T> spec, CancellationToken cancellationToken = default) where TRes : class;
}

I have created a proxy between my client and repository.

public class CachedReadonlyRepositoryProxy<T> : IQueryRepository<T> where T : BaseEntity
{
    private readonly EfReadonlyRepository<T> _repository;
    private readonly ICacheService _cacheService;
    private int? _cachingDuration;
    private readonly ISettingsService _settingsService;
    private readonly bool _isCacheable;

    public CachedReadonlyRepositoryProxy(EfReadonlyRepository<T> repository, ICacheService cacheService, ISettingsService settingsService)
    {
        _repository = repository;
        _cacheService = cacheService;
        _settingsService = settingsService;

        _isCacheable = typeof(T).IsDefined(typeof(CacheableAttribute), false);
    }

    public async Task<T> GetByIdAsync(Guid id, CancellationToken cancellationToken = default)
    {
        if (!_isCacheable)
            return await _repository.GetByIdAsync(id, cancellationToken);

        var key = "";
        var cachedRecord = _cacheService.Get<T>(key);
        if (cachedRecord != null)
            return cachedRecord;

        var result = await _repository.GetByIdAsync(id, cancellationToken);
        _cacheService.Store(key, result, await GetDuration());
        return result;
    }

    public async Task<T> FirstOrDefaultAsync(ISpecification<T> spec, CancellationToken cancellationToken = default)
    {
        if (!_isCacheable)
            return await _repository.FirstOrDefaultAsync(spec, cancellationToken);

        var key = "";
        var cachedRecord = _cacheService.Get<T>(key);
        if (cachedRecord != null)
            return cachedRecord;

        var result = await _repository.FirstOrDefaultAsync(spec, cancellationToken);
        _cacheService.Store(key, result, await GetDuration());
        return result;
    }
}

The problem is that I can't create a unique key for every query. I don't know how to distinguish specifications (Ardalis Specification library). Web API ASP.NET Core 3.1

1

There are 1 best solutions below

3
On

ISpecification<T> has CacheKey property. As per docs to enable caching for your specifications you need call EnableCache when defining specification, for example:

public class CustomerByNameWithStoresSpec : Specification<Customer>, ISingleResultSpecification
{
    public CustomerByNameWithStoresSpec(string name)
    {
        Query.Where(x => x.Name == name)
            .Include(x => x.Stores)
            .EnableCache(nameof(CustomerByNameWithStoresSpec), name);
    }
}

Also note:

Implementing caching will also require infrastructure such as a CachedRepository, an example of which is given in the sample on GitHub. The EnableCache method is used to inform the cache implementation that caching should be used, and to configure the CacheKey based on the arguments supplied.