Microsoft Distrubted Redis Cache - Getting keys based on pattern
Asked Answered
E

2

9

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?

Expansible answered 25/10, 2018 at 8:53 Comment(0)
C
16

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.

Comply answered 25/10, 2018 at 18:36 Comment(4)
So now you're using an interface which you get an implementation for via DI and add implementation specific details to your application, so bye bye DI advantages. I really struggled replacing an IMemoryCache implementation with an IDistributeCache implementation in our microservices architecture and stopped because of this problem.Backandforth
I was providing the only possible way to achieve what the OP was looking for. Unfortunately, yes, that means relying on Redis directly. The abstraction doesn't cover this scenario. However, that has nothing to do with replacing IMemoryCache with IDistributedCache, and I'm not sure what exactly your difficulty was there. It's virtually a drop in replacement. The only difference is that IDistributedCache forces serialization, which you should have been doing anyways.Comply
I know and I understand, it's just annoying that IDistributedCache has no support for expirationTokens and that's a BIG difference from IMemoryCache.Backandforth
You can set expiration in IDistributedCache via DistributedCacheEntryOptions.Asseverate
D
0

I know question is a bit old but based on this answear: How to get all keys data from redis cache

This is example solution:

in CustomerRepository.cs

using Newtonsoft.Json;
using StackExchange.Redis;
// ...

public class CustomerRepository : ICustomerRepository
{
    private readonly IDistributedCache _redis;
    private readonly IConfiguration _configuration;

    public CustomerRepository(IDistributedCache redis, IConfiguration configuration)
    {
        _redis = redis;
        _configuration = configuration;
    }

    ///<summary>replace `object` with `class name`</summary>

    public async Task<object> GetCustomersAsync(string name)
    {
        ConfigurationOptions options = ConfigurationOptions.Parse(_configuration.GetConnectionString("DefaultConnection"));
        ConnectionMultiplexer connection = ConnectionMultiplexer.Connect(options);
        IDatabase db = connection.GetDatabase();
        EndPoint endPoint = connection.GetEndPoints().First();
        var pattern = $"application:customer:{name}:*";
        RedisKey[] keys = connection.GetServer(endPoint).Keys(pattern: pattern).ToArray();
        var server = connection.GetServer(endPoint);

        var result = await _redis.GetStringAsync(key);
        return JsonConvert.DeserializeObject<object>(result);
    }
}

in appsettings.json

{
  "ConnectionStrings": {
    "DefaultConnection": "localhost:6379,password=YOUR_PASSWORD_HERE"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  }
}
Dhar answered 29/6, 2021 at 12:34 Comment(1)
This code is incomplete/not working as posted. The "server" and "db" variables are never used. The "key" variable is not defined.Tinea

© 2022 - 2024 — McMap. All rights reserved.