C#:使用 IQueryable 注入 DbContext 时,无法访问 ASP.NET Core 中的已处置对象
Posted
技术标签:
【中文标题】C#:使用 IQueryable 注入 DbContext 时,无法访问 ASP.NET Core 中的已处置对象【英文标题】:C#: Cannot access a disposed object in ASP.NET Core when injecting DbContext with IQueryable 【发布时间】:2020-10-21 03:53:04 【问题描述】:我收到以下错误。目前遵循 Async/await 模式并使用 IServiceScopeFactory。尝试将 Repo 与 IQueryable 链接。
接收错误如下:
无法访问已处置的对象。此错误的一个常见原因是释放从依赖注入中解析的上下文,然后尝试在应用程序的其他地方使用相同的上下文实例。如果您在上下文上调用 Dispose() 或将上下文包装在 using 语句中,则可能会发生这种情况。如果你使用依赖注入,你应该让依赖注入容器负责处理上下文实例。 对象名称:'PropertyContext'。
存储库:
public class AddressRepository
private readonly IServiceScopeFactory _factory;
public AddressRepository(IServiceScopeFactory factory) : base(factory)
_factory = factory;
[EnableQuery]
public IQueryable<LkAddressType> GetAddressTypes()
using (var scope = _factory.CreateScope())
var db = scope.ServiceProvider.GetService<PropertyContext>();
return db.LkAddressType.AsNoTracking();
应用服务:
public async Task<AddressTypeResponse> GetAddressTypes()
var data = await (_addressRepository.GetAddressTypes()).ToListAsync();
var mapped = _mapper.Map<ICollection<AddressTypeModel>>(data);
var dto = _mapper.Map<ICollection<AddressTypeDto>>(mapped);
return new AddressTypeResponse Body = dto;
控制器:
[HttpGet("AddressType")]
public async Task<ActionResult<AddressTypeResponse>> GetAddressTypes()
return Ok(await _service.GetAddressTypes());
目前使用 Net Core 2.2、Entity Framework Core 和 OData。
【问题讨论】:
【参考方案1】:作用域会自动释放它创建的实现IDisosable
的作用域(和瞬态)对象,因此当GetAddressTypes
结束时,scope
和db
将被释放。因此,您要么需要返回一些客户端将处理的包装器,要么具体化查询并从方法返回结果:
[EnableQuery]
public Task<List<LkAddressType>> GetAddressTypes()
using (var scope = _factory.CreateScope())
var db = scope.ServiceProvider.GetService<PropertyContext>();
return await db.LkAddressType.AsNoTracking().ToListAsync();
或者将您的上下文直接注入到存储库中,让框架确定范围:
public class AddressRepository
private readonly PropertyContext _ctx;
public AddressRepository(PropertyContext ctx,IServiceScopeFactory factory) : base(factory)
_ctx= ctx;
[EnableQuery]
public IQueryable<LkAddressType> GetAddressTypes()
return _ctx.LkAddressType.AsNoTracking();
【讨论】:
@marksmith527 为什么要创建新范围?为什么不将PropertyContext
注入AddressRepository
并让框架接受?
@marksmith527 你也在AppService.GetAddressTypes
中实现查询,然后控制器才可以使用它。
嗨@GuruStron,现在它可以工作并选择所有数据,但是OData 不起作用,localhost:6878/api/Address/AddressType?$top=2localhost:6878/api/Address/AddressType?$select=addressTypeCode
我在这里发布了一个更详细的问题,我可以发送积分并关闭它,你碰巧知道这个答案吗? ***.com/questions/62650392/…
@marksmith527 尝试按照第二个 sn-p 的建议将上下文注入存储库。我会说通常(并非总是)手动创建范围是一种代码味道。以上是关于C#:使用 IQueryable 注入 DbContext 时,无法访问 ASP.NET Core 中的已处置对象的主要内容,如果未能解决你的问题,请参考以下文章
C# Entity Framework中的IQueryable和IQueryProvider详解
温故知新C#中 IEnumerable 与IQueryable