Related question: How do I cache data that rarely changes?
I'm making an ASP.NET MVC4 application.
On every request the security details about the user will need to be checked with the area/controller/action that they are accessing to see if they are allowed to view it. The security information is stored in the database.
For example:
User
Permission
UserPermission
Action
ActionPermission
A "Permission" is a token that is applied to an MVC action to indicate that the token is required in order to access the action. Once a user is given the permission (via the UserPermission table) then they have the token and can therefore access the action.
I've been looking in to how to cache this data (since it rarely changes) so that I'm only querying in-memory data and not hitting a database (which is a considerable performance hit at the moment).
I've tried storing things in lists, using a caching provider but I either run in to problems or performance doesn't improve.
One problem that I constantly run in to is that I'm using lazy loading and dynamic proxies with EntityFramework. This means that even if I ToList()
everything and store them somewhere static, the relationships are never populated. For example, User.Permissions
is an ICollection but it's always null. I don't want to Include()
everything because I'm trying to keep things simple and generic (and easy to modify).
One thing I know is that an EntityFramework DbContext is a unit of work that acts with 1st-level caching. That is, for the duration of the unit of work, everything that is accessed is cached in memory.
I want to create a read-only DbContext that will exist indefinitely and will only be used to read about permission data. Upon testing this it worked perfectly; my page load times went from 200ms+ to 20ms. I can easily force the data to refresh at certain intervals or simply leave it to refresh when the application pool is recycled. Basically it will behave like a cache.
Note that the rest of the application will interact with other contexts that exist per request as normal.
Is there any disadvantage to this approach? Could I be doing something different?