ActionFilterAttributes повторно используются в потоках?Как это работает? - PullRequest
38 голосов
/ 20 января 2012

Я провел некоторое тестирование со следующим кодом, чтобы попытаться выяснить, как работают 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 Ответ

78 голосов
/ 20 января 2012

Это будет зависеть от версии 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
    }
}

, но вы должны написать это так:

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
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...