0

我有一个WCF Web服务,目前遇到一些并发问题。目前负载很小,但预计在未来几天内会增加很多。该操作无法完成,因为DbContext已处理 - LifestylePerWcfOperation

整体设置是WCF,实体框架6,依赖注入(Castle Windsor),UnitOfWork &存储库模式。

我设置的是打服务并行,我可以重新并发性错误,例如压力测试....

  • 同时提交数据库事务,但它不能在是否决定报告了错误事务在数据库服务器上成功或失败。
  • 对数据库的更改已成功提交,但更新对象上下文时发生错误。 ObjectContext可能处于不一致的状态。内部异常消息:由于对象的键值与ObjectStateManager中的另一个对象冲突,因此AcceptChanges无法继续。在调用AcceptChanges之前确保键值是唯一的。

  • 属性“ID”是对象的关键信息的一部分,无法修改。

从我所做的研究,它看起来像我应该注入我的DbContext与LifestylePerWcfOperation。目前正在使用LifestyleTransient完成。

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

  • 因为的DbContext已经布置

操作无法完成,所以,我真的有2个问题:

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

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

+0

您的DBContext注册并未指定生活方式,因此Windsor的默认设置将适用:Singleton。这肯定会造成问题。 –

回答

1

在回答你的问题:

1)你是在改变生活方式LifestylePerWcfOperation

2)你是从的UnitOfWork内设置了正确的DbContext。 DBContext由Windsor注入,因此Windsor将对其调用Dispose。当使用windsor时,永远不要处理注入的对象,只有当你使用工厂创建对象或解析时,你必须释放(不处理)对象,所以Windsor可以处置它。

我期望与LifeStylePerWcfOperations和删除Dispose代码,代码应该运行良好。

祝你好运, Marwijn。

+0

谢谢Marwijn!这确实是第一步。我还需要在代码中进行一些其他更改,这些更改未在此处发布 –

0

我能够解决这个问题。

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

最终的解决方案是采取每一次注册并使其成为LifestylePerWcfOperation。我有一些使用寿命较短的对象注册,所以DbContext也与这些对象一起处理。

如果有人得到这个错误,并且你正在使用Castle/EF,不要显式地处理DbContext(让Castle做它)并且做一切LifestylePerWcfOperation。这应该解决它。然后返回并有选择地重置您不想成为LifestylePerWcfOperation的任何物品的生活方式,并确保它不会随着您的行进而中断。

相关问题