rolf64: ASP.NET Arraywerte gehen verloren.

Hallo zusammen,

ich hoffe hier kann mir jemand helfen. ich baue gerade eine kleine Web-Applikation mit ASP.NET. Ich arbeite mich gerade ein.

Nun habe ich eine Seite gemacht, die via code Daten aus einer Datenbank ausliest, und in einem Array speichert. Das Array habe ich mir im Anschluss mal testweise ausgeben lassen und alles war richtig zugeordnet, sowohl lokal als auch beim Hosting.

Jetzt habe ich eine Funktion hinzugefügt, mit der man in dem Array hin und her springen kann, der jeweil aktuelle String wird dann in einer Textbox angezeigt. Aus irgendwelchen komischen Gründen verliert das Array aber seine Werte. Aber immer zu unterschiedlichen Zeitpunkten und nur wenn ich die Seite online gestellt habe. Ich weiss einfach nicht mehr weiter. Hab schon tausend sachen in der web.config geändert.

Hat jemand eine Idee woran sowas liegen kann? oder kennt vielleicht jemand das Problem?

Das Array ist in einem Modul als Public deklariert.

  1. Hi!

    Aus irgendwelchen komischen Gründen verliert das Array aber seine Werte. Aber immer zu unterschiedlichen Zeitpunkten und nur wenn ich die Seite online gestellt habe.

    In welchem Zeitrahmen passiert das denn? Innerhalb eines Requests? Zwischen zwei Requests? 20 Minuten nach dem letzten Zugriff?

    Hat jemand eine Idee woran sowas liegen kann? oder kennt vielleicht jemand das Problem?

    Ideen ja, aber um eine zum Problem passende davon zu wählen, braucht es ein paar mehr Informationen zum Ablauf. Beispielsweise wann und wo das Array gefüllt wird.

    Lo!

    1. Hey,

      also der Ablauf ist so:
      Man wählt einen Button aus, der wiederum ruft eine Routine auf, die 40 Strings aus einer Datenbank holt und in ein (20,2) großes Feld reinpackt.

      Das funktioniert auch alles. ich lass mir zur Kontrolle das Array in einer Textbox ausgeben.

      Jetzt gibt es 2 Navigationsbuttons, einer zum Weiternavigieren zum nächsten Feld-Element (x+1,0) und einen um den anderen Eintrag anzeigen zu lassen (x,1).

      Und bei diesem weiterklicken oder dem Anklicken zum Anzeigen des anderen Strings kommt es dazu, dass die Laufvariable zurücksetzt wird und auch die Inhalte des Feldes. Das passiert unterhalb einer Minute aber nie genau zum gleichen Zeitpunkt

      Erkennen kann ich es daran, dass die Laufvariable wieder auf 0 springt und bein Navigieren die Textfelder leer bleiben.

      1. Hi!

        Und bei diesem weiterklicken oder dem Anklicken zum Anzeigen des anderen Strings kommt es dazu, dass die Laufvariable zurücksetzt wird und auch die Inhalte des Feldes. Das passiert unterhalb einer Minute aber nie genau zum gleichen Zeitpunkt

        Mit einer genauen Erklärung tue ich mich momentan etwas schwer. Aber zumindest soviel kann ich sagen: Auch ASP.NET unterliegt den Eigenheiten des Webs, die da wären, dass zwischen zwei Requests erst einmal kein Zusammenhang besteht. Wenn man Daten zwischen zwei Requests behalten will, muss man sie einerseits in Richtung Browser schicken, der sie beim nächsten Reqeuest wieder mitsendet, oder andererseits mit Sessions arbeiten. Dabei wird der Browser anhand einer Session-ID erkannt und die zugehörigen Daten dann aus dem Session-Speicher geholt. Bei PHP merkt man das Nchtbestehen von Zusammenhängen sehr deutlich, da wird jeder Request in einer jungfräulichen Umgebung abgehandelt. ASP.NET ist da anders. Da läuft eine Anwendung im IIS üblicherweise länger als ein Request. Je nachdem wo du eine Variable erstellst, lebt diese auch nach einem Request-Ende weiter. Das ist recht gut, wenn man wie in deinem Fall, die unveränderliche Daten mehrfach (über mehrere Requests und/oder Anwender) verwenden will, ohne sie jedes Mal neu abzufragen. Aber es gibt da auch Aufräummechanismen. Der Application Pool im IIS, in dem deine ASP.NET-Anwendung läuft (einigermaßen aktuellen IIS vorausgesetzt) wird regelmäßig recyclet, also beendet und startet sich neu. Das passiert aber in der Default-Einstellung erst nach 20 Minuten idlen. (Andere Kriterien gibt's da auch noch.)

        Ein weiterer Fall kann auch sein, dass du mehrere Worker Processes im Application Pool konfiguriert hast. Der Normalfall wäre 1. Mehrere WPs innherhalb eines APs werden Web Garden genannt, und sie sorgen dafür, dass die Anwendung mehrfach läuft. Sie müssten sich dann auch getrennter Speicherbereiche bedienen (vermute ich). Deine Requests können dann einmal da und beim nächsten Mal in einem anderen WP behandelt werden. Auch dann sieht das dort noch nicht gefüllte Array wie geleert aus.

        Wie auch immer, ich würde mich nicht auf das Vorhandensein einmal befüllter Variablen in jedem Request verlassen und stattdessen einen Lazy-Load-Mechanismus einsetzen. Hier die C#-Variante:

        private string[] dasArray;
          public string[] DasArray {
            get {
              if (dasArray == null)
                initialisieren_und_befüllen();
              return dasArray;
            }
          }

        Die private Variable dasArray speichert das eigentliche Array. Beim Zugriff auf die Property DasArray wird zunächst der Zustand von dasArray befragt und selbiges bei Bedarf gefüllt. Das bereits volle oder eben erst gefüllte Array wird dann zurückgegeben. Es kommt also immer ein gefülltes Array zurück, egal ob es zwischenzeitlich aufgeräumt wurde oder dein Request anderswo abgearbeitet wird.

        Erkennen kann ich es daran, dass die Laufvariable wieder auf 0 springt und bein Navigieren die Textfelder leer bleiben.

        Das wäre doch ein benutzerindividueller Wert. Wenn dein Server mehrere Anwender gleichzeitig behandelt - wovon man im Web ausgehen muss -, musst du Daten, die anwenderindividuell sind, im Viewstate oder im Session-Speicher ablegen.

        Wenn du da genauere Untersuchungen anstellen willst, würde ich wie folgt vorgehen: Es gibt einen Tracing-Mechanismus, der schreibt ein paar Vorgänge mit, die so rund um den Application Lifecycle (AL) und Page Lifecycle (PL) passieren. Hab ich noch nicht großartig verwenden müssen, kann ich also nicht allzuviel dazu sagen. Wenn da zu wenig geloggt wird, kannst du in die diversen Events des AL und PL Debug-Ausgaben einfügen, damit du siehst, was abgearbeitet wird. Eventuell auch die Process-ID des Worker Process (wenn es eine solche gibt) dazu notieren und vielleicht den Zustand wichtiger Variablen. Welche Methoden dazu überschrieben werden müssen oder bereits in der Global.asax vorhanden sind, findest du bei Web-Recherchen zu den genannten Stichwörtern.

        Lo!

        1. Hi dedlfix,

          private string[] dasArray;
            public string[] DasArray {
              get {
                if (dasArray == null)
                  initialisieren_und_befüllen();
                return dasArray;
              }
            }

          genau das würde eben nicht korrekt laufen, wenn es darum geht Zustände zwischen mehrere Anfragen zu behalten. Folgendes Beispiel speichert im ViewState:

          public string[] DasArray
          {
            get
            {
              string[] dasArray = (string[])this.ViewState["dasArray"];

          if (dasArray == null)
              {
                dasArray = erstellen_und_befüllen();
                this.ViewState["dasArray"] = dasArray;
              }

          return dasArray;
            }
          }

          Man bedenke aber, dass zum Speichern im ViewState eine Serialisierung erforderlich ist (hier möglich, da Array von Strings serialisierbar sind).

          LG

          1. Hi!

            genau das würde eben nicht korrekt laufen, wenn es darum geht Zustände zwischen mehrere Anfragen zu behalten. Folgendes Beispiel speichert im ViewState:

            Dazu müssten wir erst einmal wissen, ob es überhaupt gefordert ist, Änderungen mitzuschreiben. Wenn die Daten nur angezeigt werden, dann ist das Mitschleppen im ViewState unnötig. Überhaupt würde ich den ViewState, selbst wenn Änderungen stattfinden und erhalten bleiben sollen, nicht uneingeschränkt empfehlen, denn ViewState-Daten wanderen bei jedem Response-Request munter zwischen Server und Client hin und her. Das ist also nur für einigermaßen kleine Daten sinnvoll. Für größere Datenmengen bietet sich eher eine Session an. Wobei man sich da noch überlegen muss, ob man die Daten im Speicher des Webserver-Prozesses, in einem separaten Prozess (auch auf einer anderen Maschine) oder im SQL-Server ablegen will.

            Lo!

            1. Hi dedlfix,

              oh da gibt es sicherlich noch so einige Sachen zu erzählen aber leider fehlt auch das Feedback vom Fragesteller, wo man mal konkreter ansetzen könnte :(. Nicht nur bei diesem Ursprungs-Post. Schade eigentlich.

              Auch wenn der ViewState nicht gerade ideal ist, so öffnet er doch ein wenig das Verständnis für das, was ein WebServer eigentlich macht und was er überhaupt kann bzw. wo Daten abgelegt werden. Ich persönlich drücke den ViewState hintenrum in die Session rein (LoadViewState, SaveViewState, LoadPageStateFromPersistenceMedium, SavePageStateToPersistenceMedium), was natürlich auch gewisser Vorbereitungen bedarf.

              LG

  2. Hi rolf64,

    Nun habe ich eine Seite gemacht, die via code Daten aus einer Datenbank ausliest, und in einem Array speichert.

    es gibt viele Varianten, wie man in ASP.NET Zustände speichern kann. Davon abgesehen, muss man aber auch prüfen, ob ein Zustand geladen werden soll, sofern vorhanden, oder ob es sich um eine jungfräuliche Anfrage handelt (PostBack?!). Daher kann man dir jetzt auch nicht pauschal eine Antwort geben, sondern nur Hinweise. Fakt ist jedenfalls, dass was du momentan in einem Array speicherst, geht verloren, und wird entsprechend neu geladen (zum Beispiel aus dem ViewState) oder auch gar nicht. Wenn du mit TableAdapter arbeitest, dann speichern die das auch entsprechend weg um für die nächste Anfrage die Daten parat zu haben. Ansonsten lege ich dir den ASP.NET Lebenszyklus als Suchbegriff nahe (Life Cycle), ohne hier näher zu verlinken, weil sich dazu recht viel im Internet findet und die MS-Dokumentation nicht immer die Beste ist.

    LG