MVC动作过滤器和多线程

时间:2011-12-30 00:52:41

标签: c# asp.net asp.net-mvc action-filter

我目前正在使用动作过滤器我认为是线程问题,在我的应用程序上我使用ActionFilter来执行每个动作的跟踪,此跟踪将提供统计信息,例如呼叫的持续时间以及记录发送给操作的参数。

实际跟踪实现(由其他团队完成)与IDisposable对象一起使用,基本上在创建实例时初始化开始时间,并且当处置对象设置结束日期时,两个调用都在自定义日志中创建一个条目,代码如下(为简单起见,删除一些代码):

    public class TraceActionAttribute : ActionFilterAttribute
{
    private IDisposable logManagerBeginTrace;

    /// <summary>
    /// Called by the ASP.NET MVC framework before the action method executes.
    /// </summary>
    /// <param name="filterContext">The filter context.</param>
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        base.OnActionExecuting(filterContext);
        List<object> parameters = new List<object>();

        string actionName = filterContext.ActionDescriptor.ActionName;
        Type controllerType = filterContext.Controller.GetType();
        foreach (KeyValuePair<string, object> currentParameter in filterContext.ActionParameters)
        {
            parameters.Add(currentParameter.Value);
        }

        this.logManagerBeginTrace = LogManager.BeginMethodTrace(ApplicationConstants.ApplicationName, controllerType, actionName, Guid.NewGuid(), parameters.ToArray());
    }

    /// <summary>
    /// Called by the ASP.NET MVC framework after the action method executes.
    /// </summary>
    /// <param name="filterContext">The filter context.</param>
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        base.OnActionExecuted(filterContext);
        this.logManagerBeginTrace.Dispose();
    }
}

异常并没有告诉我多少,基本上是它试图处理元素而其他人仍处于活动状态,我仍然需要查看跟踪器代码......但我发现this post其中说明如下:

  

在以前的ASP.NET MVC版本中,除少数情况外,每个请求都会创建操作过滤器。这种行为从来都不是保证行为,而只是一个实现细节,而过滤器的合同是将它们视为无状态。在ASP.NET MVC 3中,过滤器被更积极地缓存。因此,任何不正确地存储实例状态的自定义操作过滤器都可能会被破坏。

对我来说这看起来非常奇怪,因为动作过滤器应该是对等请求,这就是我们在其上放置公共属性,并为特定动作配置其行为的原因,不是吗?

我很感激任何帮助,问候。

2 个答案:

答案 0 :(得分:7)

一种可能的解决方法是将对象实例存储在HttpContext.Items而不是ActionFilter类的私有变量中。

HttpContext.Items是一种按请求存储的机制,听起来就像你需要的那样。

这是您修改后的代码大致如下所示:

 public class TraceActionAttribute : ActionFilterAttribute
{
    private IDisposable logManagerBeginTrace;

    /// <summary>
    /// Called by the ASP.NET MVC framework before the action method executes.
    /// </summary>
    /// <param name="filterContext">The filter context.</param>
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        base.OnActionExecuting(filterContext);
        List<object> parameters = new List<object>();

        string actionName = filterContext.ActionDescriptor.ActionName;
        Type controllerType = filterContext.Controller.GetType();
        foreach (KeyValuePair<string, object> currentParameter in filterContext.ActionParameters)
        {
            parameters.Add(currentParameter.Value);
        }

        filterContext.HttpContext.Items["TraceActionKey"] = LogManager.BeginMethodTrace(ApplicationConstants.ApplicationName, controllerType, actionName, Guid.NewGuid(), parameters.ToArray());
    }

    /// <summary>
    /// Called by the ASP.NET MVC framework after the action method executes.
    /// </summary>
    /// <param name="filterContext">The filter context.</param>
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        base.OnActionExecuted(filterContext);
        ((IDisposable)filterContext.HttpContext.Items["TraceActionKey"]).Dispose();
    }
}

答案 1 :(得分:1)

在MVC 5中,至少相同的行为是正确的,动作属性被缓存和重用。但不仅如此,要小心,因为同一个实例可以同时在多个线程中使用。