0

I have asp.net core 3.1 application leveraging Azure Redis Cache with nuget package : StackExchange.Redis (Version: 2.2.62). Here I am trying to reset the Cache at every app startup event with the following code:

ResetCacheService.cs

public class ResetCacheService : IHostedService
{
    private readonly IServiceProvider _serviceProvider;
    public ResetCacheService(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public async Task StartAsync(CancellationToken cancellationToken)
    {
        // Create a new scope to retrieve scoped services
        using (var scope = _serviceProvider.CreateScope())
        {
            // Get the CacheProvider instance
            var redisCache = scope.ServiceProvider.GetRequiredService<ICacheProvider>();
            //Do the cache reset asynchronously
            await redisCache.ClearCacheAsync();
        }
    }

    public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}

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 ClearCacheAsync();
}

CacheProvider.cs

public class CacheProvider : ICacheProvider
{
    private static readonly int ExpiryMinutes = ConfigManager.Get(C.AppKeys.CacheExpiryMinutes, C.Defaults.CacheExpiryMinutes);
    private static Lazy<ConnectionMultiplexer> _objCacheConn = CreateConnection();
    private static Lazy<ConnectionMultiplexer> CreateConnection()
    {
        return new Lazy<ConnectionMultiplexer>(() =>
        {
            string strConn = ConfigManager.Get(C.VaultKeys.RedisConnString);
            return ConnectionMultiplexer.Connect(strConn);
        });
    }

    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;
    }

    /// <summary>
    /// Reset the Cache
    /// </summary>
    /// <returns></returns>
    public async Task ClearCacheAsync()
    {
        var server = GetServer();
        await server.FlushAllDatabasesAsync();
    }
}

Startup.cs

public static IServiceCollection AddCacheResetHostedService(this IServiceCollection services) => services.AddHostedService<ResetCacheService>();
public virtual void ConfigureServices(IServiceCollection services) => services.AddConfigManager(this.configuration).AddCacheResetHostedService();

On executing the code I see the below error:

No connection is active/available to service this operation: FLUSHALL; It was not possible to connect to the redis server(s). ConnectTimeout, inst: 0, qu: 0, qs: 0, aw: False, rs: NotStarted, ws: Initializing, in: 0, serverEndpoint: daqmmredis.redis.cache.windows.net:6380, mc: 1/1/0, mgr: 10 of 10 available, clientName: USHYDSAPATRO7, IOCP: (Busy=0,Free=1000,Min=8,Max=1000), WORKER: (Busy=0,Free=32767,Min=8,Max=32767), v: 2.2.62.27853
santosh kumar patro
  • 7,231
  • 22
  • 71
  • 143

2 Answers2

2

Please check if the below given steps help to work around:

  • downgrading StackExchange.Redis to 2.1.58

  • Instead of creating a ConfigurationOptions parameter using the Endpoint and Password separately, use the "Primary connection string (StackExchange.Redis)" from Azure Access Keys as the parameter to ConnectionMultiplexer.Connect()

  • Set the ssl=True,sslprotocols=tls12 in your configuration to force it to the latest version if you're utilizing a secure TLS connection.

Refer here for more information.

0

In my case, I had defined and forgot a firewall rule for my client machine for Redis under Azure Portal>YourRedisCache>Settings>FireWall. This caused Redis to reject any other connections. When I deleted that firewall rule, it worked fine.

Aykut Ucar
  • 615
  • 8
  • 16