Laden...

Count einer List<> ist unerwartet 0

Erstellt von S.R. vor 10 Jahren Letzter Beitrag vor 10 Jahren 1.690 Views
S
S.R. Themenstarter:in
221 Beiträge seit 2007
vor 10 Jahren
Count einer List<> ist unerwartet 0

Hi,

ich habe hier ein Problem, was ich mir absolut nicht erklären kann und wo mir auch noch der Ansatz fehlt, wo ich anfangen soll zu suchen 😕 Ich hoffe, ihr könnt mir einen Tipp geben 😃

Ich habe eine public-Klasse "globals", in der ich von fast allen Stellen drauf zu greifen kann, um Basis-Informationen abrufen zu können - z.B. die allgemeinen Projekt-Informationen:

    public class globals
    {
        public static Projects.Projects Projects;
    }

Ich habe einen Webservice geschrieben, der beim Aufruf des SOAP-Requests als erstes folgendes macht:

    globals.Projects = new Projects.Projects(Request.ProjectDirectory);
    globals.Projects.LoadProjectsFromFile();

=> es wird also initialisiert und dann aus einer XML-Datei die Konfiguration geladen. Soweit klappt dies wunderbar.

Nun habe ich das Problem, dass in rund 20% der Fälle (bei gleichem SOAP-Aufruf) die Überprüfung

    if (globals.Projects.ProjectsCount == 0)
                { => FEHLER }

einen Fehler schmeißt, weil ProjectsCount = 0 ist => also offensichtlich keine Projekte geladen wurden. Die Projects-Klasse ist recht einfach gestrickt:

    public class Projects
    {
        private List<Project> PrjList = null;

        public int ProjectsCount
        {
            get
            {
                return this.PrjList.Count;
            }
        }

        public void LoadProjectsFromFile()
        {
            this.PrjList = new List<Project>();
            this.PrjList.Clear();

            XmlDocument xml = new XmlDocument();
            xml.Load(ProjectsFileName);
            
            XmlNode root = xml.DocumentElement;
            XmlNode childNode;

            foreach (XmlNode node in root.ChildNodes)
            {
                ...
                this.PrjList.Add(newProject);
            }

            if (this.ProjectsCount == 0)
                throw new Exception("huhu");
        }

Vor dem Testen hatte ich noch entsprechende try-Blöcke eingebaut - die habe ich aber alle entfernt um zu prüfen, ob es irgendwo knallt - tut es aber nicht.

Was mich total wundert und was ich absolut nicht verstehe: Die "huhu-Exception" wird nie ausgeführt. Das heißt also für mich, dass this.ProjectsCount niemals 0 ist - was ja auch richtig ist.

Wenn ich dann allerdings die gleiche Überprüfung über den SOAP-Request durchführe dann erhalte ich globals.Projects.ProjectsCount == 0. Wie kann das sein? Das ist doch die gleiche get-Funktion, die abgerufen wird... grübel

Ich bin für jeden Tipp mehr als dankbar!

Der verzweifelte Stefan 😃

16.842 Beiträge seit 2008
vor 10 Jahren

Ich habe eine public-Klasse "globals", in der ich von fast allen Stellen drauf zu greifen kann

Sehr schlechter Stil. Gerade bei Services die Gefahr von Thread-Unsicherheiten.
Besser: Repository Pattern (optional mit UoW Pattern).

Es ist ja interessant, dass Du sagst, dass Count einen Fehler wirft. Aber welcher?
[Hinweis] Wie poste ich richtig? Punkt 5.
Eventuell ein Folgefehler durch die nicht Thread-Sicheren Zugriffen Deiner globalen Klasse.

S
S.R. Themenstarter:in
221 Beiträge seit 2007
vor 10 Jahren

Hi,

vielen Dank für deine Antwort. Das mit dem Fehler werfen war so gemeint, dass die If-Abfrage

if (globals.Projects.ProjectsCount == 0)
    { => FEHLER }

tatsächlich ergibt, dass ProjectsCount == 0 ist. Da hatte ich mich wohl etwas schlecht ausgedrückt sorry.

An dieser Stelle fand ich diese Static-Initialisierung gar nicht so schlimm, weil ich einmal zentral die Projekt-Konfiguration lade und dann hin und wieder (z.B. Datenbank-Verbindung) nur die Werte auslese.

Bzgl. Thread-Unsicherheiten habe ich mich gar keine Gedanken gemacht und verstehe auch nicht, wieso dies ein Problem sein kann... Kennst du einen guten Artikel, wo das gut erklärt ist - will das verstehen wie das zu einem Problem kommen kann 😃

Bzgl. Repository Pattern werde ich jetzt mal schauen - sagt mir bisher auch nix 😕 Man lernt halt nie aus 😃

Danke und Gruß

Stefan

49.485 Beiträge seit 2005
vor 10 Jahren

Hallo S.R.,

lass dir doch mal ausgeben, wann das erste Add passiert und wann die Abfrage von Count auf 0. Eigentlich gibt es ja nur zwei Möglichkeiten (sofern in der Anwendung kein Remove oder Clear verwendet wird): Die Abfrage erfolgt vor dem Add. Oder es werden zwei verschiedene Instanzen verwendet. (Ok, bei Threading könnte es noch ein Problem mit Cache-Inkonsistenzen geben, so dass der Count eigentlich schon erhöht ist, aber der andere Thread noch einen alten Wert verwendet).

Wenn das Problem tatsächlich unerklärlich wäre, wie du im originalen Titel behauptet hast, bräuchtest du natürlich gar nicht zu fragen: wir könnten dir dann logischerweise auch nicht helfen ==> Titel geändert.

herbivore

16.842 Beiträge seit 2008
vor 10 Jahren

Bzgl. Thread-Unsicherheiten habe ich mich gar keine Gedanken gemacht und verstehe auch nicht, wieso dies ein Problem sein kann... Kennst du einen guten Artikel, wo das gut erklärt ist - will das verstehen wie das zu einem Problem kommen kann 😃

Ganz einfach: jeder Request erzeugt über den internen ThreadPool einen eigenen Thread im IIS (ASP Projekt wie auch WCF Services, WebAPI und Co). Mehr als das gibts quasi nicht als Grundinfo - und auch nur das ist wichtig.

Für Dich sieht das jetzt zwar so aus, als ob das alles Thread-sicher wäre, aber gerade bei allem, was das Web betrifft: so ist es nicht.
Sobald man irgendwas mit Services und im Web entwickelt ist man direkt mit Threading konfrontiert.
Ergo musst Du nun nicht mehr Event-basierend - wie in der Windows Forms-Welt - denken, sondern Request-basierend; das erleichtert die Arbeit ungemein.

Am besten man kapselt direkt alles so, dass ab dem Request-Einstieg alles Threadsafe ist bzw. eine eigene Instanz erstellt wird.
Dein Vorgehen ist so defintiv Thread-unsicher, da List von Haus aus eben nicht Threadsafe ist und Du es auch nirgends synchronisiert.

3 Wichtige Dinge, die ich immer wieder diesbezüglich nenne: Man weiß nie, ob der aktuelle Request der...* erste war.

  • der letzte war.
  • der einzige ist, der aktuell abgearbeitet wird.
S
S.R. Themenstarter:in
221 Beiträge seit 2007
vor 10 Jahren

Hi,

vielen Dank... da kommt noch einiges auf mich zu - aber ich lerne gerne 😃

Das Thema "public static"-Konstrukt stammt noch aus Vorgängerzeiten - keine Ahnung wieso das an dieser Stelle erstellt wurde - aber ich fand es mit meinem Halbwissen auch nicht schlecht 😃

Ich habe mir die Stellen nun genau angeschaut und festgestellt, dass man ohne Probleme auch auf static verzichten kann und eine eigene Instanz ohne große Änderung möglich ist. Daher habe ich das jetzt auch mal umgesetzt und siehe da - kein Fehler mehr!!!

Eure Worte werde ich mir zu Herzen nehmen und mich dazu nochmal weiter informieren. VIELEN DANK für die super Anregungen!!!

Gruß

Stefan