1

Analysieren von Protokolldateien Ich habe festgestellt, dass ~ 1% der Serviceaufrufe mit TimeoutException auf der Silverlight-Clientseite beendet wurden. Die Dienste (wcf) sind ziemlich einfach und führen keine langen Berechnungen durch. Gemäß dem Protokoll werden alle Aufrufe an die Dienste immer in weniger als 1 Sek. Verarbeitet (selbst wenn TimeoutException auf dem Client aufgetreten ist!), Es ist also kein Server-Timeout.TimeoutException bei gleichzeitigen Aufrufen von WCF-Diensten von Silverlight-Anwendung

Was ist also falsch? Kann es Konfigurations- oder Netzwerkprobleme sein? Wie kann ich es vermeiden? Welche zusätzlichen Protokollierungsinformationen können zur Lokalisierung dieses Problems hilfreich sein?

Die einzige Problemumgehung, die ich mir ausgedacht habe, besteht darin, Serviceaufrufe nach einem Timeout erneut zu versuchen.

Ich werde jede Hilfe zu diesem Thema zu schätzen wissen!

Update: Beim Start führt die Anwendung 17 Serviceaufrufe und 12 von ihnen gleichzeitig (möglicherweise Ursache des Fehlers?).

Aktualisierung: WCF-Protokoll enthielt keine nützlichen Informationen zu diesem Problem. Es scheint, dass einige Serviceanrufe die Serverseite nicht erreichen.

+0

Ich habe eine Verwirrung hier .. Wie haben Sie ClientBaseExtender verwendet? Stammt Ihr Proxy von ClientBaseExtender? Aber die Proxy-Klasse ist bereits von System.ServiceModel.ClientBase abgeleitet. Also, wie Plug-in ClientBaseExtender mit MyServiceClient? –

+0

Nein, ClientBaseExtender bietet die Erweiterungsmethode (http://msdn.microsoft.com/en-us/library/bb383977.aspx) für ClientBase. Sie können diese Methode also in allen Erben von ClientBase verwenden. –

+0

Welche ** Protokolldateien ** analysierst du? mit irgendeinem _tool_? – Kiquenet

Antwort

6

Das Problem besteht in der maximalen Anzahl gleichzeitiger Verbindungen zu einem einzelnen Server in Internet Explorer 7/6. Es sind nur 2! http://msdn.microsoft.com/en-us/library/cc304129(VS.85).aspx

Wenn wir 3 (z. B.) gleichzeitige Dienstanrufe haben, werden zwei von ihnen sofort zum Server gesendet, aber der dritte wartet in der Warteschlange. Auch der Sende-Timer (entspricht sendTimeout) wird ausgeführt, wenn sich die Anfrage in der Warteschlange befindet. Wenn die ersten beiden Dienstanforderungen für eine lange Zeit ausgeführt werden, generiert der dritte TimeoutException, obwohl es nicht an den Server gesendet wurde (und wir werden keine Informationen über diese Anfrage auf der Server-Seite sehen und kann es nicht mit Fiddler abfangen ...).

In einer realen Situation, wenn wir etwa 12 gleichzeitige Anrufe und Standard 1 Minute senden Timeout und wenn Service Anrufe verarbeiten mehr als 10 Sekunden im Durchschnitt als können wir leicht Timeout Ausnahme mit den letzten zwei Anrufe (12/2 * 10 sec = 60 sec) weil sie alle anderen warten werden.

Die Lösung lautet:

  1. Minimieren Anzahl gleichzeitiger Service-Anrufe.
  2. Erhöhen sendTimeout Wert in Client Konfig.
  3. Implementieren Sie die automatische Wiederholungsfunktion für kritische Dienste.
  4. Implementieren Sie die Warteschlange der Anforderungen, um sie zu verwalten.

In meinem Fall habe ich 1-3 Dinge getan und das war genug.

Hier ist meine Implementierung von Auto-Retry-Funktion:

public static class ClientBaseExtender 
{ 
    /// <summary> 
    /// Tries to execute async service call. If <see cref="TimeoutException"/> occured retries again. 
    /// </summary> 
    /// <typeparam name="TChannel">ServiceClient class.</typeparam> 
    /// <typeparam name="TArgs">Type of service client method return argument.</typeparam> 
    /// <param name="client">ServiceClient instance.</param> 
    /// <param name="tryExecute">Delegate that execute starting of service call.</param> 
    /// <param name="onCompletedSubcribe">Delegate that subcribes an event handler to the OnCompleted event of the service client method.</param> 
    /// <param name="onCompleted">Delegate that executes when service call is succeeded.</param> 
    /// <param name="onError">Delegate that executes when service call fails.</param> 
    /// <param name="maxAttempts">Maximum attempts to execute service call before error if <see cref="TimeoutException"/> occured (by default 5).</param> 
    public static void ExecuteAsyncRepeatedly<TChannel, TArgs>(this ClientBase<TChannel> client, Action tryExecute, 
                   Action<EventHandler<TArgs>> onCompletedSubcribe, EventHandler<TArgs> onCompleted, 
                   EventHandler<TArgs> onError, int maxAttempts) 
     where TChannel : class 
     where TArgs : AsyncCompletedEventArgs 
    { 
     int attempts = 0; 
     var serviceName = client.GetType().Name; 

     onCompletedSubcribe((s, e) => 
           { 
            if (e.Error == null) // Everything is OK 
            { 
             if (onCompleted != null) 
              onCompleted(s, e); 

             ((ICommunicationObject)client).Close(); 
             Debug.WriteLine("[{1}] Service '{0}' closed.", serviceName, DateTime.Now); 
            } 
            else if (e.Error is TimeoutException) 
            { 
             attempts++; 

             if (attempts >= maxAttempts) // Final timeout after n attempts 
             { 
              Debug.WriteLine("[{2}], Final Timeout occured in '{0}' service after {1} attempts.", serviceName, attempts, DateTime.Now); 

              if (onError != null) 
               onError(s, e); 
              client.Abort(); 

              Debug.WriteLine("[{1}] Service '{0}' aborted.", serviceName, DateTime.Now); 
              return; 
             } 

             // Local timeout 
             Debug.WriteLine("[{2}] Timeout occured in '{0}' service (attempt #{1}).", serviceName, attempts, DateTime.Now); 

             Debug.WriteLine("[{2}] Attempt #{0} to execute call to '{1}' service.", attempts + 1, serviceName, DateTime.Now); 
             tryExecute(); // Try again. 
            } 
            else 
            { 
             if (onError != null) 
              onError(s, e); 
             client.Abort(); 
             Debug.WriteLine("[{1}] Service '{0}' aborted.", serviceName, DateTime.Now); 
            } 
           }); 

     Debug.WriteLine("[{2}] Attempt #{0} to execute call to '{1}' service.", attempts + 1, serviceName, DateTime.Now); 
     tryExecute(); // First attempt to execute 
    } 
} 

Und hier ist eine Nutzung:

var client = new MyServiceClient(); 
client.ExecuteAsyncRepeatedly(() => client.MyOperationAsync(...), 
    (EventHandler<MyOperationCompletedEventArgs> handler) => client.MyOperationCompleted += handler, 
    (s, e) => // OnCompleted 
     { 
      Do(e.Result); 
     }, 
    (s, e) => // OnError 
     { 
      HandleError(e.Error); 
     } 
); 

Hope this hilfreich sein wird.

0

Mmmm ... kann es möglich sein, dass die Anfrage/Antwort mehr als 64 K oder zu viele serialisierte Objekte benötigt?

Können Sie versuchen, eine Simulation machen den Server mit einer Konsolenanwendung hiting (nur zu prüfen, ob es Netzwerk ist, SL ...)?

+0

"kann es möglich sein, dass die Anfrage/Antwort dauert mehr als 64 K oder zu viele Objekte serialisiert" Nein, denke ich. Serviceantworten sind ziemlich einfach und weniger als 64 KB. "Können Sie versuchen, den Server mit einer Konsolenanwendung zu simulieren (nur um zu überprüfen, ob es sich um ein Netzwerk handelt, SL ...)?" Danke für den Rat! Es ist nicht einfach in unserer Umgebung, aber ich werde es versuchen. –

0

Haben Sie dieses Problem immer noch?

Wenn ja, dann sollten Sie vielleicht das Netzwerk mit Fiddler oder Microsoft Network Monitor oder etwas beobachten?

Verwandte Themen