c# - 使用 DbContext 的服务器端计时器

标签 c# asp.net entity-framework asp.net-core dbcontext

我想在服务器中运行一个计时器,每 60 秒运行一次 method()

现在我已经使用下面的代码完成了一些工作

public class Alarm
{

    public Alarm(AppDbContext _db)
    {
        db = _db;
    }


    private static Timer aTimer;
    private AppDbContext db;

    public void StartTimerEvent()
    {
        // Create a timer and set a 60 second interval.
        aTimer = new Timer();
        aTimer.Interval = 60000;

        // Hook up the Elapsed event for the timer. 
        aTimer.Elapsed += (source, e) => CheckDBEvents(source, e);
        // Have the timer fire repeated events (true is the default)
        aTimer.AutoReset = true;
        // Start the timer
        aTimer.Enabled = true;

    }


    private void CheckDBEvents(Object source, ElapsedEventArgs e)
    {

        //get data from db with matching queries
        List<Grocery> DataList = db.Grocery.Where(G => G.basic).Select(G => new Grocery
        {
            Id = G.Id,
            Timeout = G.Timeout
        }).ToList();

    }

}

method() 是 CheckDBEvents(),它的作用是访问 dbcontext 实例并查找一些数据以保存到名为 DataList 的本地常量变量

问题:每次我尝试将上下文 (Dbcontext) 实例(在 Controller 或任何其他类中)传递给 CheckDBEvents() 方法时,上下文都会被处置 -DbContext Dispose Exception。 调用者

var t = new Alarm(db);
t.StartTimerEvent();

我的轮胎:-

  • 将闹钟设置为静态类:

现在,如果我能做到这一点,那就太棒了......但无法对 DbContext 进行操作,因为您无法在静态类中调用 DbContext 上的实例,您必须从调用它的人处传递它,这会导致同样的问题:db 已被处理并且没有通过

        public static void StartTimerEvent(AppDbContext db)
    {
    .....

     // Hook up the Elapsed event for the timer. 
     aTimer.Elapsed += (source, e) => CheckDBEvents(source, e, db 
     //DbContext is Disposed here and
     //don't get passed'
     );

从我读到的内容来看,常量类和 Dbcontext 相处得也不太好。

长话短说 -我想将 dbContext 的实例保留在另一个类而不是 Controller 中。 没有被处置。

如果有人知道如何执行此操作或有服务器端计时器的源代码或类似内容,请发表评论,我已经被困了 2 天

最佳答案

经过多次测试终于发现了问题所在, 我需要利用 asp.net 强大的依赖注入(inject)功能,并将该类添加为服务。另外,我使用 IHostedService 作为我的服务类的接口(interface),这是服务 FinalTest 的示例(将 Alarm 重命名为 FinalTest)

internal class FinalTest : IHostedService, IDisposable
{
    
    private Timer aTimer;
    public static List<Grocery> List;
    private AppDbContext db;
    // variable  to test that timer really works
    public static int test2;
   

    public FinalTest( AppDbContext _db )
    {
        db = _db;

    }

    //This method runs at the start of the application once only as FinalTest was set as Singleton in services
    public Task StartAsync(CancellationToken cancellationToken)
    {
        test2 = 1;
        aTimer =new Timer(CheckDBEvents, null , TimeSpan.Zero , TimeSpan.FromSeconds(10) );
        return Task.CompletedTask;
    }

    //Method runs every TimeSpan.FromSeconds(10)
    private void CheckDBEvents(object state)
    {
        
        var users = from u in db.Grocery where u.basic == true select u;
        List = users.ToList();
        //increase test2 To see changes in the real world
        test2++;
    }


    //--------shutdown operations---------//
    public Task StopAsync(CancellationToken cancellationToken)
    {
        return Task.CompletedTask;
    }

    public void Dispose()
    {
        aTimer?.Dispose();
    }

    
}

现在,如果我将其注入(inject)到服务 services.AddSingleton(FinalTest) 中,我会得到一个作用域异常,因为在 Singleton 服务中使用 AppDbContext 是一个作用域服务,效果并不好,而且不能有效地促进AppDbContext 到 Singleton 这会在将来引起问题,所以我必须为 AppDbContext 创建另一个构造函数。

    public class AppDbContext : DbContext
{
    //Scoped constructor
    public AppDbContext(DbContextOptions<AppDbContext>  options) : base(options)
    {

    }

    //Singletone constructor
    public AppDbContext(DbContextOptions<AppDbContext> options,string connection)
    {
        connectionString = connection;
    }
    private string connectionString;
    //this is an override to OnConfiguring that's 
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
         
        if (connectionString != null)
        {
            var config = connectionString;
            optionsBuilder.UseSqlServer(config);
        }

        base.OnConfiguring(optionsBuilder);
    }
    //DbSet

    public DbSet<Grocery> Grocery { get; set; }

}

最后将 AppDbContextFinalTest 添加到服务

 var connection = @"Server=(localdb)\mssqllocaldb;Database=FridgeServer.AspNetCore.NewDb;Trusted_Connection=True;ConnectRetryCount=0";
 services.AddDbContext<AppDbContext>(
            options => {
                //options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))
                options.UseSqlServer(connection);
                //var config = Configuration["Data:DefaultConnection:ConnectionString"];

                //options.UseInMemoryDatabase("Grocery")
            }
        );

  services.AddSingleton<IHostedService,FinalTest>(s => new FinalTest(new AppDbContext(null, connection) ));

这就是我的经验,阅读有关依赖注入(inject)和 Ioc 以及其他编程概念和模式的所有内容都是一次有趣的经历 如果有人遇到其中一些问题,或者甚至想了解更多有关 ASP.NET 的信息,这里有一些帮助,第一个是最重要的

http://deviq.com/category/principles/ http://deviq.com/dependency-inversion-principle/ https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.1 Use DbContext in ASP .Net Singleton Injected Class https://blogs.msdn.microsoft.com/cesardelatorre/2017/11/18/implementing-background-tasks-in-microservices-with-ihostedservice-and-the-backgroundservice-class-net-core-2-x/

感谢@KienChu 告诉我有关 IHostedService 的信息,我希望这对某人有帮助

关于c# - 使用 DbContext 的服务器端计时器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49747931/

相关文章:

c# - 如果我有一个 Dispose 方法,我必须实现 IDisposable 吗?

asp.net - 以编程方式创建 .edmx 文件

c# - Entity Framework 6 错误无法加载指定的元数据资源

c# - 本地化 resx 文件中资源字符串的参数

jquery - 将字符串数组从 ASP.NET Web 服务返回到 jquery

entity-framework - 如何使用 EF CTP5 保存 ICollection<int>

c# - Umbraco - 计划发布问题 - v7.2.1

c# - ews 找不到领域的 KDC

c# - "[HandleError]"在类级别,在方法级别重写

jquery - Kendo Treeview 节点编辑/更新