ActionFilterAttributes是否跨线程重用?这是如何运作的?

时间:2012-01-20 05:39:50

标签: asp.net-mvc

我一直在使用以下代码进行一些测试,以尝试和锻炼ActionFilterAttributes的工作方式:

public class TestAttribute : ActionFilterAttribute
{
    private string _privateValue;
    public string PublicValue { get; set; }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        _privateValue = DateTime.Now.ToString();

        base.OnActionExecuting(filterContext);
    }
}

当我在两个并行线程上运行上面的代码时,_privateValue字段会混淆。但是,PublicValue属性不会混淆。

在我看来,ActionFilterAttributes可以跨线程重用,但是根据为公共属性指定的常量创建新实例。我是对的吗?

我在哪里可以找到相关信息?

1 个答案:

答案 0 :(得分:77)

这将取决于ASP.NET MVC的版本,但您不应将实例状态存储在将在不同方法之间重用的动作过滤器中。这是一个引用,例如来自ASP.NET MVC 3中的breaking changes之一:

  

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

这基本上意味着动作过滤器的相同实例可以重复用于不同的动作,如果你在其中存储了实例状态,它可能会破坏。

就代码而言,这意味着你绝对不应该像这样写一个动作过滤器:

public class TestAttribute : ActionFilterAttribute
{
    private string _privateValue;

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        _privateValue = ... some calculation
    }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        // use _privateValue here
    }
}

但你应该这样写:

public class TestAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var privateValue = ... some calculation
        filterContext.HttpContext.Items["__private_value__"] = privateValue;
    }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        var privateValue = filterContext.HttpContext.Items["__private_value__"];
        // use privateValue safely here
    }
}