MVC动作筛选器和多线程 [英] MVC Action Filter and Multiple Threads

查看:56
本文介绍了MVC动作筛选器和多线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm currently having what i think is a threading issue with action filters, on my app i'm using an ActionFilter to perform tracing of each action, this trace will provide statistical information such as the duration of the call and also log the parameters being sent to the action.

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

The actual trace implementation (which was done by other team) works with an IDisposable object, basically when creating the instance initializes the start time, and when disposing the object sets the end date, both calls create an entry in a custom log, the code is bellow (remove some code for simplicity purposes):

    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();
    }
}

该异常并没有告诉我太多,基本上是在其他元素仍处于活动状态时它试图处置元素,我仍然必须研究示踪剂代码...但我发现

The exception is not telling me much, basically that it is trying to dispose elements while others are still active, i still have to look into the tracer code... but i found this post which says the following:

在ASP.NET MVC的早期版本中,除少数情况外,每个请求都创建了操作筛选器.此行为绝不是保证的行为,而只是实现细节,并且筛选器的约定应将其视为无状态.在ASP.NET MVC 3中,筛选器被更积极地缓存.因此,任何不正确存储实例状态的自定义操作过滤器都可能会损坏.

In previous versions of ASP.NET MVC, action filters were created per request except in a few cases. This behavior was never a guaranteed behavior but merely an implementation detail and the contract for filters was to consider them stateless. In ASP.NET MVC 3, filters are cached more aggressively. Therefore, any custom action filters which improperly store instance state might be broken.

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

Which for me appears very weirds, since action filters should be peer request, that's the reason we place public properties on it, and configure its behavior for specific Actions, don't we?

谢谢您的帮助,

推荐答案

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

One possible workaround for this is to store the object instance in HttpContext.Items instead of in a private variable on the ActionFilter class.

HttpContext.Items 是一种按请求存储的机制,听起来像您所需要的.

HttpContext.Items is a per-request storage mechanism, which sounds like what you need.

这是您修改后的代码的大致样子:

This is what your modified code would roughly look like:

 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();
    }
}

这篇关于MVC动作筛选器和多线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆