I'm creating a forum which is made up of topics, which are made up of messages.
When I try to implement the topic View in my Controller with:
public ActionResult Topic(int id) //Topic Id
{
using (var db = new DataContext())
{
var topic = db.Topics.Include("Messages").Include("Messages.CreatedBy").Include("CreatedBy").FirstOrDefault(x => x.Id == id);
//include the messages for each topic, and when they were created so that the last message can be displayed on the topic page
return topic != null ? View(topic) : View();
}
}
I get this error when I try to view the topic page:
ObjectDisposedException was unhandled by user code
The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
The error doesn't seem specific to a certain line, as when I remove the offending line, the same error apperars earlier on.
I have solved this by using:
DataContext db = new DataContext();
at the start of the controller and:
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
at the end (and taking using
out)
Although this works, I am curious as to why "Using" doesn't work, and I'm not really happy having the connection open throughout the controller, and disposing of it manually at the end.
Do any of your entities have lazy loading enabled? It seems like there are queries getting executed in your views but you are disposing your context before they get executed (hence the error saying it is already disposed). If you put the disposal in the controller Dispose method, the view will get executed before the controller and context is disposed.
I recommend installing Glimpse.Mvc5 and Glimpse.EF6 packages. Once you configure glimpse you can see every query that gets executed in your page. You might be surprised to see a few additional queries get executed that you did not intend. This is why I don't recommend using entities directly in your views.
You can't return view or something inside using context as this is causing problem disposing the context here.
correct way of using
using
statement in your case isalso do not do response redirect if you in using statement..
see here : Disposing Database context with using statement in MVC
It was a problem with Lazy Loading, so thanks for the point in the right direction @Dismissile
Once I used '.Include' to load each virtual property of Topic, it worked fine:
I guess it would have been impossible for anyone to know which properties I had declared as virtual without me saying, sorry!
Incidentally, it worked before when I was inspecting the properties in debug mode, because each property would have to be loaded for me to inspect it
This is happening because generally LINQ entities are proxy objects. If you have something like
MyEntity.ChildEntities
, the underlying SQL query isn't executed to fetch those objects until the code is executed. If you're accessing them in a view, the view isn't bound until after the action method returns, at which point the DbContext is already disposed.The lifecycle looks something like this:
topic
runs, but any additional accessors in the view that trigger more SQL queries are not executed yet.using
just disposed your DbContext.Here's a good resource on lazy loading with entities.