【问题标题】:Context has been disposed. Execute Async上下文已被处理。执行异步
【发布时间】:2020-07-23 02:57:43
【问题描述】:

使用实体框架异步执行对 Web api 的查询存在问题。 一般视图,例如请求发送到 API,ActionFilter 捕获请求到控制器的功能,使用响应键发送到客户端状态 ok,执行请求异步并在 SignalR 发送数据后。 ActionFilter 像这样开始异步执行:

HostingEnvironment.QueueBackgroundWorkItem(async (ct) =>
{
    var response = await actionContext.ActionDescriptor.ExecuteAsync(actionContext.ControllerContext,
    actionContext.ActionArguments, ct);
    var data = new JavaScriptSerializer().Serialize(response);
    await connectionContext.Connection.Send(connectionId, $"{requestKey};{data}");
});

控制器:

[HttpPost]
[Route("")]
public ICollection<TradeAccountModel> GetAll()
{
    using (var ls = _lifetimeScope.BeginLifetimeScope())
    {
        return _tradeAccountService.GetAll();
    }
}

服务:

public ICollection<TradeAccountModel> GetAll()
{
    using (_tradeAccountRepository.BeginTransaction())
    {
        return _tradeAccountRepository.Get().Select(acc => acc.ToModel());
    }
}

Respository 使用 UOW 模式。 并且当存储库尝试从 DB 获取数据时出现错误:System.InvalidOperationException: The operation cannot be completed because the DbContext has been released.

TDataRepository包含常用操作并扩展BaseDataRespository,如GetById等

public interface ITradeRepository: ITDataRepository<TradeAccount>
{
}

internal class TradeRepository : T1DataRepository<TradeAccount>,
    ITradeRepository
{

}



IEnumerable<TEntity> ITDataRepository<TEntity>.Get()
    {
        return base.Get<TEntity>();
    }

BaseDataRespository 有 BeginTransaction 方法

public IDisposable BeginTransaction()
    {
        if (_scope == null)
        {
            _scope = new TransactionScope(
                TransactionScopeOption.Required,
                new TransactionOptions()
                {
                    IsolationLevel = IsolationLevel.ReadCommitted,
                    Timeout = TimeSpan.FromSeconds(300)
                },
                TransactionScopeAsyncFlowOption.Enabled);
        }

        return _scope;
    }

上下文由 BaseDataRespository 创建

private TransactionScope _scope;
    private readonly Lazy<DataContext> _contextFactory;

    private DataContext Context => _contextFactory.Value;

    public BaseDataRepository()
    {
        _contextFactory = new Lazy<DataContext>(()=> 
        {
            var ctx = CreateContext();

            ctx.FireBuild += Build;

            return ctx;
        });
    }

【问题讨论】:

  • 能发一下_tradeAccountRepository的实现吗?
  • 是的,我已经编辑过帖子
  • 我不明白你为什么需要使用QueueBackgroundWorkItem。很可能它会导致你得到异常。因为您在操作过滤器中,并且您正在尝试执行操作结果手动操作,但是当 BackgroundWorker 运行您的代码时,该操作可能已经完成。
  • 我要问和@Eldar 一样的问题。您是否正在执行动作过滤器中的另一个动作?
  • 因为请求多,计算时间长

标签: c# asp.net entity-framework asynchronous action-filter


【解决方案1】:

如果您的DbContext 注册为范围服务/HTTP 请求范围服务,则应避免将DbContext 从请求管道传递到后台任务。

这是因为根据docs:

安排一个可以在后台运行的任务,独立于任何请求。

任何同时实现IDisposable 的作用域服务都将在请求完成后自动释放。

您应该在控制器操作/请求管道中使用独立范围激活新的DbContext,并将其传递给您的后台任务。

docs 适用于 .Net Core,但它可能会让您了解如何在后台任务中使用作用域服务。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-12-16
    • 1970-01-01
    • 1970-01-01
    • 2016-09-22
    • 2011-03-03
    • 1970-01-01
    • 2010-11-21
    相关资源
    最近更新 更多