How to search redis key in the structure using OOP,Solid,EF code-first,Cross Cutting Concerns with AOP approaach in .net core?

I will give an example that explain the situation. That example may be messy. Let’s think about Microsoft’s Northwind database example. I have Products table. It has columns like ProductName, SupplierId, CategoryId, QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, Reorder Level, Discontinued. I want to keep it in redis like PRODUCT~SUPPLIERID~CATEGORYID~PRODUCTNAME as key and other columns data as value in the same pattern like 'QuantityPerUnit~UnitPrice....'. And let’s say at .net core side, I have two methods to get a product like GetProductByCategoryId(int categoryId,string productName) and GetProductBySupplierId(int supplierId,string procductName) to get a product . In redis, I will search them like KEYS~*~1~Northwoods Cranberry Sauce to get by categoryId, and KEYS~1~*~Northwoods Cranberry Sauce to get by supplierId. In my structure, I will cache a product twice becuase of the code I have,but I don’t want to make it happen. How can I store just one product and search them ?

I got codes from udemy lecture.

This is my interface:

using System; using System.Collections.Generic; using System.Text;  namespace Core.CrossCuttingConcerns.Caching {     public interface ICacheManager     {         T Get<T>(string key);         object Get(string key);         void Add(string key, object data, int duration);         bool IsAdd(string key);         void Remove(string key);         void RemoveByPattern(string pattern);     } }   

This is ImemoryCache

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; using Core.Utilities.IoC; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection;  namespace Core.CrossCuttingConcerns.Caching.Microsoft {     public class MemoryCacheManager : ICacheManager     {         private IMemoryCache _cache;         public MemoryCacheManager()         {             _cache = ServiceTool.ServiceProvider.GetService<IMemoryCache>();         }         public T Get<T>(string key)         {             return _cache.Get<T>(key);         }          public object Get(string key)         {             return _cache.Get(key);         }          public void Add(string key, object data, int duration)         {             _cache.Set(key, data, TimeSpan.FromMinutes(duration));         }          public bool IsAdd(string key)         {             return _cache.TryGetValue(key, out _);         }          public void Remove(string key)         {             _cache.Remove(key);         }          public void RemoveByPattern(string pattern)         {             var cacheEntriesCollectionDefinition = typeof(MemoryCache).GetProperty("EntriesCollection", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);             var cacheEntriesCollection = cacheEntriesCollectionDefinition.GetValue(_cache) as dynamic;             List<ICacheEntry> cacheCollectionValues = new List<ICacheEntry>();              foreach (var cacheItem in cacheEntriesCollection)             {                 ICacheEntry cacheItemValue = cacheItem.GetType().GetProperty("Value").GetValue(cacheItem, null);                 cacheCollectionValues.Add(cacheItemValue);             }              var regex = new Regex(pattern, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase);             var keysToRemove = cacheCollectionValues.Where(d => regex.IsMatch(d.Key.ToString())).Select(d => d.Key).ToList();              foreach (var key in keysToRemove)             {                 _cache.Remove(key);             }         }     } }  

This is IDisributedCache that has only GetString and SetString no method for searching. I didn’t make it work as well.

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; using Core.Utilities.IoC; using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.DependencyInjection;  namespace Core.CrossCuttingConcerns.Caching.Redis {     public class DistributedCacheManager : ICacheManager     {         private readonly IDistributedCache _cache;         public DistributedCacheManager()         {             _cache = ServiceTool.ServiceProvider.GetService<IDistributedCache>();         }         public T Get<T>(string key)         {             return _cache.Get<T>(key);         }          public object Get(string key)         {             return _cache.Get(key);         }          public void Add(string key, object data, int duration)         {             _cache.Set(key, data, TimeSpan.FromMinutes(duration));         }          public bool IsAdd(string key)         {             return _cache.(key, out _);         }          public void Remove(string key)         {             _cache.Remove(key);         }          public void RemoveByPattern(string pattern)         {             var cacheEntriesCollectionDefinition = typeof(MemoryCache).GetProperty("EntriesCollection", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);             var cacheEntriesCollection = cacheEntriesCollectionDefinition.GetValue(_cache) as dynamic;             List<ICacheEntry> cacheCollectionValues = new List<ICacheEntry>();              foreach (var cacheItem in cacheEntriesCollection)             {                 ICacheEntry cacheItemValue = cacheItem.GetType().GetProperty("Value").GetValue(cacheItem, null);                 cacheCollectionValues.Add(cacheItemValue);             }              var regex = new Regex(pattern, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase);             var keysToRemove = cacheCollectionValues.Where(d => regex.IsMatch(d.Key.ToString())).Select(d => d.Key).ToList();              foreach (var key in keysToRemove)             {                 _cache.Remove(key);             }         }     } }  

This is Module where i configure.

using System; using System.Collections.Generic; using System.Diagnostics; using System.Text; using Core.CrossCuttingConcerns.Caching; using Core.CrossCuttingConcerns.Caching.Redis; //using Core.CrossCuttingConcerns.Caching.Microsoft; using Core.Utilities.IoC; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection;  namespace Core.DependencyResolvers {     public class CoreModule : ICoreModule     {         public void Load(IServiceCollection services)         {             services.AddMemoryCache();             services.AddStackExchangeRedisCache(option =>             {                 option.Configuration ="localhost:6379"                 option.InstanceName = "master";             });             services.AddSingleton<ICacheManager, DistributedCacheManager>();             services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();             services.AddSingleton<Stopwatch>();         }     } }  

This is add cache aspect

using System; using System.Collections.Generic; using System.Linq; using System.Text; using Castle.DynamicProxy; using Core.CrossCuttingConcerns.Caching; using Core.Utilities.Interceptors; using Core.Utilities.IoC; using Microsoft.Extensions.DependencyInjection;  namespace Core.Aspects.Autofac.Caching {     public class CacheAspect : MethodInterception     {         private int _duration;         private ICacheManager _cacheManager;          public CacheAspect(int duration = 60)         {             _duration = duration;             _cacheManager = ServiceTool.ServiceProvider.GetService<ICacheManager>();         }          public override void Intercept(IInvocation invocation)         {             var methodName = string.Format($"{invocation.Method.ReflectedType.FullName}.{invocation.Method.Name}");             var arguments = invocation.Arguments.ToList();             var key = $"{methodName}({string.Join(",", arguments.Select(x => x?.ToString() ?? "<Null>"))})";             if (_cacheManager.IsAdd(key))             {                 invocation.ReturnValue = _cacheManager.Get(key);                 return;             }             invocation.Proceed();             _cacheManager.Add(key, invocation.ReturnValue, _duration);         }     } }  

This is remove cache aspect

using System; using System.Collections.Generic; using System.Text; using Castle.DynamicProxy; using Core.CrossCuttingConcerns.Caching; using Core.Utilities.Interceptors; using Core.Utilities.IoC; using Microsoft.Extensions.DependencyInjection;  namespace Core.Aspects.Autofac.Caching {     public class CacheRemoveAspect : MethodInterception     {         private string _pattern;         private ICacheManager _cacheManager;          public CacheRemoveAspect(string pattern)         {             _pattern = pattern;             _cacheManager = ServiceTool.ServiceProvider.GetService<ICacheManager>();         }          protected override void OnSuccess(IInvocation invocation)         {             _cacheManager.RemoveByPattern(_pattern);         }     } }  

I want to make code clean like this for redis caching I want to use like this, but it caches by getting this method’s name and its parameters as key to cache it. if I do that I will cache a product twice. but I want to make it once and search in them.

        [CacheAspect(duration: 10)]         public IDataResult<List<Product>> GetListByCategory(int categoryId)         {             return new SuccessDataResult<List<Product>>(_productDal.GetList(p => p.CategoryId == categoryId).ToList());         }  
Add Comment
0 Answer(s)

Your Answer

By posting your answer, you agree to the privacy policy and terms of service.