给定一个ASP.NET Core 2.x应用程序,假设我使用两种分布式缓存机制:
services.AddDistributedSqlServerCache()
services.AddDistributedRedisCache()
据我所知,由于Redis是最后一次注册的,只要请求IDistributedCache
实例,它就会解析为RedisCache
实现。
在我的项目中,我也使用Distributed-Cache
标记帮助器,我想解析为RedisCache
(没问题,适用于上面的设置)。
但是,我也使用Session中间件,它也要求实现IDistributedCache
。
我需要Session
中间件来解析SQL分布式缓存和Distributed-Cache
标签帮助程序以及IDistributedCache
缓存的任何其他请求以解析为RedisCache
。
如果我正确理解this文章,您可以指定服务定位器解析为services.AddSingleton
的泛型调用的实现,但这似乎不会转换像AddSession()
这样的中间件注册帮助函数。
任何想法如何解决这个问题?
AddDistributedSqlServerCache()
和AddDistributedRedisCache()
分别为IDistributedCache
登记单身人士:SqlServerCache
和RedisCache
。由于依赖组件只依赖于IDistributedCache
,它们都将获得相同的分布式缓存实现(取决于最后注册的内容)。
这通常是设计因为实施,例如,会话中间件,不应该关心IDistributedCache
的实际注册实现是什么。它只取决于有一些和使用它。同样,其他服务也将只使用一个分布式缓存依赖项。
通常情况下,没有办法解决这个问题。你最终可以做的是创建一个实现IDistributedCache
本身的适配器,然后根据传递的参数委托SQL Server缓存或Redis缓存。
在你的情况下,有一个更简单的方法。由于ASP.NET Core的构建非常易于扩展,并且大多数组件都可以通过其他实现进行简单交换,因此我们可以在此处利用它来使会话中间件只使用专用的分布式缓存,而其他所有内容都回退到默认缓存。
为此,我们只是实现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
时,它将获得直接依赖于SqlServerCache
的IDistributedCache
,而不是将成为Redis缓存的一般qazxswpoi。