MVC动作过滤器和多线程

Bon*_*arp 4 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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

DMa*_*yer 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();
    }
}
Run Code Online (Sandbox Code Playgroud)