I would like to cache some responses from CommandsHandlers.
I Already did this using IPipelineBehaviour, but only 5% of my requests really must have cache, and the other 95% must skip this Pipeline. Is there a way to do that?
Below follows my code.
Thanks!
public class PipelineBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : IRequest<TResponse>, IProvideCacheKey
{
private readonly IMemoryCache _cache;
public PipelineBehavior(IMemoryCache cache)
{
_cache = cache;
}
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken,
RequestHandlerDelegate<TResponse> next)
{
// Check in cache if we already have what we're looking for
var cacheKey = request.CacheKey;
if (_cache.TryGetValue<TResponse>(cacheKey, out var cachedResponse))
{
return cachedResponse;
}
// If we don't, execute the rest of the pipeline, and add the result to the cache
var response = await next();
_cache.Set(cacheKey, response);
return response;
}
}
public class GetUserByEmailCommand : Command, IRequest<bool>, IProvideCacheKey
{
public string Email { get; set; }
public string CacheKey => $"{GetType().Name}:{Email}";
public override bool IsValid()
{
ValidationResult = new GetUserByEmailCommandValidation<GetUserByEmailCommand>().Validate(this);
return ValidationResult.IsValid;
}
}
public interface IProvideCacheKey
{
string CacheKey { get; }
}
You can wrap your caching behavior in a check that is bypassed if the request is not cacheable to let the pipeline continue. In your case, you can probably just check if the request implements your interface at the start of the Handle method:
if (request is IProvideCacheKey)
{
// perform cache behavior, return if cached and terminate the pipeline
}
// else continue the pipeline
There's a couple good examples of this in more detail at:
https://lurumad.github.io/cross-cutting-concerns-in-asp-net-core-with-meaditr
https://anderly.com/2019/12/12/cross-cutting-concerns-with-mediatr-pipeline-behaviors/