我就是这样实现我的CacheManager的。我面临的问题是,RemoveFromCache函数中的TryGetValue总是返回null。此函数是在其中一个令牌过期后调用的,因此我试图从缓存中的列表中清除该令牌,而GetAllTokens则返回所有令牌的完整列表。AddTokenToCache工作正常。
ASPNET-Core3.0上的WebAPI
CacheManager.cs
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;
}
}我的呼叫顺序是:
Startup.cs
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;
}发布于 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的另一个副本,除非您非常确定它对您来说是好的。
如何修复
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()之前绑定事件
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();
}https://stackoverflow.com/questions/60293515
复制相似问题