Laden...

Bei Verwendung des SessionStates: System.InvalidOperationException

Erstellt von UNeverNo vor 9 Jahren Letzter Beitrag vor 9 Jahren 1.258 Views
UNeverNo Themenstarter:in
153 Beiträge seit 2007
vor 9 Jahren
Bei Verwendung des SessionStates: System.InvalidOperationException

Was ich realisieren wollte war ein Locking im Backend. Mehrere Anwendungen holen sich Datensätze mit einer Meldungsnummer und diese Kombination soll eben nur 1x exklusiv abgeholt werden.

Ich habe dazu folgendes Konstrukt gebaut:


private class EVT_Standardeventhandler_Lock
{
	public int Meldungsnummer { get; set; }
	public DateTime Lockdate { get; set; }
}

public class EVT_Standardeventhandler_Locks
{
	List<EVT_Standardeventhandler_Lock> lstLocks = new List<EVT_Standardeventhandler_Lock>();

	/// <summary>
	/// Gibt True zurück wenn Lock erfolgreich gesetzt wurde, sonst False
	/// </summary>
	public bool Lock(int iMeldungsnummer)
	{
		DateTime datNow = DateTime.Now;
		lstLocks.RemoveAll(x => x.Lockdate.AddMinutes(2) < datNow); //alle Locks älter als 2 Minuten sind Schrott -> freigeben

		if (lstLocks.Any(x => x.Meldungsnummer == iMeldungsnummer))
			return false;

		lstLocks.Add(new EVT_Standardeventhandler_Lock() { Lockdate = datNow, Meldungsnummer = iMeldungsnummer });
		return true;
	}

	public void Unlock(int iMeldungsnummer)
	{
		lstLocks.RemoveAll(x => x.Meldungsnummer == iMeldungsnummer);
	}
}

EVT_Standardeventhandler_Locks befindet sich im Sessionstate und von Zeit zu Zeit bekomme ich bei der Any()-Prüfung eine

System.InvalidOperationException: Die Auflistung wurde geändert. Der Enumerationsvorgang kann möglicherweise nicht ausgeführt werden.

Ich schon mal ein wenig Google zum Thema befragt und es scheinen konkurrierende Threads der Auslöser zu sein. Anscheinend ist Any hier nicht threadsafe.

Tja die Frage ist jetzt, ob das irgendwie schöner mit Boardmitteln (.NET 3.5) geht, oder ob ich hier tatsächlich alles auf for-Schleifen-Handling

for (int i = x.Count - 1; i >= 0; i--)

umbauen muss.

Grüße,
Chris

"Wenn Architekten genauso bauen würden, wie Programmierer programmieren, dann würde der erste Specht, der vorbeikommt, die Zivilisation zerstören." (Steven Weinberg)

16.842 Beiträge seit 2008
vor 9 Jahren

Deine Collection lstLocks ist nicht Thread-safe bzw List<T> an für sich ist von Haus aus nicht Thread-Safe; Any() ist hierbei egal. Auch for hilft hier nicht - der Fehler würde genauso auftreten.
Entweder lock() oder geeignete Collections wie ConcurrentBag verwenden.
Dahingehen musst Du die Klasse EVT_Standardeventhandler_Lock ebenfalls Thread-Safe umsetzen.

Grundlagen zu diesem Thema: [Artikel] Multi-Threaded Programmierung

UNeverNo Themenstarter:in
153 Beiträge seit 2007
vor 9 Jahren

Mhh soweit ich das überblicke beschäftigt sich der Artikel hauptsächlich mit mehreren Thread, die man auch unter Kontrolle hat. In meinem Fall rufen mehrere Instanzen einer Anwendung jeweils eine Webservicemethode auf und unter der Haube ist dann im Backend die im Sessionstate gehaltene Klasse.
Oder übersehe ich was?

Könnte das Kapseln innerhalb der Methoden von Lock/Unlock jeweils innerhalb von lock {} mein Problem vielleicht schon beheben?

Grüße,
Chris

"Wenn Architekten genauso bauen würden, wie Programmierer programmieren, dann würde der erste Specht, der vorbeikommt, die Zivilisation zerstören." (Steven Weinberg)

16.842 Beiträge seit 2008
vor 9 Jahren

Nein. Bitte richtig lesen.
Du musst die Liste synchronisieren, ansonsten rufst Du diese von mehreren Threads gleichzeitig auf und das geht eben nicht.

Siehe zB auch mein ähnlicher Blogbeitrag C# – Warteschlangen – Die BlockingCollection (Ob Queue<T> oder List<T> ist egal; beide müssen durch lock() manuell synchronisiert werden).
Dort siehst Du wie man lock() anwendet: entweder direkt auf die Liste oder mit Hilfe eines Synchronisations-Objekts.

UNeverNo Themenstarter:in
153 Beiträge seit 2007
vor 9 Jahren

Hi,

das meinte ich etwa mit dem was ich schrieb. Vielen Dank, hat schön funktioniert 👍

Grüße,
Chris

"Wenn Architekten genauso bauen würden, wie Programmierer programmieren, dann würde der erste Specht, der vorbeikommt, die Zivilisation zerstören." (Steven Weinberg)