首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >缓存TryGetValue与Get

缓存TryGetValue与Get
EN

Stack Overflow用户
提问于 2020-02-19 05:19:29
回答 1查看 534关注 0票数 0

我就是这样实现我的CacheManager的。我面临的问题是,RemoveFromCache函数中的TryGetValue总是返回null。此函数是在其中一个令牌过期后调用的,因此我试图从缓存中的列表中清除该令牌,而GetAllTokens则返回所有令牌的完整列表。AddTokenToCache工作正常。

ASPNET-Core3.0上的WebAPI

CacheManager.cs

代码语言:javascript
复制
public class CacheManager : ICacheManager
{
    private IMemoryCache _cache;

    public CacheManager(IMemoryCache cache) {
        _cache = cache;

    }        
    public void AddTokenToCache(string appName, string tokenString)
    {
        List<Token> tokens = new List<Token>();

        //save this token against the application record in-memory
        if (!_cache.TryGetValue(CacheHelper.CacheKey_Tokens, out tokens))
        {
            if (tokens == null)
                tokens = new List<Token>();

        }

        tokens.Add(new Token
        {
            AppName = appName,
            GeneratedAt = DateTime.Now,
            TokenId = tokenString
        });

        // Set cache options.
        var cacheEntryOptions = new MemoryCacheEntryOptions()
        ;//    .SetSlidingExpiration(TimeSpan.FromSeconds(180)); //3 minutes

        _cache.Set(CacheHelper.CacheKey_Tokens, tokens, cacheEntryOptions);
    }

    public List<Token> GetAllTokens()
    {
        return _cache.Get<List<Token>>(CacheHelper.CacheKey_Tokens);
    }

    public bool RemoveFromCache(string tokenId)
    {

        List<Token> tokens = new List<Token>();            

        //remove this token from memory            
        if (!_cache.TryGetValue(CacheHelper.CacheKey_Tokens, out tokens)) {
            return false;
        }
        else
        {
            if (tokens != null && tokens.Count > 0)
            {
                //_logger.LogInfo("Processing token");
                //trimming quotations from the string
                tokenId = tokenId.Substring(1, tokenId.Length - 2);
                int index = tokens.FindIndex(t => t.TokenId == tokenId);

                if (index >= 0)
                    tokens.RemoveAt(index);

                var cacheEntryOptions = new MemoryCacheEntryOptions();
                _cache.Set(CacheHelper.CacheKey_Tokens, tokens, cacheEntryOptions);

                return true;
            }                
        }

        return false;
    }
}

我的呼叫顺序是:

  • AddTokenToCache (令牌被成功地添加到cache)
  • GetAllToken中(表示令牌被添加到cache)
  • AddTokenToCache中(令牌被成功地添加到cache)
  • GetAllToken (显示两个令牌都被添加到缓存中))
  • Fire TokenExpired事件,它调用RemoveFromCache (令牌是null)
  • GetAllToken (显示两个令牌都被添加到缓存中)

Startup.cs

代码语言:javascript
复制
public void ConfigureServices(IServiceCollection services)
    { 
        services.AddSingleton<ILoggerManager, LoggerManager>();

        services.AddMemoryCache();
        services.AddDbContext<GEContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
        services.AddControllers();
        services.AddRazorPages();
        services.AddSingleton<ICacheManager, CacheManager>();

        RegisterHandlerforTokenExpiredEvent(services);
        //other code removed for brevity
    }
public void RegisterHandlerforTokenExpiredEvent(IServiceCollection services)
    {
        var sp = services.BuildServiceProvider();

        var jwtManager = sp.GetService<IJWTAuthenticationManager>(); //publisher            
        var cacheManager = sp.GetService<ICacheManager>(); //subscriber

        jwtManager.TokenExpired += cacheManager.OnTokenExpired;            
    }
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-02-20 01:25:03

那是因为你用services.BuildServiceProvider()建造了另一个services.BuildServiceProvider()

( RegisterHandlerforTokenExpiredEvent(IServiceCollection服务){ var sp = services.BuildServiceProvider();//这是一个与ASP.NET内核本身构建的默认服务提供者不同的服务提供者。var jwtManager = sp.GetService();//publisher var cacheManager = sp.GetService();//订户//不能工作,因为cacheManager与您在控制器jwtManager.TokenExpired += cacheManager.OnTokenExpired中使用的实例不同;}

因此,您得到的ICacheManager实例是,而不是您在控制器/其他服务中注入的相同的单例。换句话说,您将有两个不同的ICacheManager实例!

作为一条金科玉律,不会在您的应用层代码中通过services.BuildServiceProvider()构建ServiceProvider的另一个副本,除非您非常确定它对您来说是好的。

如何修复

  1. 应该始终使用IoC而不是service模式,而不是构建另一个服务提供者的副本,然后再获取另一个实例。
  2. 似乎您的JWTAuthenticationManager是单例的,您希望在启动时绑定事件处理程序。如果是这样的话,您可以注册一个HostedService。

公共类MyHostedService : IHostedService {私有只读IJWTAuthenticationManager _jWTAuthManager;私有只读ICacheManager _cacheManager;//假设您的IJWTAuthenticationManager是一个单例服务公共MyHostedService(IJWTAuthenticationManager jWTAuthManager,ICacheManager cacheManager) { this._jWTAuthManager = jWTAuthManager;this._cacheManager = cacheManager;} public Task (JWTAuthManager){en21 20;返回;}公共任务StopAsync(CancellationToken cancellationToken) { this._jWTAuthManager.TokenExpired -= this._cacheManager.OnTokenExpired;返回Task.CompletedTask;}

并在启动程序中注册此服务:

services.AddHostedService();

另一种不需要HostedService并在启动时就开始的方法:

获取服务并在Host.Run()之前绑定事件

代码语言:javascript
复制
public static void Main(string[] args)
{
    var host = CreateHostBuilder(args).Build();
    var jwtMgr = host.Services.GetRequiredService<IJWTAuthenticationManager>();
    var cacheMgr = host.Services.GetRequiredService<ICacheManager>();
    jwtMgr.TokenExpired = cacheMgr.OnTokenExpired;
    host.Run();
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60293515

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档