使用异步存储库模式 - 无法访问已处置的对象
Posted
技术标签:
【中文标题】使用异步存储库模式 - 无法访问已处置的对象【英文标题】:Using async Repository pattern - Cannot access a disposed object 【发布时间】:2020-01-17 00:48:06 【问题描述】:我正在尝试实现异步存储库模式并希望异步更新:
我的控制器如下所示:
// PUT api/category
[HttpPut]
public void Put([FromBody] CategoryDto categoryDto)
var category = _mapper.Map<Categories>(categoryDto);
_categoryService.UpdateCategory(category);
我的RepositotyBase<T>
班级:
public abstract class RepositoryBase<T> where T : class
public virtual async Task Update(T entity)
// This code throws error: Cannot access a disposed object. A common
// cause of this error is disposing ...
await Task.Run(() => // I have **await** here
dbSet.Attach(entity);
shopContext.Entry(entity).State = EntityState.Modified;
);
我的CategoryService
:
public class CategoryService : ICategoryService
public async Task UpdateCategory(Categories category)
await _categoryRepository.Update(category); // I have **await** here
_unitOfWork.Commit();
return;
但是,RepositoryBase<T>
的方法 public virtual async Task Update(T entity)
的异步实现会抛出错误:
public abstract class RepositoryBase<T> where T : class
public virtual async Task Update(T entity)
// This code throws error: Cannot access a disposed object. A common
// cause of this error is disposing ...
await Task.Run(() =>
dbSet.Attach(entity); // I have **await** here
shopContext.Entry(entity).State = EntityState.Modified;
);
无法访问已处置的对象。此错误的常见原因是 处理从依赖注入解决的上下文和 然后稍后尝试在您的其他地方使用相同的上下文实例 应用。如果您在 上下文,或将上下文包装在 using 语句中。如果你是 使用依赖注入,你应该让依赖注入 容器负责处理上下文实例。
更新: 它是正确的异步实现吗?
我的控制器:
// PUT api/category
[HttpPut]
public void Put([FromBody] CategoryDto categoryDto)
var category = _mapper.Map<Categories>(categoryDto);
_categoryService.UpdateCategory(category);
我的通用存储库:
public abstract class RepositoryBase<T> where T : class
public virtual async Task Update(T entity)
dbSet.Attach(entity);
shopContext.Entry(entity).State = EntityState.Modified;
我的工作单位:
public class UnitOfWork : IUnitOfWork
private readonly IDbFactory dbFactory;
private StoreEntities dbContext;
public UnitOfWork(IDbFactory dbFactory)
this.dbFactory = dbFactory;
public StoreEntities DbContext
get return dbContext ?? (dbContext = dbFactory.Init());
public async Task CommitAsync()
//DbContext.Commit();
await DbContext.SaveChangesAsync();
我的服务:
public class CategoryService : ICategoryService
public async Task UpdateCategory(Categories category)
_categoryRepository.Update(category); // I have **await** here
await Task.Run(()=> _unitOfWork.Commit()); //
return;
【问题讨论】:
【参考方案1】:您需要设置您的控制器操作PUT api/category
以了解异步/等待。
@mjwills 在 cmets 中提到了这一点。
// PUT api/category
[HttpPut]
public async Task Put([FromBody] CategoryDto categoryDto)
var category = _mapper.Map<Categories>(categoryDto);
await _categoryService.UpdateCategory(category);
// you probably want to set a response code. e.g return OK()
这有点离题,但我正在讨论其他一些 cmets。
您还需要将更改保存到 EF 中的数据库。您不需要手动创建自己的任务。据我所知,EF 为您提供了一个SaveChangesAsync
方法:https://docs.microsoft.com/en-us/ef/core/saving/async。
public abstract class RepositoryBase<T> where T : class
public virtual async Task Update(T entity)
dbSet.Attach(entity);
shopContext.Entry(entity).State = EntityState.Modified;
await shopContext.SaveChangesAsync();
public class CategoryService : ICategoryService
public async Task UpdateCategory(Categories category)
return await _categoryRepository.Update(category);
【讨论】:
这还不够。其余代码也需要紧急清理,因为它不会异步执行任何操作。事实上,它并没有保存任何东西,它只是修改了 DbContext 而不保存更改 如果我们假设对SaveChanges
或SaveChangesAsync
的实际调用是在_uow.Commit
内部进行的,UpdateCategory
仍然会阻塞
@PanagiotisKanavos 你能写出正确的版本吗?我真的很难弄清楚应该如何编写正确的实现。我只是被告知我做错了,还有一件事做错了。请告诉我我应该写什么。
@Oliver 谢谢,点赞。我的个人电脑离我很远。对不起。稍后当我可以访问个人计算机时,我会写下结果。
@PanagiotisKanavos 我同意还有一些其他项目可以使用寻址,但我试图直接回答手头的问题。我想也许这段代码是来自一个更好的解决方案的sn-ps。以上是关于使用异步存储库模式 - 无法访问已处置的对象的主要内容,如果未能解决你的问题,请参考以下文章
C#:使用 IQueryable 注入 DbContext 时,无法访问 ASP.NET Core 中的已处置对象
System.ObjectDisposedException:'无法访问已处置的对象。对象名称:'OracleConnection'。'