WCF-Client blockiert aufgrund von Callback selbst beim Rückruf von IsOneWay

7

neu in WCF.

Ich habe einen Client, der beim Aufrufen eines WCF-Dienstes festgefahren ist.

Der Dienst ruft zum Zeitpunkt des Aufrufs einen Rückruf zum Client auf, der als IsOneWay markiert ist. Ich habe bestätigt, dass der Dienst den Rückruf nicht blockiert.

Der Client ruft dann sofort den gleichen Dienst erneut an (in einer engen Schleife), ohne den Rückruf bereits bedient zu haben. Der Client wird dann deadlocks (und ein Haltepunkt auf der Dienstseite wird nie ausgelöst).

Also zur Erinnerung:

%Vor%

Ich gehe davon aus, dass der Rückruf am Client-Ende eine WCF-Sperre ergriffen hat, und dann möchte der zweite Service-Aufruf vom Client auch diese Sperre, so dass ein Deadlock resultiert. Aber das ist nur eine Annahme.

Ich habe über ConcurrencyMode gelesen, aber ich kann nicht entscheiden, welchen Modus ich verwenden soll oder wo ich es hinstellen soll, weil ich nicht 100% weiß, was gerade passiert und was genau blockiert wird.

Ich würde es auch vorziehen, wenn alle Callbacks vom Dispatch-Thread bedient werden, da dies den Code einfacher hält.

Können irgendwelche WCF-Experten genau erklären, was hier vor sich geht?

Vielen Dank

    
GazTheDestroyer 08.06.2011, 09:50
quelle

2 Antworten

20

OK, ich glaube, ich habe es ausprobiert.

WCF-Dienste sind standardmäßig auf einzelne Threads eingestellt. Alle Aufrufe und Rückrufe werden zu einem einzelnen Thread (oder SynchronizationContext, um genauer zu sein) marshalled.

Meine App ist eine WPF-App mit einem einzigen Thread. Daher wird der SynchronizationContext auf den Dispatch-Thread gesetzt.

Wenn der Callback eingeht, versucht er, den Anruf an den Versand-Thread zu leiten, der natürlich beim ursprünglichen Service-Anruf blockiert wird. Ich bin nicht klar, es sperrt genau, aber es gibt offensichtlich einige globale Sperre, die es versucht, bevor Sie auf den Versand Thread warten.

Wenn der Dispatch-Thread dann den Dienst erneut aufruft, blockiert er bei dieser globalen Sperre.

Zwei Möglichkeiten:

1) Erstellen Sie den Dienstproxy in einem anderen Thread an erster Stelle. Alle Aufrufe werden stattdessen durch diesen Thread gemarshallt und es spielt keine Rolle, dass der Versand-Thread blockiert ist.

2) Wenden Sie das Attribut [CallbackBehavior (UseSynchronizationContext = false)] auf die Client-Klasse an, die den Callback implementiert. Dies bedeutet, dass WCF den Synchronisierungskontext ignoriert, wenn der Rückruf eingeht, und es den Dienst bei jedem verfügbaren Thread wartet.

Ich ging mit 2. Offensichtlich bedeutet dies, dass ich Callbacks marshalen muss, die die GUI auf den Dispatch-Thread selbst aktualisieren könnten, aber zum Glück ist meine Callback-Implementierung sowieso ein kleiner Wrapper, also mache ich in jedem einen _dispatcher.BeginInvoke () Callback-Methode, um ASYNCHRONOURS zu marshalieren. Der Versand-Thread wird dann Dienst, wenn es eine Chance bekommt, die ich in erster Linie wollte.

    
GazTheDestroyer 09.06.2011, 09:44
quelle
0

Die von Ihnen dargestellte Sequenz ähnelt einem synchronen Aufruf. Während eines asynchronen Aufrufs wäre die Sequenz:

%Vor%

Bei jedem asynchronen Web-Service-Aufruf erstellt das System einen separaten IO-Thread (IOCP-Thread) und bearbeitet die Anfrage. In diesem Fall finden Sie selten einen Deadlock.

Ich habe festgestellt, dass dieser Weg, selbst wenn er innerhalb einer Schleife aufgerufen wird, sehr gut funktioniert.

Sie können sich beispielsweise für das Ereignis .OnProcessComplete registrieren und dann die Methode ProcessCompleteAsync aufrufen.

    
KMån 08.06.2011 10:14
quelle

Tags und Links