Ninject and Entity Framework Object Context Problems
Today I had an issue with Entity Framework and caching. We have two applications that access the database. For some reason when I would update data in one application, it would not update in the other application for a while. I knew this had to be a caching issue but clearing my browser's cache did nothing. In fact, I was able to make changes to the markup on the page just fine, but the data supposedly coming out of the database was not changing. I even opened up SQL Server Management Studio and looked up the row in the database just to make sure it was saved. The data in the database was up to date, so why was the second app (the one that did not make the change to the data) not showing the updates?
The problem turned out to be Ninject. Ninject manages our dependency injection. This abstraction allows us to hide major components under a .NET interface and let Ninject resolve the dependency itself. We have a total of four projects in our solution: DataLayer, BusinessLayer, UserInterface1, UserInterface2. Both user interface applications use the business layer and the business layer uses the data layer. The data layer contains repository classes that contain the Entity Framework data contexts that they need. The business layer contains controller classes (not to be confused with MVC controllers) which interact with the repositories through interfaces. Then the user interface projects interact with the controller classes through interfaces as well.
When mapping these interfaces to concrete implementations using Ninject, you can specify the scope of the instantiated class. By default I was using InSingletonScope()
which creates a single instance of the class and uses it for injection as long as it possibly can. This makes things a little speedier since we are not creating and destroying the objects with every page request. However, the Entity Framework data context object caches all of its data for as long as it exists. This means that it gets its data once from the database, then every time you request that data it returns it from its own cache. To function properly EF data contexts need to be created and destroyed with each page request. Changing Ninject to use InRequestScope()
on the repository that contains the EF data context should fix the issue right? In most cases probably, but I neglected the fact that my repository was also a property of my controller. This cost me an extra hour of work.
Even though I set my repository to be created with each page request, I was still having the caching issue. I was very confused until I realized that my controller class was still in singleton scope. So Ninject was creating an instance of my controller, and then injecting an instance of my repository into it. But then it was using that same controller for as long as it could. When I finally realized this and set the controller to InRequestScope()
everything started working. Ugh, so much work for that little change!
In conclusion, if you ever have issues with Entity Framework caching data in your application and you use dependency injection then double-check the scope and ensure every object all the way down to the one that uses EF is in request scope. This will save you a lot of headaches!