8

我最近对我的 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结果具体化为 a User,反之亦然。

为了管理 的处置DbContext,我将代码放入每个控制器级别存储。当控制器被处置时,我也处置了DbContext。我知道这很 hacky,但是AuthorizeAttribute通过filterContext.Controller.

处理DbContext这个庄园的对象生命周期有什么问题吗?关于为什么我得到上面的交叉异常有任何合乎逻辑的解释吗?

[1] 虽然我知道没有必要处置DbContext对象,但我最近遇到了一些消息来源,指出无论如何这是最佳实践。

编辑(根据@MikeSW 的评论)

当在范围内时,AuthorizeAttribute表示 的属性DbContext正在方法中设置。该属性随后在该方法中使用。OnAuthorizationAuthorizationContextAuthorizeCore

4

2 回答 2

1

你真的需要处理上下文吗?

根据与 Microsoft ADO.NET Entity Framework 团队有联系的 Jon Gallant的这篇文章:

我是否总是必须在我的 DbContext 对象上调用 Dispose() ?没有

在与 EF 团队的开发人员交谈之前,我的回答总是响亮的“当然!”。但 DbContext 并非如此。您不需要对在 DbContext 对象上调用 Dispose 感到虔诚。尽管它确实实现了 IDisposable,但它只是实现了它,因此您可以在某些特殊情况下调用 Dispose 作为保护措施。默认情况下,DbContext 会自动为您管理连接。

于 2014-02-27T12:17:35.250 回答
0

首先,我建议您“真正”熟悉 IIS 7.0 的 ASP.NET 应用程序生命周期概述,因为它是良好 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,我从来没有遇到过你的情况,是的,每个请求都是正确的方法,所以你可以将它放在控制器或存储库中。

当然,建议您使用过滤器,然后将 [AllowAnonymous] 属性添加到您的操作中。

于 2014-02-26T19:41:16.190 回答