问题描述
我正在尝试使用在服务中注入的IMemoryCache
实例,该实例具有一个Timer,每隔x分钟触发一次方法。相同的IMemoryCache
接口被注入到控制器构造函数中,对于每个控制器请求,应将一个对象添加到列表并将其保存到缓存。我的问题是,当我尝试从缓存中获取对象列表时(在每x分钟触发的服务中调用一次),我没有获得正确的实例(我的列表为null)。我正在使用.NET Core 3.1,并且作为一种项目,我有一个Web API。
PS。我尝试使用Task
而不是Timer,但是我有相同的行为。我还尝试在触发的方法中制作DI缓存解析器。我猜是线程问题。这是我的代码:
在启动时:
services.AddMemoryCache();
services.AddScoped<SyncService>();
var sp = services.BuildServiceProvider();
//I do this to fire my timer from the constructor
var syncService = sp.GetService<SyncService>();
我的控制器:
public class TestController : BaseApiController
{
private IMemoryCache _cache;
public TestController(IMemoryCache cache)
{
_cache = cache;
}
[HttpPost]
public ActionResult<bool> AckRequest([FromBody] Ack ack)
{
if (ack != null)
{
List<Ack> ackList;
//I always get the correct value for each request
_cache.TryGetValue("ack",out ackList);
if (ackList != null)
{
ackList.Add(ack);
_cache.Set("ack",ackList);
}
else
{
var newList = new List<Ack>();
newList.Add(ack);
_cache.Set("ack",newList);
}
return Ok(true);
}
return BadRequest();
}
}
我的SyncService:
public class SyncService
{
private readonly IMemoryCache _cache;
public SyncService(IMemoryCache cache)
{
_cache = cache;
Timer myTimer = new Timer();
myTimer.Interval = 1 * 60 * 1000;
myTimer.Elapsed += SyncWithDatabase;
myTimer.Start();
//Task task = new Task(() => //tried with a Task too
//{
// while (true)
// {
// SyncWithDatabase();
// Thread.Sleep(1 * 60 * 1000);
// }
//});
//task.Start();
}
public void SyncWithDatabase(object sender,ElapsedEventArgs e)
{
List<Ack> ackList;
_cache.TryGetValue("ack",out ackList); //the list is always null
}
}
解决方法
在您的代码中,我们可以找到您通过调用BuildServicesProvider方法来创建新的服务提供者,这将导致您用来设置值的缓存实例与您在{中检索值的缓存实例不同{1}}。
要达到相同的要求,您可以尝试将其实现为hosted service。
SyncService
在Startup类的public class TimedHostedService : IHostedService,IDisposable
{
private Timer _timer;
private readonly IMemoryCache _cache;
public TimedHostedService(IMemoryCache cache)
{
_cache = cache;
}
public void Dispose()
{
_timer?.Dispose();
}
public Task StartAsync(CancellationToken cancellationToken)
{
_timer = new Timer(DoWork,null,TimeSpan.Zero,TimeSpan.FromSeconds(60));
return Task.CompletedTask;
}
private void DoWork(object state)
{
List<Ack> ackList;
_cache.TryGetValue("ack",out ackList);
}
public Task StopAsync(CancellationToken cancellationToken)
{
_timer?.Change(Timeout.Infinite,0);
return Task.CompletedTask;
}
}
方法中注册TimedHostedService
。
ConfigureServices