【问题标题】:How to fix DbContext has been disposed for an async scenario?如何修复 DbContext 已针对异步场景进行处理?
【发布时间】:2018-06-15 21:16:40
【问题描述】:

我们已将我们的应用程序从 NserviceBus v5 升级到 v6,之后我们遇到了重大问题,大部分时间都收到以下错误。

操作无法完成,因为 DbContext 已被 弃置。

在我们加载到系统之前并不明显。

我们正在使用八个并发线程运行,因此我们收到上述错误。

public class EndpointInitializer
{
    public void Initialize(IKernel container)
    {
        var endpointConfiguration = new EndpointConfiguration("MyEndpoint");
        endpointConfiguration.UseContainer<NinjectBuilder>(
            customizations => { customizations.ExistingKernel(container); });
 //More settings...
    }
}

.

public class MyMessageHandler : IHandleMessages<MyCommand>
{
    private readonly IPersonRepository _personRepository;
    public MyMessageHandler(IPersonRepository personRepository)
    {
        _personRepository = personRepository;
    }
    public async Task Handle(MyCommand message, IMessageHandlerContext context)
    {
        var person = await _personRepository.GetByIdentifierAsync(message.Identifier).ConfigureAwait(false);
        //More code...
        await _personRepository.UpdateAsync(person);
    }
}

[Serializable]
public class MyCommand
{
    public string Identifier { get; set; }
}

.

public class DependencyRegistrar
{
    public IKernel Container { get; set; }
    public void Create()
    {
        Container = new StandardKernel();
        RegisterTypes(Container);
    }
    public void RegisterTypes(IKernel kernel)
    {
        kernel.Bind<IPersonRepository>().To<PersonRepository>();
        kernel.Bind<DbContext>().To<MyDbContext>().InThreadScope();
        //More registrations...
    }
}

public class MyDbContext : DbContext
{
    public MyDbContext() : base("MyConn")
    {
    }
}

public interface IPersonRepository
{
    Task<Person> GetByIdentifierAsync(string identifier);
    Task UpdateAsync(Person entity);
    //More methods...
}

public class PersonRepository : IPersonRepository
{
    private readonly DbContext _dbContext;
    public PersonRepository(DbContext dbContext)
    {
        _dbContext = dbContext;
    }
    public async Task<Person> GetByIdentifierAsync(string identifier)
    {
        var personList = await _dbContext.Set<Person>().Where(x => x.Identifier == identifier).ToListAsync().ConfigureAwait(false);
        //More code... 
        return personList.SingleOrDefault();
    }
    public async Task UpdateAsync(Person entity)
    {
        //More code...
        await _dbContext.SaveChangesAsync().ConfigureAwait(false);
    }
}

public class Person
{
    public int Id { get; set; }
    public string Identifier { get; set; }
    //More properties...
}

我们注意到一个可行的选项是使用 Particulars 示例来获取 DataContext 以使用 UnitOfWorkSetupBehavior。但它不太适合我们的场景,因为我们有一个复杂的设置,服务和存储库在整个应用程序的构造函数中注入 DbContext。

即,目前的(部分)解决方案是调用存储库上的方法,例如;

    var person = await _personRepository.GetByIdentifierAsync(context.DataContext(), message.Identifier).ConfigureAwait(false);

但是现在,当我们运行更复杂的场景时,这还不够。

那么,我们缺少什么?这里真正的问题是什么?

【问题讨论】:

  • 好的。您只是在说我自己意识到的,但是由于这是与 ioc 一起使用的常见模式,我应该怎么想?我不想在我的句柄中使用新的存储库创建我的存储库??这是唯一的方法吗?
  • 您想试试discuss.particular.net 还是发送电子邮件至support@particular.net?
  • @SeanFarmar,是的,我之前已经与他们联系过。但看起来丹尼尔斯的回答似乎解决了我的问题。只需在将其标记为解决方案之前确保它是这种情况。

标签: c# entity-framework-6 ninject repository-pattern nservicebus


【解决方案1】:

Ninject PerThreadScope 使用 System.Threading.Thread.CurrentThread。使用 async 后,线程可能会在每次延续时发生变化(await 语句之后的代码)。您可以使用a custom named scopeasync local scope 或使用NServiceBus.Ninject 中的InUnitOfWorkScope

【讨论】:

  • 这个问题是 ninject 特有的吗?还是其他容器有同样的问题?
  • 任何容器都可能遇到该问题,具体取决于何时结合异步解决依赖关系。在异步世界中,您必须围绕任务构建代码并且必须忘记线程。任何绑定到线程概念的构造(例如 ThreadLocal)都可能表现出意外,因为对于每个延续,另一个线程可以接手任务。因此,绑定到线程的 IoC 范围在使用异步时是危险的,除非您可以保证在解析层次结构时一切都已解决,并且没有任何东西被延迟解析。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-11-12
  • 2013-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-31
  • 2021-12-06
相关资源
最近更新 更多