所以我有一个相当全面的基于活动的访问控制系统,我使用Entity Framework为MVC 4下的Web应用程序构建。好吧,准确地说,访问控制并不关心它是否使用EF,但应用程序是。
无论如何,我现在正在为每个请求加载用户的权限。我得到了从IoC容器注入到我的ApplicationController中的DbContext的引用,它覆盖了OnAuthorization,将用户的配置文件填充到HttpContext.Current.Items中。似乎工作得相当好,但我不禁想知道这是否是最佳方式。
我的想法是,由于用户的权限不经常更改,如果有的话,更好的方法是将权限配置文件加载到Session中,然后根本不需要更改它们。用户注销并重新登录(无论如何都在桌面操作系统中很常见)。但是我担心如果我使用DbContext获取,那么我得到的对象是一个动态代理,它保存对DbContext的引用,我当然不希望在整个会话中这样做。
思考?这是一个很好的方法,如果是这样的话,我如何确保我的DbContext不会在我真正需要的时候徘徊?
答案 0 :(得分:1)
在查询之前在.AsNoTracking()
上调用Set<UserPermission>
。实体仍将被代理,但将与DbContext
分开。
var userPermission = dbContext.Set<UserPermission>().AsNoTracking()
.SingleOrDefault(x => x.UserName == User.Identity.Name);
思考?这是一个好方法吗?
只要在多个Web服务器上对代码进行负载均衡,就会将动态代理的实体置于会话中。为什么?因为动态代理类。服务器A理解类型DynamicProxies.UserPermission_Guid
,因为它查询了实体。但是,服务器B到N不会,因此无法从会话中反序列化它。其他服务器将使用不同的GUID动态代理实体。
也就是说,您可以将您的数据转换为POCO对象并将其放入会话中。但是,当您第一次查询实体时,您不必担心您的实体被附加到上下文。 AsNoTracking
只会使查询执行得更快。
// 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.
};
答案 1 :(得分:1)
思考?这是一个好方法吗?
此方法附带的另一个问题是当您使用为每个http请求创建一个dbContext
的公共模式时。当请求结束时,此模式通常会处置dbContext
。
protected virtual void Application_EndRequest(object sender, EventArgs e)
但是当我们尝试获取引用已处置DbContext
的代理实体的导航属性时会发生什么?
我们将获得ObjectDisposedException