我最近对我的MVC3应用程序进行了更改,试图正确处理DbContext
对象[1]。这在开发中运行得很好,但是一旦应用程序被推送到我的生产服务器,我就开始间歇性地获得一些有趣的异常,这些异常会一直存在,直到AppPool被回收。异常可以追溯到我的自定义AuthorizeAttribute
中的代码,如下所示:
System.InvalidOperationException: The 'Username' property on 'User' could not be set to a 'Int32' value. You must set this property to a non-null value of type 'String'.
System.InvalidOperationException: The 'Code' property on 'Right' could not be set to a 'String' value. You must set this property to a non-null value of type 'Int32'.
(数据库模式如下所示:用户:[Guid,String,...],权利:[Guid,Int32,...])
就好像某些“电线越过”,应用程序混合了数据库的结果:尝试将Right
结果实现为User
,反之亦然。
为了管理DbContext
的处理,我把代码放在每个控制器级别存储它。当处理控制器时,我也处理DbContext
。我知道这很麻烦,但AuthorizeAttribute
通过filterContext.Controller
使用相同的上下文。
在这个庄园中处理DbContext
的对象生命周期有什么问题吗?有没有任何合理的解释,为什么我得到上面的纵横交错的例外?
[1]虽然我知道没有必要处理DbContext
个对象,但我最近遇到了一些消息来源,说明这是最好的做法。
编辑(根据@ MikeSW的评论)
当AuthorizeAttribute
在范围内时,DbContext
方法中正在设置代表OnAuthorization
的{{1}}的属性。然后,此属性将在AuthorizationContext
方法中使用。
答案 0 :(得分:1)
你真的需要处理上下文吗?
Jon Gallant的this post表示,他与Microsoft ADO.NET实体框架团队保持联系:
我是否总是在DbContext对象上调用Dispose()?都能跟得上
在我与EF团队的开发者交谈之前,我的答案总是响亮的“当然!”。但是DbContext并不是这样。您不需要在DbContext对象上调用Dispose时具有宗教信仰。尽管它确实实现了IDisposable,但它只实现了它,所以你可以在某些特殊情况下调用Dispose作为安全措施。默认情况下,DbContext会自动为您管理连接。
答案 1 :(得分:0)
首先,我建议您“真正”熟悉 ASP.NET Application Life Cycle Overview for IIS 7.0,因为它是良好的MVC应用程序设计的基础。
现在尝试“模仿”您的代码库
假设您有类似于此处所述的自定义MembershipProvider https://stackoverflow.com/a/10067020/1241400
然后您只需要自定义Authorize
属性
public sealed class AuthorizeByRoles : AuthorizeAttribute
{
public AuthorizeByRoles(params UserRoles[] userRoles)
{
this.Roles = AuthorizationHelper.GetRolesForEnums(userRoles);
}
}
public static class AuthorizationHelper
{
public static string GetRolesForEnums(params UserRoles[] userRoles)
{
List<string> roles = new List<string>();
foreach (UserRoles userRole in userRoles)
{
roles.Add(GetEnumName(userRole));
}
return string.Join(",", roles);
}
private static string GetEnumName(UserRoles userRole)
{
return Enum.GetName(userRole.GetType(), userRole);
}
}
您可以在任何控制器或特定操作上使用
[AuthorizeByRoles(UserRoles.Admin, UserRoles.Developer)]
public class MySecureController : Controller
{
//your code here
}
如果您愿意,您还可以订阅PostAuthorizeRequest
活动,并根据某些条件弃置结果。
protected void Application_PostAuthorizeRequest(Object sender, EventArgs e)
{
//do what you need here
}
对于DbContext
,我从未遇到过您的情况,是per request是正确的方法,因此您可以将其置于控制器或存储库中。
当然,建议您使用filters,然后为您的操作添加[AllowAnonymous]属性。