Подтвердить что ты не робот

Использование кросс-потоков свойства "HttpContext.Current" и связанных с ним вещей

Я читаю из < Essential ASP.NET с примерами в С# > следующий оператор:

Еще одно полезное свойство, о котором нужно знать, - это свойство static Current класса HttpContext. Это свойство всегда указывает на текущий экземпляр класса HttpContext для обслуживаемого запроса. Эта может быть удобно, если вы пишете вспомогательные классы, которые будут использоваться со страниц или других классов трубопроводов и, возможно, потребуется получить доступ к контекст по любой причине. Используя статическое свойство Current для получить контекст, вы можете избежать передачи ссылки на него вспомогательные классы. Например, класс, показанный в листинге 4-1, использует Текущее свойство контекста для доступа к QueryString и печать что-то в текущий буфер ответов. Обратите внимание, что для этого статического свойство, которое должно быть правильно инициализировано, вызывающий должен выполнять исходный поток запросов, поэтому, если вы породили дополнительные потоки для выполнения работы во время запроса вы должны позаботиться о предоставлении доступа к классу контекста.

Я задаюсь вопросом о первопричине смелой части, и одна вещь ведет к другой, вот мои мысли:

Мы знаем, что процесс может иметь несколько потоков. Каждый из этих потоков имеет свои собственные стеки, соответственно. Эти потоки также имеют доступ к области общей памяти, куче.

Затем стек, насколько я понимаю, является тем местом, где хранится весь контекст для этого потока. Чтобы поток мог получить что-то в куче, он должен использовать указатель, а указатель хранится в его стеке.

Поэтому, когда мы выполняем некоторые вызовы с перекрестными потоками, мы должны убедиться, что вся необходимая информация контекста передается из стека потоков вызывающего объекта в стек потока вызываемого.

Но я не совсем уверен, допустил ли я ошибку.

Любые комментарии будут глубоко оценены.

Спасибо.

ADD

Здесь стек ограничен стек пользователя.

4b9b3361

Ответ 1

Есть четыре вещи, которые работают вместе, чтобы вызвать поведение, о котором вы спрашиваете:

  • HttpContext - это объект экземпляра, ссылка которого может быть найдена в HttpContext.Current
  • Thread также является объектом экземпляра, ссылка которого может быть найдена в Thread.CurrentThread
  • Thread.CurrentThread является статическим, но ссылается на другой объект Thread в каждом потоке
  • HttpContext.Current фактически указывает на Thread.CurrentThread.ExecutionContext.IllogicalCallContext.HostContext

Выводы, которые мы можем извлечь из приведенных выше значений:

  • Поскольку HttpContext является объектом экземпляра, а не static, нам нужна его ссылка для доступа к нему.
  • Поскольку HttpContext.Current фактически указывает на свойство на Thread.CurrentThread, изменение Thread.CurrentThread на другой объект, скорее всего, изменится HttpContext.Current
  • Поскольку при переключении потоков Thread.CurrentThread изменяется, HttpContext.Current также изменяется при переключении потоков (в этом случае HttpContext.Current становится нулевым).

Объединив все это, что заставляет HttpContext.Current не работать в новом потоке? Изменение ссылки Thread.CurrentThread, которое происходит при переключении потоков, изменяет ссылку HttpContext.Current, которая мешает нам получить экземпляр HttpContext, который мы хотим.

Чтобы повторить, единственное, что происходит здесь, - это Thread.CurrentThread ссылка на другой объект в каждом потоке. HttpContext работает так же, как и любой другой объект экземпляра. Поскольку потоки в том же AppDomain могут ссылаться на одни и те же объекты, все, что нам нужно сделать, это передать ссылку на HttpContext в наш новый поток. Нет никакой информации о контекстах для загрузки или что-то в этом роде. (есть некоторые довольно серьезные потенциальные проблемы с прохождением HttpContext в другие потоки, но ничего не мешает вам это делать).

Несколько последних замечаний на стороне, с которыми я столкнулся, исследуя:

  • В некоторых случаях Thread ExecutionContext "течет" (копируется) из одного потока в другой. Почему тогда HttpContext не "течет" в нашу новую тему? Поскольку HttpContext не реализует интерфейс ILogicalThreadAffinative. Класс, хранящийся в ExecutionContext, распространяется только в том случае, если он реализует ILogicalThreadAffinative.

  • Как ASP.NET перемещает HttpContext из Thread в Thread (Thread-Agility), если он не протекает? Я не совсем уверен, но похоже, что он может передать его в HttpApplication.OnThreadEnter().

Ответ 2

Я думаю, что нашел подходящее объяснение здесь: http://odetocode.com/articles/112.aspx

Подводя итог, код HttpContext.Current выглядит следующим образом:

public static HttpContext get_Current()
{ 
    return (CallContext.GetData("HtCt") as HttpContext); 
}

с CallContext функционирует как поточно-локальное хранилище (т.е. каждый поток будет видеть другую копию данных и не сможет получить доступ к копиям, видимым другими потоками). Следовательно, как только текущий контекст инициализируется в одном потоке, последующие обращения другими потоками приведут к NullReferenceException, так как свойство является локальным потоком в исходном потоке.

Итак, ваше первоначальное объяснение было близким, в том смысле, что проблема в том, что данные видны только одному потоку.

Ответ 3

Поле поддержки Current помечено как ThreadStatic (я предполагаю), поэтому оно не будет доступно/инициализировано в созданных пользователем потоках.

В чем дело, вы должны захватить экземпляр HttpContext.Current в потоке запроса, а затем использовать этот экземпляр в своих потоках, а не ссылаться на HttpContext.Current.