Search code examples
c#asp.net-core.net-coreredisasp.net-core-mvc

Microsoft Distrubted Redis Cache - Getting keys based on pattern


We are working with the Microsoft Distrbuted Cache implementation for .NET core. See https://learn.microsoft.com/en-us/aspnet/core/performance/caching/distributed?view=aspnetcore-2.1 for more information.

Now we can get an key by the following code.

var cacheKey = "application:customer:1234:profile";
var profile = _distributedCache.GetString(cacheKey);

What i want to do is tho do the following:

var cacheKey = "application:customer:1234:*";
var customerData = _distributedCache.GetString(cacheKey);

So that we can get the following keys with this pattern:

  • application:customer:1234:Profile
  • application:customer:1234:Orders
  • application:customer:1234:Invoices
  • application:customer:1234:Payments

Could not get this work with any wildcard or without an wild card. Is there an solution without implementing another Redis nuget package?


Solution

  • This isn't supported via the IDistributeCache interface. It's designed to get/set a specific key, not return a range of keys. If you need to do something like this, you'll need to drop down into the underlying store, i.e. Redis. The good news is that you don't need anything additional: the same StackExchange.Redis library that is needed to support the Redis IDistributedCache implementation also provides a client you can utilize directly.

    In particular to your scenario here, you'd need some code like:

    var server = _redis.GetServer(someServer);
    foreach(var key in server.Keys(pattern: cacheKey)) {
        // do something
    }
    

    Here, _redis is an instance of ConnectionMultiplexer. This should already be registered in your service collection since it's utilized by the Redis IDistributedCache implementation. As a result, you can inject it into the controller or other class where this code exists.

    The someServer variable is a reference to one of your Redis servers. You can get all registered Redis servers via _redis.GetEndpoints(). That will return an IEnumerable of servers, which you can either pick from or enumerate over. Additionally, you can simply connect directly to a particular server via passing the host string and port:

    var server = _redis.GetServer("localhost", 6379);
    

    Be advised, though, that Keys() will result in either a SCAN or KEYS command being issued at the Redis server. Which is used depends on the server version, but either is fairly inefficient, as the entire keyspace must be looked at. It is recommended that you do not use this in production, or if you must, that you issue it on a slave server.

    With your question technically answered, given the complexity and the inherent inefficiency of SCAN/KEYS, you'd be better served just doing something like:

    var cacheKeyPrefix = "application:customer:1234";
    var profile = _distributedCache.GetString($"{cacheKeyPrefix}:Profile");
    var orders = _distributedCache.GetString($"{cacheKeyPrefix}:Orders");
    var invoices = _distributedCache.GetString($"{cacheKeyPrefix}:Invoices");
    var payments = _distributedCache.GetString($"{cacheKeyPrefix}:Payments");
    

    That's going to end up being much quicker and doesn't require anything special.