如何在计时器回调或方法中激发I Task的情况下获取IMemoryCache的正确实例?

问题描述

我正在尝试使用在服务中注入的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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...