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的任何物品的生活方式,並確保它不會隨着您的行進而中斷。

相關問題