2009-09-16 7 views
7

Ich denke, ich brauche Hilfe, um zu verstehen, wie statische Objekte in einer ASP.Net-Anwendung bestehen bleiben. Ich habe dieses Szenario:Warum ist der "Kontext" meiner statischen ASP.Net-Funktion zwischen Benutzersitzungen?

someFile.cs in einer Klassenbibliothek:

public delegate void CustomFunction(); 

public static class A { 
    public static CustomFunction Func = null; 
} 

someOtherFile.cs in einer Klassenbibliothek:

public class Q { 
    public Q() { 
     if (A.Func != null) { 
      A.Func(); 
     } 
    } 
} 

Einige ASP.Net Seite:

Page_Init { 
    A.Func = MyFunc; 
} 

public void MyFunc() { 
    System.IO.File.AppendAllText(
     "mydebug.txt", DateTime.Now.ToString("hh/mm/ss.fff", Session.SessionID)); 
} 

Page_Load { 
    Q myQ = new Q(); 
    System.Threading.Thread.Sleep(20000); 
    mQ = new Q(); 
} 

Die Idee ist, dass ich ein Business-Objekt habe, das einige Operationen auf der Basis einer Callback-Funktion auf UI-Ebene ausführt. Ich setze die Callback-Funktion in Page_Init auf eine statische Variable (in der realen Code-Version, auf der Master-Seite, wenn das einen Unterschied macht). Ich dachte, dass jede Ausführung der Seite, unabhängig davon, aus welcher Benutzersitzung sie stammt, die Logik dieser Funktion durchläuft, aber auf ihrer eigenen Datenmenge operiert. Was stattdessen zu geschehen scheint, ist eine Nebenläufigkeitsproblematik.

Wenn ich eine Benutzersitzung ausfühle, während sie zwischen den Anrufen zu dieser Rückruffunktion schläft, starte eine andere Benutzersitzung, wenn die erste Sitzung aus dem Ruhezustand zurückkommt, nimmt sie die Sitzungs-ID aus der zweiten Benutzersitzung auf. Wie kann das möglich sein?

Ausgabe von mydebug.txt:

01/01/01.000 abababababab (session #1, first call) 
01/01/05.000 cdcdcdcdcdcd (session #2, first call - started 5 seconds after session #1) 
01/01/21.000 cdcdcdcdcdcd (session #1 returns after the wait but has assumed the function context from session #2!!!!!) 
01/01/25.000 cdcdcdcdcdcd (session #2 returns with its own context) 

Warum den Kontext der Funktion (das heißt, seine lokalen Daten, etc.) von einer Benutzersitzung zu einem anderen überschrieben werden?

+0

Danke, jeder, für die Hilfe. StackOverflow-Regeln :) –

Antwort

2

Eine Lösung, die Sie in Betracht ziehen könnten, ist mit [ThreadStatic].

http://msdn.microsoft.com/en-us/library/system.threadstaticattribute(VS.71).aspx

Es wird Ihre Statik pro Thema machen. Es gibt jedoch Cavaets, also solltest du testen.

+0

Neben der MSDN-Anmerkung in Ihrem Link zu den anfänglichen Werten: Was sind die Vorbehalte? –

+0

Dies funktioniert nicht in ASP.NET. Sie können nicht vorhersagen, welcher Thread eine bestimmte Anfrage bearbeiten wird. – Brannon

+0

@Brannon - aber können wir nicht garantieren, dass ein einzelner Thread eine einzelne Anfrage bedient? Ich denke, das ist mein Problem - das myFunc eines Threads wurde mitten in der Operation durch die Zuweisung eines anderen Threads von myFunc geändert. –

11

Jede Anfrage an eine asp.net-Website kommt herein und wird auf einem eigenen Thread verarbeitet. Aber jeder dieser Threads gehört zu derselben Anwendung. Das heißt, alles, was Sie als statisch kennzeichnen, wird für alle Anfragen und damit auch für alle Sitzungen und Benutzer freigegeben.

In diesem Fall wird die MyFunc Funktion, die der statischen Func Mitglied über oben kopiert wird mit jedem Page_Init in A Teil Ihrer Seite Klasse ist, und so jeder Benutzer jedes Mal, wenn ein Page_Init hat, er die A.Func verwendet ersetzt ist durch alle Anfragen.

+0

Ich verstehe, dass die Funktion Adresse ersetzt wird. Ich verstehe jedoch nicht, warum die Daten, auf die in der Funktion zugegriffen wird, auch überkreuzen. Warum hat Session # 1, die Session.SessionID = Abababababab hat, beim erneuten Aufruf von myFunc plötzlich Session.SessionID = cdcdcdcdcdcd? –

+0

Da der Delegat die gesamte Umgebung dieser Methode erfasst, einschließlich des aktuellen Sitzungsobjekts, wenn Sie es dem statischen Delegaten zuweisen. – nos

+0

Da vor Sitzung Nr. 1 die statische A.Func() -Methode in der Q() - Konstruktorsitzung aufgerufen wird, hat Sitzung Nr. 2 diese Funktion durch ihre eigene Implementierung ersetzt. Du rufst eine ganz andere Funktion das 2. Mal an. –

4

Statische Daten werden unter der gesamten application domain Ihrer Webanwendung geteilt. Kurz gesagt, es wird von allen Threads geteilt, die Anfragen in Ihrer Webanwendung bedienen, es ist nicht an eine Sitzung/Thread/Benutzer gebunden, sondern an die Webapp als Ganzes (anders als zB PHP, wo jede Anfrage in einer eigenen isolierten Umgebung lebt) Bar ein paar Knöpfe zur Verfügung gestellt - wie die Sitzungsvariable.)

+0

Wie ich versuche, in meinem Kommentar zu Joel richtig zu verbalisieren, verstehe ich, warum die Funktionsreferenz unter der App-Domäne geteilt wird. Ich verstehe nicht, warum die Variablen, die Sitzung/Thread/Benutzer in der Logik der Funktion gebunden sind, auch zwischen der Anwendungsdomäne geteilt werden. –

4

Ich werde nicht versuchen, die Erklärungen der anderen Antworten von statischen Mitgliedern zu verbessern, aber möchte einen anderen Weg zeigen, um Ihr unmittelbares Problem zu kodieren.

Als Lösung Sie eine Instanz orientierte Version Ihrer Klasse A, speichern sie in einer Seite-Ebene variabel und übergeben es an Q ‚s Konstruktor beim Laden der Seite machen könnte: In

public class MyPage: Page { 
    private A2 _a2; 

    // I've modified A2's constructor here to accept the function 
    protected Page_Init() { this._a2 = new A2(MyFunc); } 

    protected Page_Load() { 
     Q myQ = new Q(this._a2); 
     // etc.. 
    } 
} 

Tatsache, wenn es keine dringende Notwendigkeit gibt, A2 früher zu deklarieren, könnten Sie es instanziieren, wenn Sie Ihre Instanz Q in Page_Load erstellen.

Bearbeiten: Um die Frage zu beantworten, die Sie in anderen Kommentaren ausgelöst haben, ist der Grund, dass die Variablen freigegeben werden, dass die Anforderungen denselben Delegaten teilen, der nur eine einzige Kopie seiner Variablen hat. Siehe Jon Skeets The Beauty of Closures für weitere Details.

+0

DOH !!!!!!! Das ergibt jetzt einen ganzen Sinn für mich. Ich habe nicht einmal gemerkt, dass ich in diesem Fall eine Schließung vorgenommen habe. Mein Beispielcode ist eine extrem vereinfachte Version des echten Codes - Ihre vorgeschlagene Lösung wird leider nicht in den realen Fall passen. Aber vielen Dank für die Schließung Erklärung. –

Verwandte Themen