我一直在使用以下代码进行一些测试,以尝试和锻炼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可以跨线程重用,但是根据为公共属性指定的常量创建新实例。我是对的吗?
我在哪里可以找到相关信息?
答案 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
}
}