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

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

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

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

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

Dar*_*rov 81

这将取决于ASP.NET MVC的版本,但您不应将实例状态存储在将在不同方法之间重用的动作过滤器中.以下是ASP.NET MVC 3中一个重大更改的引用:

在以前版本的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
    }
}
Run Code Online (Sandbox Code Playgroud)

但是你应该这样写:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @cbp,在你的情况下,你有2个不同的动作,因为在第一个你将PublicValue设置为"a",在第二个你将它设置为"b".在这种情况下没有问题,因为动作过滤器是属性,属性是.NET中的元数据,元数据在编译时与特定成员相关联.如果它是针对相同的操作而您尝试在不同的方法`OnActionExecuting`,`OnActionExecuted`,...之间重用实例字段的值,则可能会遇到问题. (6认同)
  • 好但是如果ActionFilter并行重用,那么公共属性的值是否可能不可靠?例如,使用上面的代码,如果两个动作同时执行 - 一个将PublicValue设置为"a",另一个将PublicValue设置为"b" - 我必须确信创建了两个TestAttribute实例,否则我无法依赖PublicValue的价值,无论我打算如何使用它.如果你永远不能依赖他们的状态对某一特定行为是正确的,那么即使拥有公共财产也会有什么意义呢? (5认同)
  • Action Filter的公共属性如何(例如OutputCache的Duration属性)?我假设如果属性不同,则会创建一个新实例. (2认同)
  • @cbp,在动作过滤器上有实例字段(私有或公共)没有错.这是你在里面使用它的方式,你应该非常小心. (2认同)