MVC ActionFilterAttribute DbContext dispose解决方案
本文关键字:解决方案 dispose DbContext ActionFilterAttribute MVC | 更新日期: 2023-09-27 18:05:14
我目前有以下ActionFilterAttribute在我的MVC项目。对于第一个请求,它工作得很好,但是随后的请求返回一条消息,表示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;过滤器被更积极地缓存。因此,任何自定义操作不正确存储实例状态的过滤器可能会被破坏。
我不确定如何最好地解决这个问题。我考虑将我的两个私人只读字段移动到onactionexecution块,我相信会解决这个问题,但我担心多线程,如果有问题的实现。
似乎很多人都使用Castle Windsor或Ninject来解决这个问题,但这些都超出了我的专业水平,甚至在浏览了Windsor教程(https://github.com/castleproject/Windsor/blob/master/docs/mvc-tutorial-intro.md)之后,我也无法理解我到底需要做什么。
问题出在您初始化并保留的两个字段上:
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成员)会针对每个请求重新初始化,因此您不必担心代码会试图重用已处置的实例。
另一种选择是创建一个代理过滤器类,它将实例化并连接实际的过滤器。
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
。