无法访问ASP.NET Core后台服务中的已处置对象

时间:2019-03-15 09:23:55

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

我试图找出为什么我的数据库上下文被下面的代码所取代。我正在尝试在整个处理阶段更新记录的状态,但是在尝试将更改保存到htis实体的状态字段时遇到了异常。

如果我在.SaveChanges()或.FirstOrDefault()调用中使用异步或非异步方法,则没有区别。

此注册为由IHostedService运行

IHostedService:

bin/hive --hiveconf hive.root.logger=INFO,DAILY //for HiveCLI (deprecated)
bin/hiveserver2 --hiveconf hive.root.logger=INFO,DAILY

后台服务:

public class HostedDaemon : IHostedService
{
    private readonly ILogger<HostedDaemon> _logger;
    private Timer _queueTimer;
    private Timer _runTimer;
    private IServiceProvider Services { get; set; }

    public HostedDaemon(IServiceProvider services, ILogger<HostedDaemon> logger)
    {
        Services = services;
        _logger = logger;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        var queueAutoEvent = new AutoResetEvent(false);
        _logger.LogInformation("HostedDaemon Starting");
        _queueTimer = new Timer(QueueJobs, queueAutoEvent, TimeSpan.Zero,
            TimeSpan.FromSeconds(900));
        _runTimer = new Timer(RunQueuedJobs, queueAutoEvent, TimeSpan.Zero,
            TimeSpan.FromSeconds(10));
        return Task.CompletedTask;
    }
    public Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("HostedDaemon Stopping");
        _queueTimer?.Change(Timeout.Infinite, 0);
        _runTimer?.Change(Timeout.Infinite, 0);
        return Task.CompletedTask;
    }
    public void Dispose()
    {
        _queueTimer?.Dispose();
        _runTimer?.Dispose();
    }

    private void QueueJobs(object stateInfo)
    {
        using (var scope = Services.CreateScope())
        {
            var autoEvent = (AutoResetEvent)stateInfo;
            var daemonProcessing = scope.ServiceProvider.GetRequiredService<IDaemonService>();
            //daemonProcessing.QueueJob();
            //daemonProcessing.RunJob();
            autoEvent.Set();
        }
    }
    private void RunQueuedJobs(object stateInfo)
    {
        using (var scope = Services.CreateScope())
        {
            var autoEvent = (AutoResetEvent)stateInfo;
            var daemonProcessing = scope.ServiceProvider.GetRequiredService<IDaemonService>();
            //daemonProcessing.QueueJob();
             daemonProcessing.RunJob(); 
            autoEvent.Set();
        }
    }
}

例外:

    public async Task RunJob()
    {
        try
        {
            _logger.LogInformation("Starting transaction processing");
            //TODO: Hook up SP
            var nextQueuedJob = _context.Transaction
                .Where(x => x.TransactionStatusId == (int) TransactionStatus.Queued).OrderBy(x => x.QueuedTime)
                .Include(x => x.BrokerageData).FirstOrDefault();

            if (nextQueuedJob != null)
            {
                nextQueuedJob.TransactionStatusId = (int)TransactionStatus.ProcessingData;
                _context.Transaction.Update(nextQueuedJob);
                //await _context.SaveChangesAsync();
                var brokerageData = nextQueuedJob.BrokerageData.FirstOrDefault();
                var order = JsonConvert.DeserializeObject<OrderShort>(brokerageData.BrokerageContent);

                var dynamicsSalesOrder = await CreateNewSalesOrderShort(order);
                var salesOrderLines = new List<SalesOrderLineShort>();
                foreach (var orderItem in order.Items)
                {
                    var unitPrice = (orderItem.SubTotal + orderItem.Tax)/orderItem.Quantity;
                    var salesOrderLine = new SalesOrderLineShort
                    {
                        ItemId = new Guid("42dd99ff-7133-41f7-88c5-81f922ef77dd"),
                        LineType = "Item",
                        Description = orderItem.ProductDescription,
                        UnitOfMeasureId = new Guid("cab0928b-e7af-4bd6-923f-3706b4761681"),
                        UnitPrice = unitPrice,
                        DiscountAmount = orderItem.CouponDiscountAmount,
                        Quantity = orderItem.Quantity,
                        TaxCode = "DEV"
                    };
                    salesOrderLines.Add(salesOrderLine);
                }
                nextQueuedJob.TransactionStatusId = (int)TransactionStatus.ProcessingComplete;
                await _context.SaveChangesAsync();

                nextQueuedJob.TransactionStatusId = (int)TransactionStatus.ReadyForTransfer;
                //TOOO: hook into reconciliation tables to commit an update 
                nextQueuedJob.TransactionStatusId = (int)TransactionStatus.TransferringData;

                foreach (var salesOrderLine in salesOrderLines)
                {

                    await _requestClient.PostRequest(
                        $"https://api.businesscentral.dynamics.com/v1.0/afff8eda-37c9-4c72-833b-a36dc6c8d5df/api/beta/companies/c7fdd45d-617d-47b3-adbe-7c0c69c21dd1/salesOrders/{dynamicsSalesOrder.Id}/salesOrderLines",
                        salesOrderLine);
                }

                nextQueuedJob.TransactionStatusId = (int)TransactionStatus.TransferComplete;

                nextQueuedJob.TransactionStatusId = (int)TransactionStatus.ReadyForValidation;
                nextQueuedJob.TransactionStatusId = (int)TransactionStatus.ValidatingOriginData;
                var query = new CrmQuery();
                query.UpdateOrderStatus(order.SalesOrderId, CrmQuery.OrderFIStatus.Completed,
                    order.FI_LastModified);
                nextQueuedJob.TransactionStatusId = (int)TransactionStatus.TransactionCompleted;
            }
        }
        catch (Exception e)
        {
            _logger.LogError($"exception occurred while running job.\n{e.InnerException}");
        }

    }

启动配置:

Message "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.\r\nObject name: 'FisEntities'."  string

1 个答案:

答案 0 :(得分:2)

RunQueuedJobs类的HostedDaemon方法中,将daemonProcessing.RunJob();替换为daemonProcessing.RunJob().Wait();,如下所示:

private void RunQueuedJobs(object stateInfo)
{
    using (var scope = Services.CreateScope())
    {
        var autoEvent = (AutoResetEvent)stateInfo;
        var daemonProcessing = scope.ServiceProvider.GetRequiredService<IDaemonService>();
        //daemonProcessing.QueueJob();
         daemonProcessing.RunJob().Wait(); // <-- Here it is
        autoEvent.Set();
    }
}

现在它应该可以正常工作了。