我已经做了一些测试与下面的代码尝试和锻炼如何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在线程之间重用,但是根据指定给公共属性的常量创建新的实例。我对么?
在哪里可以找到有关这方面的信息?
解决方法
这将取决于ASP.NET MVC的版本,但是你不应该将实例状态存储在将在不同方法之间重用的动作过滤器中。这里是一个引用的例子从一个
breaking changes在ASP.NET MVC 3:
In prevIoUs versions of ASP.NET MVC,action filters are create 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.
这基本上意味着相同的动作过滤器实例可以重用于不同的操作,如果你已经存储了实例状态,它可能会破坏。
而在代码这意味着你绝对不应该写一个动作过滤器像这样:
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 } }