Являются ли экземпляры статического класса уникальными для запроса или сервера в 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 для этой цели).


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, чтобы к нему могли обращаться все объекты в конвейер обработки запросов.


4

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

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


1

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

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

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

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


3
Джон Скит показывает нам, что ThreadStatic никогда не бывает безопасным в ASP.Net stackoverflow.com/questions/4791208/…
— Марк Линделл

Отклонено, поскольку поток не является уникальным для запроса. Пожалуйста, удалите этот ответ
— seebiscuit
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.