如何在 Class / 单独线程 ASP.Net 核心中使用 ApplicationDbContext

How to use ApplicationDbContext in a Class / Separate Thread ASP.Net Core

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

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

System.ObjectDisposedException: 'Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.'

此设置用于测试目的。

    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();
        }
    }

这是我尝试创建连接(或传递现有连接)并开始循环和 collect/insert 数据的 class。

    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 Class

    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);
    }

默认情况下,您的 DI 容器将 DbContext 的范围限定为请求。如果你想在一个long-运行的后台进程中使用,直接创建即可。例如:

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");
}

尽管您可能希望从您的配置中读取连接字符串。

我通过调用 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();
}