2010-02-12 8 views
6

In meiner WCF-Client-Klasse handle ich das Faulted()-Ereignis, so dass, wenn der Remote-Dienst eine Ausnahme auslöst und den Kanal beschädigt, ich es immer noch anmutig herunterfahren kann. Hier ist mein Code:Was ist System.ServiceModel.Diagnostics.CallbackException und warum kann ich damit nicht umgehen?

protected void RemoteDataRetriever_Faulted(object sender, EventArgs e) 
{ 
    (sender as ICommunicationObject).Abort(); 
    this.Dispose(); 
    throw new ChannelTerminatedException("The remote service threw an unhandled exception and as a result the channel has been closed."); 
} 

So was würde ich erwarten, ist, dass der Client die ChannelTerminatedException umgehen kann, die ich geworfen habe manuell und eine Nachricht an den Benutzer senden, usw. Statt meine Ausnahme in einem System.ServiceModel.Diagnostics.CallbackException gewickelt zu werden. Ok, gut. Außer hier ist der Haken: diese CallbackException existiert nicht in der ServiceModel-Bibliothek und es scheint, dass ich keine Möglichkeit habe, sie zu behandeln, außer als generisches Exception, was mir für meine Komponententests nicht gut tut. Was zum Teufel geht hier vor? Kann ich das irgendwie deaktivieren und die Ausnahme werfen, die ich ursprünglich wollte?

+0

Da Sie die Ausnahme selbst auslösen, können Sie eine andere Ausnahme verwenden, die nicht umgebrochen wird? Ich denke etwas, das nicht die Tatsache entlarvt, dass Sie WCF unter alles verwenden ... –

+0

Kein Würfel. Ich habe die ChannelTerminatedException in eine StackOverflowException geändert ;-) und es wird immer noch in diese nervige CallbackException eingepackt (die eine, die ich werfe, ist die innere Ausnahme). Und dann gibt es die lästige Nachricht: "Ein Benutzer-Rückruf hat eine Ausnahme ausgelöst. Überprüfen Sie den Ausnahme-Stack und die innere Ausnahme, um den Rückruf zu bestimmen, der fehlgeschlagen ist." Ja, ich weiß, dass der Rückruf eine Ausnahme ausgelöst hat! Ich war derjenige, der es geworfen hat! Ich werde weitere Nachforschungen anstellen und prüfen, ob irgendwo ein WCF-Flag/Parameter vorhanden ist, mit dem ich dieses Verhalten deaktivieren kann. –

Antwort

4

Wie sich herausstellt, System.ServiceModel.Diagnostics.CallbackException ist eine interne Klasse in einer wenig bekannten Assembly gefüllt "% SystemRoot% \ Microsoft.net \ Framework \ v3.0 \ Windows Communication Foundation \ SMDiagnostics.dll", die nur interne enthält Klassen. Nun, das stinkt, weil es bedeutet, dass wir diese Ausnahme niemals fangen können. Ich konnte jedoch die Klasse/Methode ausfindig machen, die die obige Ausnahme instanziiert (System.ServiceModel.Diagnostics.ExceptionUtility.ThrowHelperCallback (Exception innerException)) und festgestellt, dass sie von der virtuellen Methode OnFaulted() in CommunicationObject aufgerufen wird. Also theoretisch jede Klasse, die von CommunicationObject (Entschuldigung ClientBase<T>) abgeleitet ist, kann diese Methode überschreiben und sagen, dass sie ThrowHelperCallback() nicht aufrufen. Dies bedeutet, dass die einzigen möglichen Kandidaten Klassen sind, die von ChannelFactoryBase<T> abgeleitet sind. Theoretisch könnte ich meine eigene Custom-Channel-Factory implementieren, die die lästige CallbackException unterdrückt, aber im Moment ist es zu viel Arbeit, also denke ich, ich muss mich nur damit befassen.

EDIT: @ Jeremy - Wenn ich die SOAP-Hülle über die Leitung zurück überprüfen, finde ich, dass es mir einen generischen Fehler gibt, wie erwartet, dass die CallbackException nicht serialisiert wird und daher nicht generiert wird der Server.

<s:Body> 
    <s:Fault> 
     <s:Code> 
      <s:Value>s:Receiver</s:Value> 
      <s:Subcode> 
       <s:Value xmlns:a="http://schemas.microsoft.com/net/2005/12/windowscommunicationfoundation/dispatcher">a:InternalServiceFault</s:Value> 
      </s:Subcode> 
     </s:Code> 
     <s:Reason> 
      <s:Text xml:lang="en-US">The server was unable to process the request due to an internal error. For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the &lt;serviceDebug&gt; configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework 3.0 SDK documentation and inspect the server trace logs.</s:Text> 
     </s:Reason> 
    </s:Fault> 
</s:Body> 
+0

Ich glaube nicht, dass ich klargestellt habe, dass CallbackException auf dem Client als Antwort auf eine nicht behandelte Ausnahme generiert wird, die vom Host zurückgegeben wird. Mein Hauptpunkt war der generische Fehler sollte serverseitig behandelt werden, also muss der Klient (der sehr gut von jemand anderem in einer anderen Sprache gebaut werden könnte) nicht haben. –

+0

OK, +1 auf Ihre Antwort.Als Antwort benutze ich FaultContracts, um die häufigsten Ausnahmen zu senden, die auf Client-Seite korrekt behandelt werden, aber ernsthaftere und unerwartetere Exceptions würden idealerweise im Faulted-Ereignis behandelt werden. Deshalb bin ich ein wenig verärgert über MS, dass sie die Ausnahme stehlen, die ich zu werfen versuche, und sie in eine Klasse verpacken, die für sie intern ist. Nachdem ich jedoch für eine Handvoll MS-Frameworks entwickelt habe, weiß ich jetzt, dass dies nur ein Teil des Kurses ist. –

+0

Wie man mit Exceptions umgehen kann, ist eine Sache, bei der jeder etwas anderes macht, aber ich stimme zu, dass es keinen Sinn macht, eine unzugängliche Ausnahme auszulösen, selbst wenn die Methode, die es auslöst, überschrieben werden soll. Wickeln Sie es zumindest in einen öffentlichen Typ, damit es gehandhabt werden kann. –

2

Sie sehen die System.ServiceModel.Diagnostics.CallbackException da eine Ausnahme auf dem Server auftritt. Da die Ausnahme außerhalb der Domäne der Clientanwendung auftritt, ist sie möglicherweise von einem Typ, auf den der Client keinen Zugriff hat. Der Rückrufmechanismus verarbeitet dies, indem er die CallbackException generiert, die Sie sehen. Dies ähnelt der System.TypeInitializationException, die ausgelöst wird, wenn beim Zugriff auf ein statisches Member eine nicht behandelte Ausnahme auftritt. Wenn Sie versuchen, dies auf elegante Weise zu handhaben, möchten Sie möglicherweise die Ausnahme auf der Serverseite behandeln und den Socket schließen, wodurch anschließend eine Ausnahme auf dem Client ausgelöst wird, die verarbeitet werden kann.

+0

Falsch. Siehe meine Antwort. –

+0

Ich denke, die Art, wie ich es formuliert habe, war ein bisschen vage. Ich habe die Antwort etwas übersichtlicher gestaltet. –