Reputation: 36329
So I have a fairly comprehensive activity-based access control system I built for a web app under MVC 4 using Entity Framework. Well, to be precise the access control doesn't care if it's using EF or not, but the app is.
Anyway, I'm loading the user's permissions on each request right now. I get a reference to my DbContext injected from the IoC container into my ApplicationController, and it overrides OnAuthorization to stuff the user's profile into the HttpContext.Current.Items. Seems to work fairly well, but I can't help but wonder if it's the best way.
My thought was that since the users' permissions don't change often, if ever, the better way to do it would be to load the profile of permissions into the Session instead, and then not have to change them at all until the user logs out and logs back in (pretty common in desktop OS's anyway). But I'm concerned that if I fetch using the DbContext, then the object I get back is a dynamic proxy which holds a reference to the DbContext and I certainly don't want to do that for the whole session.
Thoughts? Is this a good approach, and if so how do I ensure that my DbContext doesn't linger beyond when I really need it?
Upvotes: 1
Views: 940
Reputation: 56
Thoughts? Is this a good approach?
Another problem attached to this approach is when you use the common pattern that create one dbContext
per http request. This pattern typically dispose dbContext
when the request ends.
protected virtual void Application_EndRequest(object sender, EventArgs e)
But what happen when we try to get navigation property of a proxy entity which reference to a disposed DbContext
?
We will get a ObjectDisposedException
Upvotes: 1
Reputation: 47375
Invoke .AsNoTracking()
on the Set<UserPermission>
before you query out. Entities will still be proxied, but will be detached from the DbContext
.
var userPermission = dbContext.Set<UserPermission>().AsNoTracking()
.SingleOrDefault(x => x.UserName == User.Identity.Name);
Thoughts? Is this a good approach?
Putting a dynamically proxied entity in session will break as soon as you load balance your code across more than 1 web server. Why? Because of the dynamic proxy class. Server A understands the type DynamicProxies.UserPermission_Guid
, because it queried out the entity. However Server B through N do not, and therefore cannot deserialize it from the Session. The other servers will dynamically proxy the entity with a different GUID.
That said, you could DTO your data into a POCO object and put it in session instead. However then you do not need to worry about your entity being attached to the context when you first query it out. AsNoTracking
will only make the query perform a bit faster.
// you can still call .AsNoTracking for performance reasons
var userPermissionEntity = dbContext.Set<UserPermission>().AsNoTracking()
.SingleOrDefault(x => x.UserName == User.Identity.Name);
// this can safely be put into session and restored by any server with a
// reference to the DLL where the DTO class is defined.
var userPermissionSession = new UserPermissionInSession
{
UserName = userPermissionEntity.UserName,
// etc.
};
Upvotes: 1