A library for easy and convenient use of distributed caching.
Here you can find a demonstration of how to use CacheQ in your code by following these simple steps in CQRS pattern using MediatR (personally prefer)
Required Packages:
Provider Packages:
public class EvenNumbersCountQuery : IRequest<int>
{
public int StartRange { get; set; }
public int EndRange { get; set; }
}
class EvenNumbersCountQueryHandler : IRequestHandler<EvenNumbersCountQuery, int>
{
public Task<int> Handle(EvenNumbersCountQuery request, CancellationToken cancellationToken)
{
int count = 0;
for (int i = request.StartRange; i < request.EndRange; i++)
{
if (i % 2 == 0)
{
count++;
}
}
return Task.FromResult(count);
}
}
In this step, you can define the cache policy by setting the ExpirationLevel and Key.
class EvenNumbersCountQueryCachePolicy : ICachePolicy<EvenNumbersCountQuery>
{
public CacheLevel ExpirationLevel => CacheLevel.Regular;
public string Key(EvenNumbersCountQuery query)
{
return query.StartRange + "," + query.EndRange;
}
}
In this example, the use of MediatR is a must; however, it might not be necessary to use MediatR. In other words, CacheQ is not dependent on MediatR.
internal class QueryCachingBehavior<TRequest, TResult> : IPipelineBehavior<TRequest, TResult>
where TRequest : IRequest<TResult>
{
private readonly ICachePolicy<TRequest> _cachePolicy;
private readonly ICacheManager _cacheManager;
public QueryCachingBehavior(
IEnumerable<ICachePolicy<TRequest>> cachePolicy,
ICacheManager cacheManager)
{
_cachePolicy = cachePolicy.SingleOrDefault();
_cacheManager = cacheManager;
}
public async Task<TResult> Handle(TRequest request,
CancellationToken cancellationToken,
RequestHandlerDelegate<TResult> next)
{
if (_cachePolicy is null)
{
return await next();
}
return await ReadOrUpdateCache(request, next);
}
private async Task<TResult> ReadOrUpdateCache(TRequest request, RequestHandlerDelegate<TResult> next)
{
if (_cacheManager.TryGetValue(
_cachePolicy,
request,
out TResult cachedResult))
{
return await Task.FromResult(cachedResult);
}
// Read From Handler
TResult result = await next();
// Update Cache
_cacheManager.SetItem(_cachePolicy, request, result);
return result;
}
}
services.AddMediatR(queriesAssembly);
services.AddCacheQ(queriesAssembly,
options =>
{
options.UseDistributedMemoryCache();
});
services.AddScoped(typeof(IPipelineBehavior<,>), typeof(QueryCachingBehavior<,>));
{
"Logging": {
"LogLevel": {
"Default": "Information"
}
},
"AllowedHosts": "*",
"CacheQ": {
"veryShort": "00:00:10",
"short": "00:00:30",
"regular": "00:01:00",
"long": "00:05:00",
"veryLong": "00:30:00"
}
}
Based on your need, you can configure the cache provider in this step. The CacheQ providers use Microsoft.Extensions.Caching internal providers.
services.AddCacheQ(assembly,
options =>
{
options.UseDistributedMemoryCache(memoryCacheOptions =>
{
memoryCacheOptions.SizeLimit = 1024;
// ...
});
});
services.AddCacheQ(assembly,
options =>
{
options.UseStackExchangeRedisCache(redisOptions =>
{
redisOptions.Configuration = "...";
// ...
});
});
services.AddCacheQ(assembly,
options =>
{
options.UseDistributedSqlServerCache(sqlOptions =>
{
sqlOptions.ConnectionString = "...";
sqlOptions.SchemaName = "";
sqlOptions.TableName = "";
// ...
});
});
services.AddCacheQ(assembly,
options =>
{
options.UseNCacheDistributedCache(nCacheOptions =>
{
nCacheOptions.CacheName = "democache";
nCacheOptions.EnableLogs = true;
nCacheOptions.ExceptionsEnabled = true;
});
});
Consider these Queries: EvenNumbersCountQuery and OddNumbersCountQuery. Key in CachePolicy for them would be the same for a specific range(start, end) so it's needed to distinguish cache values base on Query Type (or even Query assembly) it's customizable based on your need (recommended as the default prefix key is quite large!)
this is the default implementation of PrefixKey:
builder.UsePrefixKey(type =>
{
return type.Assembly.GetName().Name + "," + type.FullName;
});
As you might have done it multiple times in other programs, Logging could be simply customized
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"CacheQ": "Information"
}
},
"AllowedHosts": "*",
"CacheQ": {
"veryShort": "00:00:10",
"short": "00:00:30",
"regular": "00:01:00",
"long": "00:05:00",
"veryLong": "00:30:00"
}
}