Czy wystąpienia klasy statycznej są unikalne dla żądania lub serwera w ASP.NET?

182

Czy w witrynie ASP.NET klasy statyczne są unikalne dla każdego żądania WWW, czy też są tworzone w razie potrzeby, a GCed za każdym razem, gdy GC zdecyduje się je usunąć?

Powodem, dla którego pytam, jest to, że napisałem już kilka klas statycznych w języku C #, a zachowanie jest inne niż się spodziewałem. Spodziewałbym się, że klasy statyczne będą unikalne dla każdego żądania, ale tak nie jest.

Jeśli nie są one unikalne dla każdego żądania, czy istnieje sposób, aby im to umożliwić?

AKTUALIZACJA:
Driis odpowiedział mi dokładnie to, czego potrzebowałem. Korzystałem już z klasy singleton, jednak korzystałem z instancji statycznej i dlatego byłem współdzielony między żądaniami, nawet jeśli użytkownicy byli różni, co w tym przypadku było złe. Używanie HttpContext.Current.Itemsdoskonale rozwiązuje mój problem. Dla każdego, kto natknie się na to pytanie w przyszłości, oto moja implementacja, uproszczona i skrócona, aby łatwo zrozumieć wzór:

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;
        }
    }
}
Dan Herbert
źródło
Tylko jedna głowa: jeśli przekierujesz swoją prośbę, powiedzmy, ze filterContext.Result = new RedirectResult(...)stracisz swoje przedmioty, ponieważ zostanie utworzony nowy HttpContext. Więcej szczegółów tutaj: stackoverflow.com/questions/16697601/…
Reuel Ribeiro
Powiązane pytanie z dobrą odpowiedzią znajduje się na stackoverflow.com/q/5219431 .
Theophilus

Odpowiedzi:

146

Twoje klasy statyczne i pola instancji statycznych są współużytkowane między wszystkimi żądaniami do aplikacji i mają taki sam okres istnienia jak domena aplikacji. Dlatego należy zachować ostrożność podczas korzystania z instancji statycznych, ponieważ mogą występować problemy z synchronizacją itp. Należy również pamiętać, że wystąpienia statyczne nie zostaną poddane GC przed ponownym przetworzeniem puli aplikacji, a zatem wszystko, do czego odnosi się wystąpienie statyczne, nie zostanie poddane GC. Może to prowadzić do problemów z użyciem pamięci.

Jeśli potrzebujesz instancji o takim samym okresie istnienia jak żądanie, sugerowałbym użycie HttpContext.Current.Itemskolekcji. To z założenia ma być miejscem do przechowywania rzeczy potrzebnych w wyniku żądania. Aby uzyskać lepszy wygląd i czytelność, możesz użyć wzorca Singleton, aby pomóc Ci zarządzać tymi elementami. Wystarczy utworzyć klasę Singleton, w której będzie przechowywana jej instancja HttpContext.Current.Items. (W mojej wspólnej bibliotece dla ASP.NET mam do tego celu ogólną klasę SingletonRequest).

driis
źródło
3
Czy możesz podać próbkę swojego wzoru Singleton obejmującego HttpContext.Current.Items?
Airn5475,
Więcej szczegółów na temat mojej sytuacji: w mojej aplikacji internetowej użytkownik będzie przeglądał bibliotekę klas kodu, która korzysta ze wspólnej właściwości klasy. Chcę, aby ta właściwość była specyficzna dla użytkownika, ale nie chcę przekazywać tej właściwości różnym funkcjom. Czy wspomniany projekt da sobie z tym radę?
Airn5475,
Czy mógłbyś podzielić się klasą SingletonRequest?
Tebo,
Nie przechowuję żadnych danych w klasie statycznej. Używam klasy statycznej tylko do pobierania danych lub ustawiania danych jako warstwy danych. Czy jest więc jakiś problem?
krzykliwy
"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"- Czy jest na to jakieś źródło, ponieważ nie ma to żadnego sensu i jest sprzeczne z tym, co przeczytałem gdzie indziej. Po ponownym przetworzeniu AppPool powiązana domena aplikacji zostaje całkowicie zburzona i poddana GC. Kiedy tak się stanie, wszelkie powiązane instancje statyczne również zostaną GC, ponieważ ich root (AppDomain) zniknął. W ramach recyklingu puli tworzona jest nowa AppDomain i inicjowane są powiązane z nią instancje statyczne.
Nick
30

Członkowie statyczni mają zakres tylko bieżącego procesu roboczego, więc nie ma to nic wspólnego z żądaniami, ponieważ różne żądania mogą, ale nie muszą być obsługiwane przez ten sam proces roboczy.

  • Aby udostępnić dane konkretnemu użytkownikowi i między żądaniami, użyj HttpContext.Current.Session.
  • Aby udostępnić dane w ramach konkretnego żądania, użyj HttpContext.Current.Items.
  • Aby udostępnić dane w całej aplikacji, napisz do tego mechanizm lub skonfiguruj usługi IIS do pracy z jednym procesem i napisz aplikację singleton / use.

Nawiasem mówiąc, domyślna liczba procesów roboczych wynosi 1, dlatego sieć jest pełna ludzi myślących, że członkowie statyczni mają zasięg całej aplikacji.

Moshe Bixenshpaner
źródło
11

Ponieważ typy są zawarte w domenie aplikacji, oczekiwałbym, że będą istnieć klasy statyczne, dopóki domena aplikacji nie zostanie przetworzona lub jeśli żądanie zostanie obsłużone przez inną domenę aplikacji.

Mogę wymyślić kilka sposobów, aby obiekty specyficzne dla konkretnego żądania zależały od tego, co chcesz zrobić, na przykład możesz utworzyć instancję obiektu w Application.BeginRequest, a następnie zapisać go w obiekcie HttpRequest, aby był dostępny dla wszystkich obiektów w potok przetwarzania żądania.

Sijin
źródło
4

Jeśli nie są one unikalne dla każdego żądania, czy istnieje sposób, aby im to umożliwić?

Nie. Członkowie statyczni są własnością procesu ASP.NET i są współużytkowani przez wszystkich użytkowników aplikacji sieci Web. Musisz przejść do innych technik zarządzania sesjami, takich jak zmienne sesji.

rp.
źródło
1

Normalnie statyczne metody, właściwości i klasy są wspólne na Applicationpoziomie. Tak długo, jak aplikacja działa, są udostępniane.

Możesz określić inne zachowanie za pomocą ThreadStaticatrybutu. W takim przypadku będą one specyficzne dla bieżącego wątku, który moim zdaniem jest specyficzny dla każdego żądania.
Nie radziłbym tego jednak, ponieważ wydaje się to zbyt skomplikowane.

Możesz użyć HttpContext.Current.Itemsdo skonfigurowania rzeczy dla jednego żądania lub HttpContext.Current.Sessiondo skonfigurowania rzeczy dla jednego użytkownika (między żądaniami).

Zasadniczo jednak, chyba że musisz używać takich rzeczy Server.Transfer, najlepszym sposobem jest po prostu utworzenie rzeczy raz, a następnie jawne przekazanie ich przez wywołanie metody.

Sklivvz
źródło
3
Jon Skeet pokazuje nam, że ThreadStatic nigdy nie jest bezpieczny w ASP.Net stackoverflow.com/questions/4791208/…
Mark Lindell
Oddany głos, ponieważ wątek nie jest unikalny dla żądania. Usuń tę odpowiedź
seebiscuit