Пользовательский зависимый инъекционный решатель для промежуточного программного обеспечения ASP.NET Core 2.x? - PullRequest
0 голосов
/ 29 августа 2018

Учитывая приложение ASP.NET Core 2.x, допустим, я использую два механизма распределенного кэша:

services.AddDistributedSqlServerCache()
services.AddDistributedRedisCache()

Насколько я понимаю, поскольку Redis был зарегистрирован последним, каждый раз, когда запрашивается экземпляр IDistributedCache, он разрешается к реализации RedisCache.

В моем проекте я также использую помощник по тегам Distributed-Cache, который я хочу разрешить до RedisCache (без проблем, работает с вышеуказанными настройками).

Однако я также использую промежуточное программное обеспечение Session, которое также запрашивает реализацию IDistributedCache.

Мне нужно промежуточное ПО Session для разрешения к распределенному кешу SQL и помощник тега Distributed-Cache, а также любой другой запрос для кэша IDistributedCache для разрешения к RedisCache.

Если я правильно понимаю эту статью , вы можете указать, к какой реализации разрешает локатор служб для общих вызовов services.AddSingleton, но, похоже, это не переводит вспомогательные функции регистрации промежуточного программного обеспечения, такие как AddSession() .

Есть идеи, как это решить?

1 Ответ

0 голосов
/ 29 августа 2018

Оба AddDistributedSqlServerCache() и AddDistributedRedisCache() регистрируют синглтон для IDistributedCache: SqlServerCache и RedisCache соответственно. Поскольку зависимые компоненты зависят только от IDistributedCache, все они получат одинаковую реализацию распределенного кэша (в зависимости от того, что было зарегистрировано последним).

Это, как правило, дизайн, потому что реализация, например, промежуточное программное обеспечение сеанса не должно заботиться о фактической зарегистрированной реализации IDistributedCache. Это просто зависит от того, есть ли некоторые и использует это. И в равной степени другие службы также будут использовать только одну распределенную зависимость кэша.

Обычно не было бы способа обойти это. В конечном итоге вы можете создать какой-то адаптер, который сам реализует IDistributedCache, а затем в зависимости от переданных аргументов делегировать либо в кэш SQL Server, либо в кэш Redis.

В вашем случае есть более простой способ. Поскольку ядро ​​ASP.NET построено так, чтобы быть очень расширяемым, и большинство компонентов можно просто поменять местами другими реализациями, мы можем использовать это здесь, чтобы промежуточное ПО сеанса просто использовало специализированный распределенный кеш, а все остальное возвращается к кешу по умолчанию.

Для этого мы просто реализуем 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.

...