Чи унікальні екземпляри статичного класу для запиту або сервера в 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/…
Реуель Рібейро

Питання, пов’язане з хорошою відповіддю, є на сайті stackoverflow.com/q/5219431 .
Теофіл

Відповіді:


146

Ваші статичні класи та поля статичного примірника поділяються між усіма запитами до програми та мають такий самий термін служби, що й домен програми. Тому ви повинні бути обережними під час використання статичних екземплярів, оскільки у вас можуть виникнути проблеми синхронізації тощо. Також майте на увазі, що статичні екземпляри не будуть GC'ed до того, як пул додатків буде перероблений, і тому все, на що посилається статичний екземпляр, не буде GC'ed. Це може призвести до проблем з використанням пам'яті.

Якщо вам потрібен екземпляр із таким же терміном служби, що і запит, я б запропонував скористатися HttpContext.Current.Itemsколекцією. Це за задумом означає, що це місце для зберігання речей, які вам потрібні під час запиту. Для кращого дизайну та читабельності ви можете використовувати шаблон Singleton, який допоможе вам керувати цими елементами. Просто створіть клас Singleton, в якому зберігається його примірник HttpContext.Current.Items. (У моїй загальній бібліотеці для ASP.NET я маю для цього загальний клас SingletonRequest).


3
Не могли б ви надати зразок вашого одиночного шаблону HttpContext.Current.Items?
Airn5475

Детальніше про мою ситуацію: у моєму веб-додатку користувач перегляне бібліотеку класів коду, яка використовує спільне властивість класу. Я хочу, щоб ця властивість була специфічною для користувача, але я не хочу передавати цю властивість різним функціям. Чи можете дизайн, який ви згадуєте, правильно впоратися з цим?
Airn5475

Будь ласка, не могли б ви поділитися класом SingletonRequest?
Тебо

Я не зберігаю жодних даних у статичному класі. Я використовую статичний клас лише для отримання даних або встановлення даних як рівня даних. Так чи є якась проблема?
garish

"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) відсутній. У рамках рециркуляції пулу створюється новий AppDomain, і пов'язані з ним статичні екземпляри ініціалізуються.
Нік

30

Статичні члени мають сферу застосування лише поточного робочого процесу, тому це не має нічого спільного з запитами, оскільки різні запити можуть бути або не можуть бути оброблені одним і тим же робочим процесом.

  • Для того, щоб обмінюватися даними з певним користувачем та між запитами, використовуйте HttpContext.Current.Session.
  • Для обміну даними в конкретному запиті використовуйте HttpContext.Current.Items.
  • Для обміну даними у всій програмі або напишіть механізм для цього, або налаштуйте IIS для роботи з одним процесом та напишіть програму Singleton / use.

До речі, кількість робочих процесів за замовчуванням дорівнює 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.