Client side data portal cache (example) #3645
Replies: 2 comments 7 replies
-
Thank you for sharing this. I'd like to make sure @mtavares628 sees this thread as well, because he was instrumental in what's been added to CSLA 8 this far. I think that this implementation and what we've added to CSLA 8 should be compatible, or very close? Specifically, you have a way to determine whether a type is cacheable, and also a cache. And you have a decorator for the client-side data portal to check the cache as appropriate. In the CSLA 8 change, the client-side data portal always invokes a check for a cacheable type, and if it is cacheable then it invokes the cache to get the result. For example, in the fetch operation: csla/Source/Csla/DataPortalT.cs Line 245 in dd16fda The differences I see are that the current CSLA implementation doesn't provide access to the isSync value to the cache. Is that important? If so, why? Also, the current CSLA implementation asks you basically to cache (or at least return) a |
Beta Was this translation helpful? Give feedback.
-
@mtavares628 I changed our implementation based on your comment. Now it locks based on the generated private async Task<DataPortalResult> GetOrCreate(CacheKey cacheKey, Func<Task<DataPortalResult>> getFunc)
{
if (_memoryCache.TryGetValue(cacheKey, out DataPortalResult? value))
{
return value!;
}
var semaphore = _synchronizationLocks.AddOrUpdate(cacheKey, _ => new SemaphoreSlim(1), (_, x) => x);
await semaphore.WaitAsync();
try
{
return (await _memoryCache.GetOrCreateAsync(cacheKey, _ =>
{
LogCacheMiss(cacheKey.Type);
return getFunc();
}))!;
}
finally
{
semaphore.Release();
}
} |
Beta Was this translation helpful? Give feedback.
-
@rockfordlhotka As discussed here our current implementation.
First all necessary code and afterwards some brief explanations.
The caching interface + criteria marker interface
The main interface
IOurDataPortalCache
only provides the single method to move every logic related to caching (e.g. locking, checking etc.) into the actual implementation to not leak any details into the decorator.The
IHasCacheableKey
is used in criterias to differentiate between multiple result lists of one type. For exampleLookupROList
has a discriminator which identifies disjunct sets of the type. So with the interface you can cache those different results. A simple example would beWith this you can cache values for all discriminators without polluting/corrupting other values of this type. Drawback: You need more memory. Total would be Count of Discriminators + 1 (whole list).
The options to define which types should be cached
Defines the types which should be cached when used during a fetch.
Our in-memory implementation with
IMemoryCache
The decorator to forward calls to our cache
Not much to do here. Route all calls (except Fetch) to the decorated instance. Send the Fetch call through our cache.
The sync warning is to find Fetch() issues (sync deadlocks in our case) and resolve them.
DI registration extension
Register all necessary services so the cache decorator can do it's work.
Registration in app
Configure the app and which types should be cached.
Beta Was this translation helpful? Give feedback.
All reactions