28

I am using Redis cache for caching purpose (specifically stackexchange.Redis C# driver. Was wondering is there any ways to get all the keys available in cache at any point in time. I mean the similar thing I can do in ASP.NET cache object (below code sample)

var keys = Cache.GetEnumerator();                               
while(keys.MoveNext())
{
     keys.Key.ToString() // Key
}

Redis documentation talks about KESY command but do stackexchange.Redis have implementation for that command.

Debugging through the connection.GetDataBase() instance, I don't see any method / property for that.

Any idea?

Rahul
  • 76,197
  • 13
  • 71
  • 125

6 Answers6

22

Function that you need is under IServer interface, and can be reached with:

ConnectionMultiplexer m = CreateConnection();
m.GetServer("host").Keys();

Note that prior to version 2.8 of redis server that will use KEYS command you mentioned, and it can be very slow in certain cases. However if you use redis 2.8+ - it will use SCAN command instead, which performs better. Also ensure that you really need to get all keys, in my practice I've never ever needed this.

Evk
  • 98,527
  • 8
  • 141
  • 191
14
string connectionString = "my_connection_string";
ConfigurationOptions options = ConfigurationOptions.Parse(connectionString);
ConnectionMultiplexer connection = ConnectionMultiplexer.Connect(options);
IDatabase db = connection.GetDatabase();
EndPoint endPoint = connection.GetEndPoints().First();
RedisKey[] keys = connection.GetServer(endPoint).Keys(pattern: "*").ToArray();
MTZ4
  • 2,274
  • 2
  • 25
  • 41
9

Try using this code snippet, it worked for me:

IServer server = Connection.GetServer("yourcache.redis.cache.windows....", 6380);
foreach (var key in server.Keys())
{
   Console.WriteLine(key);
}

source

Tanvi Mathur
  • 91
  • 1
  • 2
  • 1
    Tanvi, appreciate for answering but isn't your answer same as already posted and accepted one? – Rahul Aug 09 '16 at 14:13
  • I tried to use the approach in the answer given here, and it didn't work for me, so I posted the solution that I found elsewhere. – Tanvi Mathur Aug 10 '16 at 05:13
  • 1
    Tanvi, probably that didn't worked for you cause you tried it as-is. It's an abstract code posted but do points exactly what needs to be done. Irrespective of that +1 for your effort to post the working code. – Rahul Aug 10 '16 at 13:46
5

You need db to distinguish where to look for keys. So the last line of MTZ4 answer then becomes:

RedisKey[] keys = connection.GetServer(endPoint).Keys(database: db.Database, pattern: "*").ToArray();

where db.Database is the numeric identifier of the Redis Database you want to query.

VChanis
  • 51
  • 1
  • 3
5

Once you have your instance of IDatabase, I am using this as we speak:

        var endpoints = _Cache.Multiplexer.GetEndPoints();
        var server = _Cache.Multiplexer.GetServer(endpoints[0]);
        var keys = server.Keys();
2

ASP.Net Core 3.1

Add following packages to your .csproj

<ItemGroup>
  <PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="3.1.15" />
  <PackageReference Include="StackExchange.Redis.Extensions.AspNetCore" Version="7.0.1" />
  <PackageReference Include="StackExchange.Redis.Extensions.Core" Version="7.0.1" />
  <PackageReference Include="StackExchange.Redis.Extensions.Newtonsoft" Version="7.0.1" />
</ItemGroup>

In Startup.cs this is how you would be able to register Redis Client ready to be injected in your workflow code.

public class Startup
{
  public void ConfigureServices(IServiceCollection services)
  {
    // ... other registrations

    // Used By : Sample Below : RedisCacheHelperController (Method 1 Only)
    services.AddSingleton<IConnectionMultiplexer>(
            ConnectionMultiplexer.Connect(DbHelper.GetRedisConnectionHost(Options.IsDevDb()))
        );

    // Used By : Sample Below : DistributedCacheController (Method 2 Only)
    services.AddStackExchangeRedisCache(options => 
            options.Configuration = DbHelper.GetRedisConnectionHost(Options.IsDevDb())
        );

    // ... other registrations
  }
}

Note:

DbHelper.GetRedisConnectionHost(Options.IsDevDb()) :>>> is my way to resolve the connection information/string for my Redis instance respective to my environment. You can have your own way here for that or you can hard-code it here if you like to begin with.

Method 1

So, having the above stuffs in place, would be able to inject the Redis IConnectionMultiplexer into your Controllers or Services.

public class RedisCacheHelperController : ControllerBase
{
    private readonly IConnectionMultiplexer multiplexer;

    public RedisCacheHelperController(IConnectionMultiplexer multiplexer)
    {
        this.multiplexer = multiplexer;
    }
}

Here are the helper APIs to demonstrate how can you use the IConnectionMultiplexer.

public class RedisCacheHelperController : ControllerBase
{
    private readonly IConnectionMultiplexer multiplexer;

    public RedisCacheHelperController(IConnectionMultiplexer multiplexer)
    {
        this.multiplexer = multiplexer;
    }

    [HttpGet("{key}")]
    public async Task<IActionResult> GetCacheByKey([FromRoute] string key)
    {
        var responseContent = await multiplexer.GetDatabase().StringGetAsync(key);

        return Content(
           responseContent,
           Constants.ContentTypeHeaderValueJson // "application/json"
       );
    }

    [HttpPost("{key}")]
    public async Task<IActionResult> PostCacheByKey([FromRoute] string key, [FromBody] object data)
    {
        var requestContent = data.Json(); // JsonConvert.SerializeObject(data)
        await multiplexer.GetDatabase().StringSetAsync(key, requestContent);
        return Ok(key);
    }

    [HttpDelete("{key}")]
    public async Task<IActionResult> DeleteCacheByKey([FromRoute] string key)
    {
        await multiplexer.GetDatabase().KeyDeleteAsync(key);
        return Ok(key);
    }

    [HttpGet("CachedKeys")]
    public IActionResult GetListCacheKeys([FromQuery] [DefaultValue("*")] string pattern)
    {
        var keys = multiplexer
            .GetServer(multiplexer
                .GetEndPoints()
                .First())
            .Keys(pattern: pattern ?? "*")
            .Select(x => x.Get());

        return Ok(keys);
    }
   
    // ... could have more Reids supported operations here
}

Now the above is the use-case where you want access Redis Client and do more Redis specific stuffs. The package Microsoft.Extensions.Caching.StackExchangeRedis we included in .csproj above supports Reids to be registered and injected in as a IDistributedCache. The interface IDistributedCache is been defined by the Microsoft and supports basic/common functionalities by the different distributed cache solutions where Redis is one of that.

Meaning if your purpose is limited to set and/or get cache as a key-value pair, you would rather like to do it this way in Method 2 below.

Method 2

public class DistributedCacheController : ControllerBase
{
    private readonly IDistributedCache distributedCache;

    public DistributedCacheController(IDistributedCache distributedCache)
    {
        this.distributedCache = distributedCache;
    }
    
    [HttpPost("{key}")]
    public async Task<IActionResult> PostCacheByKey([FromRoute] string key, [FromBody] object data)
    {
        var requestContent = data.Json(); // JsonConvert.SerializeObject(data)
        await distributedCache.SetStringAsync(key, requestContent);
        return Ok(key);
    }

    [HttpGet("{key}")]
    public async Task<IActionResult> GetCacheByKey([FromRoute] string key)
    {
        var responseContent = await distributedCache.GetStringAsync(key);

        if (!string.IsNullOrEmpty(responseContent))
        {
            return Content(
               responseContent,
               Constants.ContentTypeHeaderValueJson // "application/json"
            );
        }

        return NotFound();
    }

    [HttpDelete("{key}")]
    public async Task<IActionResult> DeleteCacheByKey([FromRoute] string key)
    {
        await distributedCache.RemoveAsync(key);
        return Ok(key);
    }
}
Leniel Maccaferri
  • 100,159
  • 46
  • 371
  • 480
GDroid
  • 1,254
  • 1
  • 16
  • 36
  • i get RedisKey does not contain a definition for Get(), any idea? – Gabriel Manzini Aug 27 '21 at 21:50
  • 1
    This shows how to utilize Redis from aspnetcore, but does not answer the question which is how do you enumerate the keys – Sean Aug 31 '21 at 17:55
  • 1
    `Method1`, scroll down to `API4` **[HttpGet("CachedKeys")]** is the answer. Unfortunately **IDistributedCache** doesn't provide you the mechanism to get all keys. For that you must use `Method1`. – GDroid Sep 01 '21 at 22:39