操作无法完成,因为 DbContext 已被释放 - LifestylePerWcfOperation

The operation cannot be completed because the DbContext has been disposed - LifestylePerWcfOperation

我的 WCF Web 服务目前遇到了一些并发问题。目前负载较小,但预计未来几天会增加很多。

整体设置是WCF,Entity Framework6,依赖注入(Castle Windsor),UnitOfWork & Repository Pattern。

我设置了一个并行命中服务的压力测试,我可以重新创建并发错误,例如....

根据我所做的研究,我似乎应该使用 LifestylePerWcfOperation 注入我的 DbContext。目前正在使用 LifestyleTransient 完成。

当我切换到 LifestylePerWcfOperation 并重新运行测试时,我每次都会得到这个:

所以我真的有两个问题:

  1. 我假设真正的解决方案是将我的 DbContext 切换到 LifestylePerWcfOperation 是否正确?
  2. 如果是这样,为什么我的 DbContext 被吞噬了?

这是一些代码:

AppStart.cs:

IocContainer.AddFacility<TypedFactoryFacility>();

IocContainer.Register(Component.For<IRepositoryFactory>().AsFactory());

IocContainer.Register(Component.For<IUnitOfWork>()
                               .ImplementedBy<UnitOfWork>)
                             /*.LifestylePerWcfOperation()*/);

IocContainer.Register(Component.For(typeof(IDbContext))
                               .ImplementedBy(dbContextType)
                               .DependsOn(Dependency.OnValue("connectionString", String.Format(ConfigurationManager.ConnectionStrings["---"].ConnectionString))));
                             /*.LifestylePerWcfOperation()*/

IocContainer.Register(Component.For(typeof(IRepository<>))
                               .ImplementedBy(typeof(Repository<>))
                               .LifestyleTransient()
                             /*.LifestylePerWcfOperation()*/);

// Register the actual dbContextType so consuming applications can access it without an interface
IocContainer.Register(Component.For(dbContextType)
                               .Named(dbContextType.Name)
                               .DependsOn(Dependency.OnValue("connectionString", String.Format(ConfigurationManager.ConnectionStrings["----"].ConnectionString)));
                             /*.LifestylePerWcfOperation()*/

UnitOfWork.cs:

public class UnitOfWork : IUnitOfWork
{
    private readonly IDbContext _dbContext;
    private bool _disposed;

    public UnitOfWork(IDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public int Commit()
    {
        return _dbContext.SaveChanges();
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (disposing)
            {
                _dbContext.Dispose();
            }

            _disposed = true;
        }
    }
}

Repository.cs

public class Repository<T> : IRepository<T> where T : class
{
    private readonly IDbSet<T> _dbset;

    public Repository(IDbContext dbContext)
    {
        _dbset = dbContext.Set<T>();
    }

    public IQueryable<T> Query()
    {
        return _dbset.AsQueryable();
    }

    public virtual IEnumerable<T> GetAll()
    {
        return _dbset.AsEnumerable();
    }

    public virtual void Add(T entity)
    {
        _dbset.Add(entity);
    }

    public virtual void Delete(T entity)
    {
        _dbset.Remove(entity);
    }

    public virtual void Delete(ICollection<T> entities)
    {
        entities.ToList().ForEach(Delete);
    }
}

如果需要,我可以添加更多代码。感谢您提供的任何帮助!!

回答您的问题:

1) 您将生活方式更改为 LifestylePerWcfOperation 是正确的

2) 您正在从 UnitOfWork 中处理 DBContext。 DBContext 由 Windsor 注入,因此 Windsor 将对其调用 Dispose。使用 windsor 时,永远不要处置注入的对象,只有当您使用工厂或 Resolve 创建了一个对象时,您才必须释放(而不是处置)该对象,以便 Windsor 可以处置它。

我希望通过 LifeStylePerWcfOperations 和删除 Dispose 代码,代码应该 运行 没问题。

祝你好运, 马尔维恩.

我能够解决这个问题。

修复正是 Marwijn 提到的。修复后,我仍然遇到类似的错误。

最后的修复是获取每一个注册并使其成为 LifestylePerWcfOperation。我注册了一些生命周期较短的对象,因此 DbContext 也被这些对象处理掉了。

如果有人遇到此错误,并且您正在使用 Castle/EF,请不要显式处置 DbContext(让 Castle 执行)并使所有内容都成为 LifestylePerWcfOperation。那应该解决它。然后返回并有选择地重置您不想成为 LifestylePerWcfOperation 的任何对象的生活方式,并确保它不会在您进行时中断。