2010-02-12 15 views
6

En mi clase de cliente WCF estoy manejando el evento Faulted() de modo que si el servicio remoto arroja una excepción y falla el canal, al menos puedo cerrarlo con gracia. Aquí está mi código:¿Qué es System.ServiceModel.Diagnostics.CallbackException y por qué no puedo manejarlo?

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."); 
} 

Así que lo que se espera es que el cliente puede manejar el ChannelTerminatedException que he tirado manualmente y enviar un mensaje al usuario, etc. En cambio mi excepción se está envuelto en una System.ServiceModel.Diagnostics.CallbackException. Está bien. Excepto que aquí está el truco: esta CallbackException no existe en la biblioteca de ServiceModel y parece que no hay forma de que la maneje excepto como genérico Exception, lo cual no me sirve para las pruebas de mi unidad. ¿Qué diablos está pasando aquí? ¿Puedo desactivarlo de alguna manera y lanzar la excepción que originalmente quería?

+0

Dado que usted mismo está lanzando la excepción, ¿puede usar otra excepción que no se ajuste? Estoy pensando en algo que no expone el hecho de que estás usando WCF debajo de todo ... –

+0

Sin dados. Cambié la excepción ChannelTerminatedException a StackOverflowException ;-) y todavía está envuelto en esa molesta CallbackException (la que lanzo termina siendo la excepción interna). Y luego aparece el mensaje molesto: "Una devolución de llamada del usuario arrojó una excepción. Verifique la excepción y la excepción interna para determinar la devolución de llamada que falló". Sí, sé que la devolución de llamada arrojó una excepción. Yo fui quien lo tiró! Voy a investigar más y ver si hay una bandera/parámetro WCF en alguna parte que pueda usar para desactivar este comportamiento. –

Respuesta

4

Como resultado, System.ServiceModel.Diagnostics.CallbackException es una clase interna rellena el interior de un pequeño conjunto conocido llamado "% SystemRoot% \ Microsoft.net \ Framework \ v3.0 \ Windows Communication Fundación \ SMDiagnostics.dll", que a su vez incluye solamente interna clases Bueno, eso apesta porque significa que nunca, nunca podremos detectar esa excepción. Sin embargo, pude buscar la clase/método que ejemplifica la excepción anterior (System.ServiceModel.Diagnostics.ExceptionUtility.ThrowHelperCallback (Exception innerException)) y encontré que está siendo llamado por el método virtual OnFaulted() dentro de CommunicationObject. Entonces, teóricamente cualquier clase que se derive de CommunicationObject (perdón ClientBase<T>) puede anular ese método y decirle que no llame a ThrowHelperCallback(). Lo que significa que los únicos candidatos viables son las clases que derivan de ChannelFactoryBase<T>. En teoría, podría seguir adelante e implementar mi propia fábrica de canales personalizados que suprime la molesta CallbackException, pero por el momento es demasiado trabajo, así que supongo que tendré que lidiar con eso.

EDIT: @Jeremy - Si inspecciono el sobre de SOAP volviendo por el cable, me da una falla genérica, como era de esperar, que indica que la CallbackException NO está siendo serializada y NO se está generando en el servidor.

<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

No creo que haya aclarado que CallbackException se genera en el cliente como respuesta a una excepción no controlada devuelta por el host. Mi punto principal era que la falla genérica debe manejarse en el lado del servidor para que el cliente (que bien podría ser construido por otra persona en otro idioma) no tenga que hacerlo. –

+0

OK, +1 a su respuesta.En respuesta, estoy usando FaultContracts para enviar las excepciones más comunes para que se manejen correctamente en el extremo del cliente, pero las excepciones más serias e inesperadas se manejarían idealmente en el evento Faulted. Es por eso que estoy un poco molesto con MS que roban la excepción que estoy tratando de lanzar y envolverla en una clase que es interna para ellos. Sin embargo, después de haber desarrollado para un puñado de marcos de trabajo de MS, ahora sé que esto es simplemente el par del curso. –

+0

Manejar las excepciones es una de esas cosas que cada uno tiene una forma diferente de hacer, pero estoy de acuerdo en que no tiene sentido lanzar una excepción inaccesible, incluso si el método que lo lanza está destinado a ser anulado. Al menos envuélvalo en un tipo público para que pueda ser manejado. –

2

Usted está viendo la System.ServiceModel.Diagnostics.CallbackException una excepción porque se está produciendo en el servidor. Como la excepción se produce fuera del dominio de la aplicación cliente, posiblemente sea de un tipo al que el cliente no tiene acceso. El mecanismo de devolución de llamada maneja esto generando la CallbackException que está viendo. Es similar al System.TypeInitializationException que se lanza cuando se produce una excepción no controlada al acceder a un miembro estático. Si intenta manejar esto con elegancia, es posible que desee manejar la excepción en el lado del servidor y cerrar el socket, lo que posteriormente desencadenará una excepción en el cliente que se puede manejar.

+0

Incorrecto. Ver mi respuesta –

+0

Creo que la forma en que lo expresé fue un poco vago. He editado la respuesta para ser un poco más claro. –

Cuestiones relacionadas