[英]ASP.NET Boilerplate - “The ObjectContext instance has been disposed” exception
我正在尝试使用ASP.NET Boilerplate处理我的项目,但我遇到了一个严重的问题。
我有2个模特:照片和评论:
public class Comment : Entity<int>
{
[DataType(DataType.MultilineText)]
public string Text { get; set; }
public string Author { get; set; }
public int ItemID { get; set; }
public virtual Item Item { get; set; }
}
public class Item : Entity<int>
{
public string Title { get; set; }
public string Description { get; set; }
public ItemSourceType SourceType { get; set; }
public byte[] PhotoBytes { get; set; }
public string Url { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
}
另外,我已经基于RepositoryBase<Item>
创建了默认的OOB存储库,并且对Comment
。
当我尝试获得像这样的商品时,存在问题:
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Item item = _repoItems.Get(id.Value);
if (item == null)
{
return HttpNotFound();
}
return View(item);
}
当我调试此代码时,我可以在Comments
属性中看到该item
具有此异常。
我是否缺少ASP.NET Boilerplate的内容?
感谢您的帮助!
//编辑:完整的异常消息:
{"The ObjectContext instance has been disposed and can no longer be used for operations that require a connection."}
我只是偶然发现了同样的问题。 似乎是UnitOfWork实现为每个“ UnitOfWork”创建并布置了一个新的DbContext。
因此,要解决该特定问题,请尝试注入“ IUnitOfWorkManager”并调用
public ActionResult Details(int? id) { if (id == null) { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } using(var uow = _unitOfWorkManager.Begin()) { try { Item item = _repoItems.Get(id.Value); if (item == null) { return HttpNotFound(); } return View(item); } finally { uow.Complete() }; } }
如果可行,请考虑在ApiController的构造函数中调用“ Begin()”,并在其“ Dispose()”替代中调用“ Complete()”。 希望有帮助!
否。问题很可能在您的存储库中,不幸的是您未包含其中的代码。 如果我不得不猜测,我会说您在该存储库方法中使用的是以下内容:
using (var context = new ApplicationContext())
{
// fetch something
}
您的Comments
属性是虚拟的,这意味着默认情况下,Entity Framework将延迟加载它,仅当您尝试访问该属性时才向数据库实际发出该查询。 但是,到那时,您的上下文已被处置,因为存储库方法已完成其工作,并且您的上下文仅在using
块内可用。
有很多方法可以解决此问题。 您可以热切地在using块中加载注释:
return context.Items.Include("Comments").Find(id);
但是,这确实可以解决问题。 您可以做的最好的事情就是不使用using
。 理想情况下,对于每个请求,您的上下文应实例化一次,并且只能实例化一次。 最简单的方法是使用依赖项注入容器,并向您的存储库中添加一个接受上下文的构造函数:
public class MyAwesomeRepository
{
private readonly ApplicationContext context;
public MyAwesomeRepository(ApplicationContext context)
{
this.context = context;
}
}
DI容器的配置将根据您选择的配置而有所不同,但是通常,您需要确保将上下文类绑定到请求范围。
我在ASP.NET Boilerplate中遇到了类似的问题,并发现只有当您根据接口和类的命名约定命名该接口和类时,此框架才能正确实现所有DI魔术。 您可以通过某种方式手动进行操作,但是您必须深入了解ABP架构,而不是想要的。
@ChrisPratt发布的链接(请参阅答案中的评论)说:
命名约定在这里非常重要。 例如,您可以将PersonAppService的名称更改为MyPersonAppService或其他包含“ PersonAppService”后缀的名称,因为IPersonAppService具有此后缀。 但是您不能将服务命名为PeopleService。 如果执行此操作,则不会自动为IPersonAppService注册(它已注册到DI框架,但已通过自注册,而不是通过接口注册),因此,如果需要,应手动注册。
就我而言,我有一个名为ProductService的服务,该服务实现了IProductAppService接口。 在我将服务重命名为ProductAppService之前,它因ObjectDisposedException异常而失败。
我认为OP仍然没有这个问题,但是希望它将为像我一样在ABP方面苦苦挣扎的人们节省几个小时。 :-)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.