我有一个WCF Web服务,目前遇到一些并发问题。目前负荷很小,但预计在未来几天会增加很多。
整体设置是WCF,实体框架6,依赖注入(Castle Windsor),UnitOfWork&存储库模式。
我设置了一个压力测试,并行地检查服务,我可以重新创建并发错误,例如......
已成功提交对数据库的更改,但更新对象上下文时发生错误。 ObjectContext可能处于不一致状态。内部异常消息:AcceptChanges无法继续,因为对象的键值与ObjectStateManager中的另一个对象冲突。在调用AcceptChanges之前,请确保键值是唯一的。
属性“ID”是对象密钥信息的一部分,无法修改。
从我所做的研究中,看起来我应该用LifestylePerWcfOperation注入我的DbContext。目前正在使用LifestyleTransient。
当我切换到LifestylePerWcfOperation并重新运行测试时,我每次都会得到这个:
所以我真的有两个问题:
以下是一些代码:
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 :(得分:1)
回答你的问题:
1)将生活方式改为LifestylePerWcfOperation
是正确的2)您正在UnitOfWork中部署DBContext。 DBContext由Windsor注入,因此Windsor将在其上调用Dispose。当使用windsor从不处理注入的对象时,只有使用工厂或Resolve创建对象时才必须释放(不处置)对象,因此Windsor可以处理它。
我希望使用LifeStylePerWcfOperations并删除Dispose代码,代码应运行正常。
祝你好运, Marwijn。答案 1 :(得分:0)
我能够解决这个问题。
修复正是Marwijn所说的。解决之后,我仍然遇到类似的错误。
最后的解决方法是每次注册并使其成为LifestylePerWcfOperation。我注册了一些使用寿命较短的对象,因此DbContext也被处理掉了这些对象。
如果有人收到此错误,并且您正在使用Castle / EF,请不要明确处理DbContext(让Castle执行此操作)并制作所有LifestylePerWcfOperation。那应该解决它。然后返回并有选择地重置您不希望成为LifestylePerWcfOperation的任何物品的生活方式,并确保它不会随着时间的推移而中断。