我试图使用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
创建了默认的OOB存储库。
当我试图获得这样的项目时存在问题:
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);
}
当我调试此代码时,我可以看到item
属性Comments
中存在此异常。
我是否遗漏了ASP.NET Boilerplate中的内容或什么?
感谢您的帮助!
//编辑: 完整的异常消息:
{"The ObjectContext instance has been disposed and can no longer be used for operations that require a connection."}
答案 0 :(得分:3)
我偶然发现了同样的问题。 似乎是UnitOfWork实现为每个&#34; UnitOfWork&#34;
创建并处理一个新的DbContext因此,要解决该特定问题,请尝试注入&#34; IUnitOfWorkManager&#34; 并致电
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() }; } }
如果可行,请考虑调用&#34; Begin()&#34;在你的ApiController的构造函数和&#34;完成()&#34;在它的&#34; Dispose()&#34;覆盖。 希望有所帮助!
答案 1 :(得分:0)
没有。问题最有可能发生在您的存储库中,遗憾的是您的代码未包含在其中。如果我不得不猜测,我会说你在该存储库方法中使用了类似的内容:
using (var context = new ApplicationContext())
{
// fetch something
}
您的Comments
属性是虚拟的,这意味着默认情况下,Entity Framework会延迟加载它,只有在您尝试访问该属性时才会实际向该数据库发出查询。但是,到那时,您已经处理了上下文,因为存储库方法已经完成了它的工作,并且您的上下文仅在using
块中可用。
有很多方法可以解决这个问题。您可以急切地在使用块中加载注释:
return context.Items.Include("Comments").Find(id);
然而,这真的只是掩盖了这个问题。你能做的最好的事情就是不要使用using
。理想情况下,您的上下文应该为每个请求实例化一次且仅实例化一次。最简单的方法是使用依赖注入容器并将一个构造函数添加到接受上下文的存储库中:
public class MyAwesomeRepository
{
private readonly ApplicationContext context;
public MyAwesomeRepository(ApplicationContext context)
{
this.context = context;
}
}
您的DI容器的配置将根据您选择的配置而有所不同,但通常,您希望确保将上下文类绑定到请求范围。
答案 2 :(得分:0)
我遇到了与ASP.NET Boilerplate类似的问题,并且发现只有在根据命名约定命名接口和类时,此框架才能正确地完成所有这些DI魔术。你可以以某种方式手动完成它,但你必须深入研究ABP架构比你想要的更深。
@ChrisPratt发布的链接(见他的回答中的评论)说:
命名约定在这里非常重要。例如,您可以将PersonAppService的名称更改为MyPersonAppService,或者将其他名称更改为包含&#39; PersonAppService&#39; postfix,因为IPersonAppService有这个后缀。但是您不能将您的服务命名为PeopleService。如果你这样做,它没有自动注册IPersonAppService(它已经注册到DI框架但是有自己注册,而不是接口),所以,如果你愿意,你应该手动注册它。
就我而言,我有一个名为ProductService的服务,实现接口IProductAppService。在将我的服务重命名为ProductAppService之前,对于ObjectDisposedException异常,我失败了。
我不认为OP仍然存在这个问题,但希望它能为像我这样与ABP斗争的人们节省几个小时。 : - )