【问题标题】:MVC ActionFilterAttribute DbContext Disposed SolutionsMVC ActionFilterAttribute DbContext Disposed 解决方案
【发布时间】:2016-08-31 19:42:09
【问题描述】:

我目前在我的 MVC 项目中有以下 ActionFilterAttribute。它适用于第一个请求,但后续请求会返回 DbContext 已释放的消息。

public class PermissionFilter : ActionFilterAttribute
{
    private readonly ApplicationGroupManager _groupManager = new ApplicationGroupManager();
    private readonly ActionPermissionManager _permissionManager = new ActionPermissionManager();

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var request = filterContext.HttpContext.Request;
        var response = filterContext.HttpContext.Response;
        if (request.IsAjaxRequest())
        {
            #region Preventing caching of ajax request in IE browser

            response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));
            response.Cache.SetValidUntilExpires(false);
            response.Cache.SetCacheability(HttpCacheability.NoCache);
            response.Cache.SetNoStore();

            #endregion Preventing caching of ajax request in IE browser
        }
        var currentAreaName = filterContext.RequestContext.RouteData.DataTokens["area"];
        var currentActionName = filterContext.ActionDescriptor.ActionName;
        var currentControllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
        var userId = HttpContext.Current.User.Identity.GetUserId<int>();

        if (!_groupManager.UserHasAdministratorAccess(userId))
        {
            if (!_permissionManager.HasPermission((currentAreaName == null ? String.Empty : currentAreaName.ToString()), currentControllerName, currentActionName, userId))
            {
                filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary { { "controller", "Account" }, { "action", "Login" } });
            }
        }

        base.OnActionExecuting(filterContext);
    }
}

我已经阅读了足够多的内容,意识到这是 MVC3 中引入的以下更改的问题

重大更改:在以前版本的 ASP.NET MVC 中,操作过滤器 除少数情况外,按请求创建。这种行为从来没有 一个有保证的行为,但仅仅是一个实现细节和 过滤器的合同是认为它们是无国籍的。在 ASP.NET MVC 3 中, 过滤器被更积极地缓存。因此,任何自定义操作 不正确地存储实例状态的过滤器可能会被破坏。

我不确定如何最好地解决此问题。我考虑将我的两个私有只读字段移动到 OnActionExecuting 部分,我相信这可以解决问题,但我担心多线程以及该实现是否存在问题。

似乎很多人使用 Castle Windsor 或 Ninject 解决了这个问题,但这些超出了我的专业水平,即使在完成了 Windsor 教程 (https://github.com/castleproject/Windsor/blob/master/docs/mvc-tutorial-intro.md) 之后,我也无法理解我到底需要做什么.

【问题讨论】:

  • 在您的情况下,使用 Castle Windsor 或 Ninject 就像试图用雷神之锤敲击别针。

标签: c# asp.net asp.net-mvc dbcontext actionfilterattribute


【解决方案1】:

问题在于您初始化并保留的两个字段:

private readonly ApplicationGroupManager _groupManager = new ApplicationGroupManager();
private readonly ActionPermissionManager _permissionManager = new ActionPermissionManager();

大概其中至少有一个具有 DbContext 实例,该实例也在构造函数或字段/属性初始化程序中初始化。我显然不知道这些类的内部工作原理,但看起来它们没有被任何其他方法使用。它们确实应该在方法而不是类字段中声明:

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
    ApplicationGroupManager groupManager = new ApplicationGroupManager();
    ActionPermissionManager permissionManager = new ActionPermissionManager();

    // The rest of your code here
}

这也将解决您看到的错误。由于每个请求都会重新初始化 Manager 实例(及其 DbContext 成员),因此您不必担心代码会尝试重用已处理的实例。

【讨论】:

  • 正如我在问题中所说,这是我倾向于的解决方案。但是,由于每个修饰方法只有一个 ActionFilterAttribute 实例,因此是否对变量有任何担忧?对同一方法的两个同时请求是否会导致这些变量出现问题?
  • 这对你来说真的是一个问题......他们是你的课程。如果他们在内部保持静态或全局状态,那么是的 - 这可能是一个问题。只要您的类设计良好并明确声明依赖关系,那么您就不会有任何问题。
【解决方案2】:

另一种方法是创建一个代理过滤器类,它将实例化并连接实际的过滤器。

public class PermissionFilterProxy : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            // create and wire the actual filter
            // so in this way its lifetime is handled by us
            PermissionFilter permissionFilter = new PermissionFilter();
            permissionFilter.OnActionExecuting(filterContext);
            base.OnActionExecuting(filterContext);

        }
    }

现在您将配置(添加)此代理,而不是 PermissionFilter

【讨论】:

  • 这是一个有趣的解决方案...谢谢。
  • 请注意,这仍然会导致根据请求重新初始化您的管理器类。它实际上与我下面的解决方案效果相同,但是如果您不能修改底层过滤器(或者您出于某种原因真的不想这样做),则此解决方案会更好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-03-12
  • 2012-02-19
  • 2015-12-15
  • 1970-01-01
  • 2014-08-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多