ASP.NET Core 2.x 中间件的自定义依赖注入解析器?

use*_*433 5 c# asp.net-core asp.net-core-middleware

给定一个 ASP.NET Core 2.x 应用程序,假设我使用两种分布式缓存机制:

services.AddDistributedSqlServerCache()
services.AddDistributedRedisCache()
Run Code Online (Sandbox Code Playgroud)

IDistributedCache据我了解,由于 Redis 是最后注册的,因此每当请求实例时,它都会解析RedisCache实现。

在我的项目中,我还使用了Distributed-Cache标签助手,我想解决它RedisCache(没问题,适用于上述设置)。

然而,我也在使用会话中间件,它也需要一个IDistributedCache实现。

我需要Session中间件来解析 SQL 分布式缓存和Distributed-Cache标记帮助程序以及任何其他IDistributedCache缓存请求以解析为RedisCache.

如果我正确理解本文,您可以指定服务定位器解析为对 的通用调用的实现services.AddSingleton,但这似乎并不能转换中间件注册帮助器函数,例如AddSession().

有什么想法如何解决这个问题吗?

pok*_*oke 4

AddDistributedSqlServerCache()和分别为:和AddDistributedRedisCache()注册一个单例。由于依赖组件仅依赖于,因此它们都将获得相同的分布式缓存实现(取决于最后注册的内容)。IDistributedCacheSqlServerCacheRedisCacheIDistributedCache

\n\n

这通常是设计使然,因为实现(例如会话中间件)不应该关心实际注册的实现是什么IDistributedCache。它只取决于有一些并使用它。同样,其他服务也将只使用一个分布式缓存依赖项。

\n\n

通常,\xe2\x80\x99t 确实没有办法解决这个问题。您最终可以做的是创建一些实现IDistributedCache自身的适配器,然后根据传递的参数委托给 SQL Server 缓存或 Redis 缓存。

\n\n

对于你的情况,有一个更简单的方法。由于 ASP.NET Core 被构建为非常可扩展的,并且大多数组件可以简单地由其他实现进行交换,因此我们可以在此处利用这一点使会话中间件仅使用专门的分布式缓存,而其他所有内容都回退到默认缓存。

\n\n

为此,我们只需实现ISessionStore并注册它,这基本上也是这样AddSession()做的。在自定义会话存储实现中,IDistributedCache我们将SqlServerCache直接依赖而不是依赖。这样,我们就不会回退到默认值IDistributedCache(无论是什么),而是强制系统使用SqlServerCache.

\n\n
public class SqlServerCacheSessionStore : ISessionStore\n{\n    private readonly IDistributedCache _cache;\n    private readonly ILoggerFactory _loggerFactory;\n\n    public SqlServerCacheSessionStore(SqlServerCache cache, ILoggerFactory loggerFactory)\n    {\n        _cache = cache ?? throw new ArgumentNullException(nameof(cache));\n        _loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));\n    }\n\n    public ISession Create(string sessionKey, TimeSpan idleTimeout, TimeSpan ioTimeout, Func<bool> tryEstablishSession, bool isNewSessionKey)\n    {\n        if (string.IsNullOrEmpty(sessionKey))\n            throw new ArgumentNullException(nameof(sessionKey));\n        if (tryEstablishSession == null)\n            throw new ArgumentNullException(nameof(tryEstablishSession));\n\n        return new DistributedSession(_cache, sessionKey, idleTimeout, ioTimeout, tryEstablishSession, _loggerFactory, isNewSessionKey);\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

这实际上与DistributedSessionStore默认ISessionStore实现相同的实现,只是我们依赖于SqlServerCache而不是IDistributedCache

\n\n

现在,我们只需要在方法中连接所有内容Configure

\n\n
// we keep the Redis cache as the default\nservices.AddDistributedRedisCache();\n\n// no call to `AddSqlServerCache` as we don\xe2\x80\x99t want to overwrite the `IDistributedCache`\n// registration; instead, register (and configure) the SqlServerCache directly\nservices.AddSingleton<SqlServerCache>();\nservices.Configure<SqlServerCacheOptions>(options =>\n{\n    // here goes the configuration that would normally be done in the\n    // configure action passed to `AddSqlServerCache`\n    options.ConnectionString = Configuration.GetConnectionString("DistributedCache");\n});\n\n// add session, but overwrite the `ISessionStore` afterwards\nservices.AddSession();\nservices.AddTransient<ISessionStore, SqlServerCacheSessionStore>();\n
Run Code Online (Sandbox Code Playgroud)\n\n

这应该就是全部了。因此,当会话中间件现在解析时,ISessionStore它将SqlServerCacheSessionStore直接依赖于Redis 缓存SqlServerCache,而不是一般的IDistributedCacheRedis 缓存。

\n