I have asp.net core 3.1 web api project which leverages Azure SQL database as its data storage option. At present I am also using Azure Redis Cache to improve performance of the application.
Here goes the code details :
ICacheProvider.cs:
public interface ICacheProvider
{
IList<string> GetKeys();
IList<string> GetKeys(string strGroup);
T Get<T>(string strKey, string strGroup = "");
bool Set(string strKey, object objData, string strGroup = "", int? intMinutes = null);
bool Remove(string strKey, string strGroup = "");
bool RemoveGroup(string strGroup);
bool ClearCache();
Task<bool> ClearCacheAsync();
}
CacheProvider.cs
public class CacheProvider : ICacheProvider
{
private static readonly int ExpiryMinutes = ConfigManager.Get(CacheExpiryMinutes, CacheExpiryMinutes);
private static Lazy<ConnectionMultiplexer> _objCacheConn = CreateConnection();
private static Lazy<ConnectionMultiplexer> CreateConnection()
{
return new Lazy<ConnectionMultiplexer>(() =>
{
string conn = ConfigManager.Get(RedisConnString);
return ConnectionMultiplexer.Connect(conn);
});
}
private ConnectionMultiplexer Connection
{
get
{
return _objCacheConn.Value;
}
}
private IDatabase GetDatabase()
{
return Connection.GetDatabase();
}
private EndPoint[] GetEndPoints()
{
return Connection.GetEndPoints();
}
private IServer GetServer()
{
var objEndpoint = GetEndPoints().First();
return Connection.GetServer(objEndpoint);
}
public IList<string> GetKeys()
{
return GetKeys("*");
}
public IList<string> GetKeys(string strGroup)
{
var lstKeys = new List<string>();
try
{
var objServer = GetServer();
if (objServer != null)
{
var strPattern = strGroup + ":*";
var objRedisKeys = objServer.Keys(pattern: strPattern);
var objLst = objRedisKeys.GetEnumerator();
while (objLst.MoveNext())
{
lstKeys.Add(objLst.Current.ToString());
}
}
}
catch (Exception)
{
lstKeys = new List<string>();
}
return lstKeys;
}
public T Get<T>(string strKey, string strGroup = "")
{
T objData = default(T);
try
{
var objCache = GetDatabase();
if (!strKey.IsEmpty() && objCache != null)
{
strKey = (strGroup.IsEmpty() ? C.CacheGroups.General : strGroup) + ":" + strKey;
var strData = objCache.StringGet(strKey).ToString();
if (!strData.IsEmpty())
{
objData = JsonConvert.DeserializeObject<T>(strData);
}
}
}
catch (Exception)
{
objData = default(T);
}
return objData;
}
public bool Set(string strKey, object objData, string strGroup = "", int? intMinutes = null)
{
bool blnSuccess = false;
try
{
var objCache = GetDatabase();
if (!strKey.IsEmpty() && objData != null && objCache != null)
{
intMinutes = intMinutes ?? ExpiryMinutes;
strKey = (strGroup.IsEmpty() ? C.CacheGroups.General : strGroup) + ":" + strKey;
var strData = JsonConvert.SerializeObject(objData);
var tsExpiry = new TimeSpan(0, intMinutes.Value, 0);
blnSuccess = objCache.StringSet(strKey, strData, tsExpiry);
}
}
catch (Exception)
{
blnSuccess = false;
}
return blnSuccess;
}
public bool Remove(string strKey, string strGroup = "")
{
bool blnSuccess = false;
try
{
var objCache = GetDatabase();
if (!strKey.IsEmpty() && objCache != null)
{
strKey = (strGroup.IsEmpty() ? C.CacheGroups.General : strGroup) + ":" + strKey;
blnSuccess = objCache.KeyDelete(strKey);
}
}
catch (Exception)
{
blnSuccess = false;
}
return blnSuccess;
}
public bool RemoveGroup(string strGroup)
{
bool blnSuccess = false;
try
{
var lstKeys = GetKeys(strGroup);
var objCache = GetDatabase();
if (lstKeys.Count > 0 && objCache != null)
{
foreach (var strKey in lstKeys)
{
objCache.KeyDelete(strKey);
}
blnSuccess = true;
}
}
catch (Exception)
{
blnSuccess = false;
}
return blnSuccess;
}
public bool ClearCache()
{
bool blnSuccess = false;
try
{
var objServer = GetServer();
if (objServer != null)
{
objServer.FlushAllDatabases();
blnSuccess = true;
}
}
catch (Exception)
{
blnSuccess = false;
}
return blnSuccess;
}
public async Task<bool> ClearCacheAsync()
{
// Get server details
var server = GetServer();
if (server is null)
return false;
// Flush All Databases
await server.FlushAllDatabasesAsync();
return true;
}
}
I am consuming the above CacheProvider in my code as mentioned below :
private async Task<IReadOnlyList<TestInfo>> GetDataAsync(int Id1, int Id2, int Id3, string cacheKey)
{
var data = _cacheProvider.Get<IReadOnlyList<TestInfo>>(cacheKey, TestCacheGroup);
if (data is null)
{
data = await _test.GetSampleDataAsync(Id1, Id2, Id3);
_cacheProvider.Set(cacheKey, data, TestCacheGroup, Defaults.CacheExpiryMinutes);
}
return data;
}
LazyCache by default uses MemoryCache under the hood. I came through documentation that LazyCache can be extended to swap out to redis or casandra at a later time but keep the same code and API.
Can anyone help me here with some code sample which will serve as a reference for my implementation
It is recommended for v2+ users of LazyCache users (who require the use of Redis, etc) move to the IDistributedCache
present in asp .net framework. For versions earlier, they provide a mechanism to do so via the ObjectCache
class. The following link may help those 1.x users: LazyCache Redist, Cassandra Extensions
There is an existing Redis implementation here: LazyCache: Redis