【问题标题】:How to use ApplicationDbContext in a Class / Separate Thread ASP.Net Core如何在类/单独的线程 ASP.Net Core 中使用 ApplicationDbContext
【发布时间】:2019-05-28 01:33:01
【问题描述】:

我正在尝试让一个单独的线程启动一个循环过程,以从 api 调用收集和导入数据并将其插入本地数据库。我尝试以与在控制器中相同的方式创建数据库连接,但它不断给我各种错误。

我尝试了多种方法。对于下面的设置,它给了我这个错误:

System.ObjectDisposedException: '无法访问已处置的对象。此错误的一个常见原因是释放从依赖注入中解析的上下文,然后尝试在应用程序的其他地方使用相同的上下文实例。如果您在上下文上调用 Dispose() 或将上下文包装在 using 语句中,则可能会发生这种情况。如果你使用依赖注入,你应该让依赖注入容器负责处理上下文实例。'

此设置用于测试目的。

    public class HomeController : Controller
    {
        public ApplicationDbContext db;

        public HomeController(ApplicationDbContext context)
        {
            db = context;
        }

        public IActionResult Index()
        {
            // This executes the code and inserts the test row no problem.
            BinanceData binanceData = new BinanceData();
            binanceData.Symbol = "Test";
            binanceData.RealTime = DateTime.Now;
            db.BinanceData.Add(binanceData);
            db.SaveChanges();
            // End

            // Where I create the new thread and start the process
            Thread doThis = new Thread(delegate ()
            {
                DataCollection dataCollection = new DataCollection(db);
                dataCollection.InsertData(DateTime.Now);
            });
            doThis.Start();
            // End

            return View();
        }
    }

这是我尝试创建连接(或传递现有连接)并开始循环并收集/插入数据的类。

    public class DataCollection
    {
        public ApplicationDbContext db;

        public DataCollection(ApplicationDbContext context)
        {
            db = context;
        }

        public void InsertData(DateTime nextTime)
        {
            List<string> tokens = new List<string> { "ETHBTC", "LTCBTC", "BNBBTC", "NEOBTC", "GASBTC", "BTCUSDT", "MCOBTC", "WTCBTC", "LRCBTC", "QTUMBTC", "YOYOBTC", "OMGBTC", "ZRXBTC", "STRATBTC", "SNGLSBTC", "BQXBTC", "KNCBTC", "FUNBTC", "SNMBTC", "IOTABTC", "LINKBTC", "XVGBTC", "SALTBTC", "MDABTC", "MTLBTC", "SUBBTC", "EOSBTC", "SNTBTC", "ETCBTC", "MTHBTC", "ENGBTC", "DNTBTC", "ZECBTC", "BNTBTC", "ASTBTC", "DASHBTC", "OAXBTC", "BTGBTC", "EVXBTC", "REQBTC", "VIBBTC", "TRXBTC", "POWRBTC", "ARKBTC", "XRPBTC", "MODBTC", "ENJBTC", "STORJBTC", "KMDBTC", "RCNBTC", "NULSBTC", "RDNBTC", "XMRBTC", "DLTBTC", "AMBBTC", "BATBTC", "BCPTBTC", "ARNBTC", "GVTBTC", "CDTBTC", "GXSBTC", "POEBTC", "QSPBTC", "BTSBTC", "XZCBTC", "LSKBTC", "TNTBTC", "FUELBTC", "MANABTC", "BCDBTC", "DGDBTC", "ADXBTC", "ADABTC", "PPTBTC", "CMTBTC", "XLMBTC", "CNDBTC", "LENDBTC", "WABIBTC", "TNBBTC", "WAVESBTC", "GTOBTC", "ICXBTC", "OSTBTC", "ELFBTC", "AIONBTC", "NEBLBTC", "BRDBTC", "EDOBTC", "WINGSBTC", "NAVBTC", "LUNBTC", "APPCBTC", "VIBEBTC", "RLCBTC", "INSBTC", "PIVXBTC", "IOSTBTC", "STEEMBTC", "NANOBTC", "VIABTC", "BLZBTC", "AEBTC", "NCASHBTC", "POABTC", "ZILBTC", "ONTBTC", "STORMBTC", "XEMBTC", "WANBTC", "WPRBTC", "QLCBTC", "SYSBTC", "GRSBTC", "CLOAKBTC", "GNTBTC", "LOOMBTC", "REPBTC", "TUSDBTC", "ZENBTC", "SKYBTC", "CVCBTC", "THETABTC", "IOTXBTC", "QKCBTC", "AGIBTC", "NXSBTC", "DATABTC", "SCBTC", "NPXSBTC", "KEYBTC", "NASBTC", "MFTBTC", "DENTBTC", "ARDRBTC", "HOTBTC", "VETBTC", "DOCKBTC", "POLYBTC", "PHXBTC", "HCBTC", "GOBTC", "PAXBTC", "RVNBTC", "DCRBTC", "USDCBTC", "MITHBTC", "BCHABCBTC" };

            foreach (string token in tokens)
            {
                BinanceData binance = new BinanceData();
                using (var client = new BinanceClient())
                {
                    var data = client.GetKlines(token, Binance.Net.Objects.KlineInterval.OneMinute, null, null, 2);
                    var kline = data.Data[0];
                    binance.Symbol = token;
                    binance.Close = kline.Close;
                    binance.CloseTime = kline.CloseTime;
                    binance.High = kline.High;
                    binance.Low = kline.Low;
                    binance.Open = kline.Open;
                    binance.OpenTime = kline.OpenTime;
                    binance.QuoteAssetVolume = kline.QuoteAssetVolume;
                    binance.TakerBuyBaseAssetVolume = kline.TakerBuyBaseAssetVolume;
                    binance.TakerBuyQuoteAssetVolume = kline.TakerBuyQuoteAssetVolume;
                    binance.TradeCount = kline.TradeCount;
                    binance.Volume = kline.Volume;
                    binance.RealTime = DateTime.Now;
                }
            db.BinanceData.Add(binance);
            db.SaveChanges();
            }
            CountUntilNextMin(nextTime);
        }

        public void CountUntilNextMin(DateTime nextTime)
        {
            while (DateTime.Now < nextTime)
            {
                System.Threading.Thread.Sleep(10000);
            }
            DateTime passTime = DateTime.Now.AddMinutes(1);
            InsertData(passTime);
        }
    }

这是我的 ApplicationDbContext 类

    public class ApplicationDbContext : IdentityDbContext
    {
        public DbSet<ApplicationUser> ApplicationUsers { get; set; }
        public DbSet<BinanceData> BinanceData { get; set; }
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
            : base(options)
        {
        }

        public ApplicationDbContext()
            : base()
        {
        }
    }

还有我的 StartUp.cs ConfigureServices 方法

    public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<CookiePolicyOptions>(options =>
        {
            // This lambda determines whether user consent for non-essential cookies is needed for a given request.
            options.CheckConsentNeeded = context => true;
            options.MinimumSameSitePolicy = SameSiteMode.None;
        });

        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));
        services.AddIdentity<IdentityUser, IdentityRole>()
            .AddDefaultUI()
            .AddDefaultTokenProviders()
            .AddEntityFrameworkStores<ApplicationDbContext>();

        services.AddMvc()
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    }

【问题讨论】:

    标签: c# entity-framework asp.net-core .net-core ef-code-first


    【解决方案1】:

    默认情况下,您的 DI 容器将 DbContext 范围限定为请求。如果您想在长时间运行的后台进程中使用它,只需直接创建它即可。例如:

    Thread doThis = new Thread(delegate ()
    {
        using (var db = new ApplicationDbContext())
        {
          DataCollection dataCollection = new DataCollection();
          dataCollection.InsertData(DateTime.Now);
        }
    });
    

    需要配置 DbContext,最简单的方法是重写 OnConfiguring 以连接到您的数据库。至少,像这样:

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
          optionsBuilder.UseSqlServer("Server=YourServer;Database=YourDatabase;Trusted_Connection=True;MultipleActiveResultSets=true");
    }
    

    虽然您可能希望从配置中读取连接字符串。

    【讨论】:

    • 大卫谢谢你。 Thread doThis = new Thread(delegate () { using (var db = new ApplicationDbContext()) { DataCollection dataCollection = new DataCollection(db); dataCollection.InsertData(DateTime.Now); } }); 我得到 System.InvalidOperationException: '没有为此 DbContext 配置数据库提供程序。可以通过覆盖 DbContext.OnConfiguring 方法或在应用程序服务提供者上使用 AddDbContext 来配置提供者
    • 需要为您的 DbContext 提供配置。见docs.microsoft.com/en-us/ef/core/miscellaneous/…
    • 我一直试图解决这个问题,但没有运气。您能否说明这是如何完成的,以便我将您的答案标记为答案?
    • 你是真正的救星!我把它放在我的 ApplicationDbContext 中。谢谢大卫新年快乐!
    • 长时间保持 DbContext 打开是一种非常糟糕的做法。不要那样做!
    【解决方案2】:

    我通过调用 CreateScope 来尝试一下

    public static async Task InitializeDatabaseAsync(IServiceProvider serviceProvider, IHostingEnvironment env)
    {
        var result = false;
    
        using (var scope1 = serviceProvider.CreateScope())
        using (var db1 = scope1.ServiceProvider.GetService<MainContext>())
        {
             result = await db1.Database.EnsureCreatedAsync();
            if (result)
            {
    
                InsertTestData(serviceProvider, env);
            }
        }
    }
    

    然后

    using (var scope = serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope())
    using (var db = scope.ServiceProvider.GetService<MainContext>())
    {
        existingData = db.Set<TEntity>().ToList();
    }
    

    【讨论】:

      猜你喜欢
      • 2019-03-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-02
      • 2019-10-13
      • 2021-07-11
      相关资源
      最近更新 更多