Являются ли экземпляры статического класса уникальными для запроса или сервера в ASP.NET?

182

На веб-сайте ASP.NET, являются ли статические классы уникальными для каждого веб-запроса, или они создаются при необходимости, и GCed всякий раз, когда GC решает избавиться от них?

Причина, по которой я спрашиваю, состоит в том, что я написал несколько статических классов раньше в C #, и поведение отличается от того, что я ожидал. Я ожидал, что статические классы будут уникальными для каждого запроса, но, похоже, это не так.

Если они не уникальны для каждого запроса, есть ли способ позволить им быть?

ОБНОВЛЕНИЕ:
ответ, который дриса дала мне, был именно тем, в чем я нуждался. Я уже использовал одноэлементный класс, однако он использовал статический экземпляр и поэтому распределялся между запросами, даже если пользователи были разными, что в данном случае было плохо. Использование HttpContext.Current.Itemsрешает мою проблему отлично. Для тех, кто сталкивается с этим вопросом в будущем, вот моя реализация, упрощенная и сокращенная, чтобы было легко понять шаблон:

using System.Collections;
using System.Web;

public class GloballyAccessibleClass
{
    private GloballyAccessibleClass() { }

    public static GloballyAccessibleClass Instance
    {
        get
        {
            IDictionary items = HttpContext.Current.Items;
            if(!items.Contains("TheInstance"))
            {
                items["TheInstance"] = new GloballyAccessibleClass();
            }
            return items["TheInstance"] as GloballyAccessibleClass;
        }
    }
}
Дэн Герберт
источник
Просто filterContext.Result = new RedirectResult(...)наперед : если вы перенаправите ваш запрос, скажем, с вами вы потеряете свои товары, потому что будет создан новый HttpContext. Более подробная информация здесь: stackoverflow.com/questions/16697601/…
Reuel Ribeiro
Соответствующий вопрос с хорошим ответом находится по адресу stackoverflow.com/q/5219431 .
Феофил

Ответы:

146

Ваши статические классы и поля статических экземпляров совместно используются всеми запросами к приложению и имеют то же время жизни, что и домен приложения. Поэтому вы должны быть осторожны при использовании статических экземпляров, поскольку у вас могут возникнуть проблемы с синхронизацией и тому подобное. Также имейте в виду, что статические экземпляры не будут подвергнуты GC до повторного использования пула приложений, и поэтому все, на что ссылается статический экземпляр, не будет GC. Это может привести к проблемам с использованием памяти.

Если вам нужен экземпляр с тем же временем жизни, что и у запроса, я бы предложил использовать HttpContext.Current.Itemsколлекцию. Это предназначено для хранения вещей, которые вам нужны по запросу. Для лучшего дизайна и удобочитаемости вы можете использовать шаблон Singleton, чтобы помочь вам управлять этими элементами. Просто создайте класс Singleton, в котором хранится его экземпляр HttpContext.Current.Items. (В моей общей библиотеке для ASP.NET у меня есть общий класс SingletonRequest для этой цели).

driis
источник
3
Не могли бы вы предоставить образец вашей модели Singleton HttpContext.Current.Items?
Airn5475
Подробнее о моей ситуации: в моем веб-приложении пользователь будет бегать по библиотеке классов кода, которая использует свойство общего класса. Я хочу, чтобы это свойство было специфичным для пользователя, но я не хочу передавать это свойство различным функциям. Может ли дизайн, который вы упомянули, справиться с этим правильно?
Airn5475
Пожалуйста, не могли бы вы поделиться классом SingletonRequest?
Tebo
Я не храню никаких данных в статическом классе. Я использую статический класс только для получения данных или установки данных в качестве слоя данных. Так есть ли проблемы?
Гари
"static instances will not be GC'ed before the application pool is recycled, and therefore everything that is referenced by the static instance, will not be GC'ed"- Есть ли источник для этого, потому что это не имеет никакого смысла и противоречит тому, что я читал в другом месте. Когда AppPool перерабатывается, соответствующий домен приложений полностью разрушается и GC'd. Когда это происходит, любые связанные статические экземпляры также будут GC'd, потому что их корень (AppDomain) исчез. В рамках перезапуска пула создается новый домен приложений и инициализируются связанные с ним статические экземпляры.
Ник
30

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

  • Для обмена данными с конкретным пользователем и между запросами используйте HttpContext.Current.Session.
  • Для обмена данными в рамках конкретного запроса используйте HttpContext.Current.Items.
  • Чтобы обмениваться данными по всему приложению, либо напишите механизм для этого, либо настройте IIS для работы с одним процессом и напишите одноразовое приложение.

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

Моше Биксеншпанер
источник
11

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

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

Sijin
источник
4

Если они не уникальны для каждого запроса, есть ли способ позволить им быть?

Нет. Статические члены принадлежат процессу ASP.NET и доступны всем пользователям веб-приложения. Вам нужно будет обратиться к другим методам управления сеансом, таким как переменные сеанса.

гр.
источник
1

Обычно статические методы, свойства и классы являются общими на Applicationуровне. Пока приложение живет, оно является общим.

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

Вы можете использовать, HttpContext.Current.Itemsчтобы настроить вещи для одного запроса, или HttpContext.Current.Sessionнастроить вещи для одного пользователя (между запросами).

В общем, хотя, если вам не нужно использовать такие вещи, как Server.Transferлучший способ, это в основном создавать вещи один раз, а затем передавать их явно через вызов метода.

Sklivvz
источник
3
Джон Скит показывает нам, что ThreadStatic никогда не бывает безопасным в ASP.Net stackoverflow.com/questions/4791208/…
Марк Линделл
Отклонено, поскольку поток не является уникальным для запроса. Пожалуйста, удалите этот ответ
seebiscuit