https://github.com/baune8d/expressioncache
ExpressionCache takes advantage of expressions to generate and maintain cache keys for your application.
https://github.com/baune8d/expressioncache
cache csharp dotnet
Last synced: 6 months ago
JSON representation
ExpressionCache takes advantage of expressions to generate and maintain cache keys for your application.
- Host: GitHub
- URL: https://github.com/baune8d/expressioncache
- Owner: Baune8D
- License: mit
- Created: 2017-07-16T22:03:49.000Z (almost 9 years ago)
- Default Branch: main
- Last Pushed: 2024-12-30T20:34:46.000Z (over 1 year ago)
- Last Synced: 2025-05-04T11:43:43.377Z (about 1 year ago)
- Topics: cache, csharp, dotnet
- Language: C#
- Homepage:
- Size: 195 KB
- Stars: 3
- Watchers: 1
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# ExpressionCache
[](https://ci.appveyor.com/project/Baune8D/expressioncache)
[](https://codecov.io/gh/Baune8D/expressioncache)
| Package | Version |
| ----------------------------|:---------------------------------------------------------------------------------------------------------------------------------------:|
| ExpressionCache.Core | [](https://www.nuget.org/packages/ExpressionCache.Core) |
| ExpressionCache.Distributed | [](https://www.nuget.org/packages/ExpressionCache.Distributed) |
**Dev feed:** [https://www.myget.org/F/baunegaard/api/v3/index.json](https://www.myget.org/F/baunegaard/api/v3/index.json)
## Table of Contents
1. [ExpressionCache.Core](#expressionCache.core)
2. [ExpressionCache.Distributed](#expressionCache.distributed)
## ExpressionCache.Core
### Key generation
The cache key will be a combination of class name, function name and parameter values.
The following code snippet is the heart of the library:
```csharp
public class SampleService
{
private readonly IDistributedCacheService _cacheService;
private readonly SampleRepository _sampleRepository;
public SampleService(IDistributedCacheService cacheService, SampleRepository sampleRepository)
{
_cacheService = cacheService;
_sampleRepository = sampleRepository;
}
public async Task GetAsync(int entityId, CacheAction cacheAction = CacheAction.Invoke)
{
if (cacheAction != CacheAction.Bypass)
{
return await _cacheService.InvokeCacheAsync(
() => GetAsync(entityId, CacheAction.Bypass),
TimeSpan.FromDays(1), cacheAction);
}
return await _sampleRepository.GetAsync(entityId);
}
}
```
**Flow (Without an existing cache entry)**
1. Lets say we call GetAsync(5) on the above snippet.
2. cacheAction is not equal to Bypass, so InvokeCacheAsync gets called.
3. A lookup in cache with generated key \{SampleService}\{GetAsync}\{5}\{Bypass} happens.
4. No cache entry is found so the expression GetAsync(5, CacheAction.Bypass) is invoked.
5. This time the cache is skipped because of Bypass. Result of sampleRepository is returned.
6. The returned value gets cached and InvokeCacheAsync returns.
### CacheAction enum
1. **Invoke** - The default action. Will check for a cached value and return it if found.
2. **Bypass** - Used to bypass the caching entirely. **Note!** Should always be used in the expression to InvokeCache.
3. **Overwrite** - Skip checking for cached value, but still cache new value.
### Object parameters
If complex objects are used as function parameters, ExpressionCache needs a way to know how to build the key value.
By extending **ICacheKey** one can define how to build the key.
```csharp
public class SampleObject : ICacheKey
{
public int Parameter1 { get; set; }
public int Parameter2 { get; set; }
public virtual void BuildCacheKey(ICacheKeyBuilder builder)
{
builder
.By(Parameter1)
.By(Parameter2);
}
}
```
## ExpressionCache.Distributed
ExpressionCache use providers to support different caching engines.
Included in this repository is ExpressionCache.Distributed which works with Microsofts IDistributedCache interface.
### .NET Core Dependency Injection
The library include extensions for IServiceCollection interface.
```csharp
public void ConfigureServices(IServiceCollection services)
{
// Register an IDistributedCache implementation.
services.AddDistributedRedisCache(options =>
{
options.Configuration = "localhost";
options.InstanceName = "Sample";
});
// Register the distributed cache service.
services.AddDistributedExpressionCache();
}
```
You can now inject IDistributedCacheService using DI into you code.
### Full service example
```csharp
public class SampleService
{
private readonly IDistributedCacheService _cacheService;
private readonly SampleRepository _sampleRepository;
public SampleService(IDistributedCacheService cacheService, SampleRepository sampleRepository)
{
_cacheService = cacheService;
_sampleRepository = sampleRepository;
}
public async Task CreateAsync(EntityDto entity)
{
var newId = await _sampleRepository.CreateAsync(entity);
if (newId > 0)
{
// Add new entity to cache.
return await GetAsync(newId, CacheAction.Overwrite) != null;
}
return false;
}
public async Task UpdateAsync(EntityDto entity)
{
if (await _sampleRepository.UpdateAsync(entity))
{
// Overwrite cached entity with updated one.
return await GetAsync(entity.Id, CacheAction.Overwrite) != null;
}
return false;
}
public async Task DeleteAsync(int entityId)
{
if (await _sampleRepository.DeleteAsync(id))
{
// Remove cached entity.
await _cacheService.RemoveAsync(() => GetAsync(entityId, CacheAction.Bypass));
return true;
}
return false;
}
public async Task GetAsync(int entityId, CacheAction cacheAction = CacheAction.Invoke)
{
if (cacheAction != CacheAction.Bypass)
{
// Check for existing cached entity.
return await _cacheService.InvokeCacheAsync(
() => GetAsync(entityId, CacheAction.Bypass),
TimeSpan.FromDays(1), cacheAction);
}
// If not already cached, this result will get cached.
return await _sampleRepository.GetAsync(entityId);
}
}
```
### Interface members
The full interface of IDistributedCacheService.
```csharp
public interface IExpressionCacheBase
{
string GetKey(Expression> expression);
string GetKey(Expression>> expression);
TResult InvokeCache(Expression> expression, TimeSpan expiry, CacheAction cacheAction);
Task InvokeCacheAsync(Expression>> expression, TimeSpan expiry, CacheAction cacheAction);
}
public interface IDistributedCacheService : IExpressionCacheBase
{
void Remove(Expression> expression);
void Remove(Expression>> expression);
Task RemoveAsync(Expression> expression);
Task RemoveAsync(Expression>> expression);
bool Exists(Expression> expression);
bool Exists(Expression>> expression);
Task ExistsAsync(Expression> expression);
Task ExistsAsync(Expression>> expression);
TResult Get(Expression> expression);
TResult Get(Expression>> expression);
Task GetAsync(Expression> expression);
Task GetAsync(Expression>> expression);
Task> GetManyAsync(IEnumerable>> expressions);
Task> GetManyAsync(IEnumerable>>> expressions);
void Set(Expression> expression, TValue value, TimeSpan expiry);
void Set(Expression>> expression, TValue value, TimeSpan expiry);
Task SetAsync(Expression> expression, TValue value, TimeSpan expiry);
Task SetAsync(Expression>> expression, TValue value, TimeSpan expiry);
}
```