鉴于一个ASP.NET Core 2.x应用程序,假设我使用了两种分布式缓存机制:
services.AddDistributedSqlServerCache()
services.AddDistributedRedisCache()
据我了解,由于Redis是最后一次注册,因此,每当请求IDistributedCache
的实例时,它都会解析为RedisCache
的实现。
在我的项目中,我还使用了Distributed-Cache
标签助手,我想将其解析为RedisCache
(没问题,可以使用上述设置)。
但是,我也正在使用会话中间件,该中间件还要求实现IDistributedCache
。
我需要Session
中间件来解析到SQL分布式缓存和Distributed-Cache
标签助手,以及对IDistributedCache
缓存来解析到RedisCache
的任何其他请求
如果我正确理解this的文章,则可以指定服务定位器针对对services.AddSingleton
的通用调用解析为哪种实现,但这似乎并不能翻译{{1 }}。
有什么办法解决这个问题吗?
答案 0 :(得分:3)
AddDistributedSqlServerCache()
和AddDistributedRedisCache()
分别为IDistributedCache
注册一个单例:SqlServerCache
和RedisCache
。由于相关组件仅依赖于IDistributedCache
,因此它们都将获得相同的分布式缓存实现(取决于上次注册的内容)。
这通常是设计使然,因为实现例如会话中间件应该不关心IDistributedCache
的实际注册实现是什么。它仅取决于存在 some 并使用它。同样,其他服务也将只使用一个分布式缓存依赖项。
通常,解决这个问题真的没有办法。您最终可以做的是创建一些适配器,该适配器本身实现IDistributedCache
,然后根据传递的参数委托给SQL Server缓存或Redis缓存。
在您的情况下,有一种更简单的方法。由于ASP.NET Core的构建具有很高的可扩展性,并且大多数组件可以由其他实现简单地交换,因此我们可以在此处利用它使会话中间件仅使用专用的分布式缓存,而其他所有内容都归还默认缓存。 / p>
为此,我们只需实现ISessionStore
并将其注册,这基本上就是AddSession()
所做的。在自定义会话存储实现中,我们将直接依赖于IDistributedCache
,而不是依赖于SqlServerCache
。这样一来,我们就不会退回到默认的IDistributedCache
(无论如何),而是强制系统使用SqlServerCache
。
public class SqlServerCacheSessionStore : ISessionStore
{
private readonly IDistributedCache _cache;
private readonly ILoggerFactory _loggerFactory;
public SqlServerCacheSessionStore(SqlServerCache cache, ILoggerFactory loggerFactory)
{
_cache = cache ?? throw new ArgumentNullException(nameof(cache));
_loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
}
public ISession Create(string sessionKey, TimeSpan idleTimeout, TimeSpan ioTimeout, Func<bool> tryEstablishSession, bool isNewSessionKey)
{
if (string.IsNullOrEmpty(sessionKey))
throw new ArgumentNullException(nameof(sessionKey));
if (tryEstablishSession == null)
throw new ArgumentNullException(nameof(tryEstablishSession));
return new DistributedSession(_cache, sessionKey, idleTimeout, ioTimeout, tryEstablishSession, _loggerFactory, isNewSessionKey);
}
}
这实际上与DistributedSessionStore
的实现相同,后者是默认的ISessionStore
实现,除了我们依赖SqlServerCache
而不是IDistributedCache
。
现在,我们只需要使用Configure
方法进行连接:
// we keep the Redis cache as the default
services.AddDistributedRedisCache();
// no call to `AddSqlServerCache` as we don’t want to overwrite the `IDistributedCache`
// registration; instead, register (and configure) the SqlServerCache directly
services.AddSingleton<SqlServerCache>();
services.Configure<SqlServerCacheOptions>(options =>
{
// here goes the configuration that would normally be done in the
// configure action passed to `AddSqlServerCache`
options.ConnectionString = Configuration.GetConnectionString("DistributedCache");
});
// add session, but overwrite the `ISessionStore` afterwards
services.AddSession();
services.AddTransient<ISessionStore, SqlServerCacheSessionStore>();
这应该是全部。因此,当会话中间件现在解析ISessionStore
时,它将得到直接依赖于SqlServerCacheSessionStore
的{{1}}而不是一般的SqlServerCache
,后者将是Redis缓存。>