给定一个ASP.NET Core2.x应用程序,假设我使用了两种分布式缓存机制:
services.AddDistributedSqlServerCache()
services.AddDistributedRedisCache()据我所知,由于Redis是在最后一次注册的,所以无论何时请求IDistributedCache的实例,它都会解析为RedisCache实现。
在我的项目中,我还使用了Distributed-Cache标签帮助器,我希望将其解析为RedisCache (没有问题,适用于上面的设置)。
然而,我也在使用会话中间件,它也需要一个IDistributedCache实现。
我需要Session中间件来解析到SQL分布式缓存和Distributed-Cache标记帮助器,以及任何其他对IDistributedCache缓存的请求来解析到RedisCache。
如果我正确理解了this文章,您可以指定服务定位器为对services.AddSingleton的通用调用解析到哪个实现,但这似乎不能转换AddSession()等中间件注册助手函数。
有什么办法解决这个问题吗?
发布于 2018-08-29 07:08:34
AddDistributedSqlServerCache()和AddDistributedRedisCache()都为IDistributedCache注册了一个单例:SqlServerCache和RedisCache。由于依赖组件只依赖于IDistributedCache,因此它们都将获得相同的分布式缓存实现(取决于最后注册的内容)。
这通常是设计的,因为实现,例如会话中间件,不应该关心IDistributedCache的实际注册实现是什么。它只是依赖于有一些,并使用它。同样,其他服务也将只使用一个分布式缓存依赖项。
通常,不会真的有办法绕过这一点。您最终可以做的是创建一些适配器来实现IDistributedCache本身,然后根据传递的参数将其委托给SQL Server缓存或Redis缓存。
但在您的情况下,有一种更简单的方法。由于ASP.NET核心被构建为具有很强的可扩展性,并且大多数组件可以被其他实现简单地交换,因此我们可以在这里利用这一点来使会话中间件仅使用专门的分布式缓存,而所有其他组件都回落到默认缓存。
为此,我们只需实现ISessionStore并注册它,这基本上也是AddSession()所做的。在自定义会话存储实现中,我们将直接依赖SqlServerCache,而不是依赖于IDistributedCache。因此,我们不会退回到默认的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);
}
}这实际上与默认的ISessionStore实现DistributedSessionStore是相同的,只是我们依赖于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时,它将获得直接依赖于SqlServerCache的SqlServerCacheSessionStore,而不是作为Redis缓存的通用IDistributedCache。
https://stackoverflow.com/questions/52067152
复制相似问题