domingo, 12 de junio de 2016

El famoso error: "System.ServiceModel.FaultException'1 was not handle by user code" cuando trabajamos con WCF.

El famoso error: "System.ServiceModel.FaultException'1 was not handle by user code" cuando trabajamos con WCF.

Introducción:

Si alguna vez has trabajado con WCF estoy seguro que te debes haber topado con este error, y si no, tuviste demasiada suerte.

Lo primero que piensas es que algo en tu código esta mal o que el try-catch no esta capturando la excepción. Y comienzas a modificar y agregar mas código para poder controlar ese error y terminas con mas código de manejo de error que de lógica propia del servicio.

Administrar correctamente procesos de manejo de errores en una aplicación es una pesadilla si quieres hacerlo bien. Yo diría que no es exactamente la parte mas emocionante, pero es realmente necesario para prevenir cualquier situación no manejada.

En una aplicación normal basta con colocar tu código dentro del bloque try-catch con el tipo de excepción, y esta se manejara como una excepción .net normal que usted puede manejar.

Con servicios WCF esto se maneja un poco diferente, simplemente porque WCF tiene que garantizar la interoperabilidad con cualquier aplicación cliente con el fin de que sean capaces de capturar el error devuelto.

Para eso WCF necesita convertir la “excepción .net normal” en un mensaje de excepción SOAP que pueda ser comprendido por cualquier aplicación cliente.

El FaultContract:

Para conseguir convertir la “excepción .net normal” en un mensaje de excepción SOAP, es necesario especificar un atributo FaultContract en su servicio, ya sea de forma declarativa o imperativa. Para mi caso de ejemplo lo he hecho de manera declarativa.
Se debe especificar un atributo FaultContract por cada método de su servicio que desee controlar.

[OperationContract]
[FaultContract (typeof(MyError))]
Boolean myMethod();

MyError es un tipo personalizado que define un mensaje de error.
Después de haber configurado el atributo FaultContract del servicio, lo siguiente que necesita es convertir la “excepción .net normal” en un mensaje de excepción SOAP en el método del servicio del lado del servidor como sigue:

Código del lado del servicio:

catch (Exception ex)
 {
   var ErrLog = new MyError (“This is an error”,”Critical”);
   var fe = new FaultException<MyError> (ErrLog, new FaultReason(ErrLog.Message));
   throw fe;
 }

Código del lado del cliente:

Desde el lado de la aplicación cliente simplemente necesita capturar el tipo de error FaultException como normalmente recupera un mensaje de el servicio SOAP de la siguiente manera:

catch (FaultException<MyError> myError)
 {
   var msg = myError.Detail.Message;
   MessageBox.Show(msg);
   wcfclient.Close();
 }

A continuación usted debería recibir un mensaje de error enviado desde su servicio, dentro de su aplicación cliente pero… esto no esta funcionando exactamente como usted esperaba. Es aquí donde me pase muchos días verificando mi código y la manera como había implementado mi manejo de excepción y todo estaba correcto, pero cuando ejecutaba mi aplicación y mi servicio y enviaba un solicitud a mi servicio esta se detenía cada vez que lanzaba la excepción (throw fe). El error retornado por el servicio era muy extraño era como:
System.ServiceModel.FaultException`1 was unhandled by user code
Después de mucha investigación pude encontrar la solución con el Dr. Google, este error era debido a unas opciones marcadas por defecto en la sección de Debugging del Visual Studio que hace que la ejecución de mi código se pare cada vez que hay una excepción que no tiene una lógica verdadera en el mensaje. Esto me genero mucha confusión.

Deshabilitando el error:

Para deshabilitar este comportamiento debemos desactivar las siguientes 2 opciones del Visual Studio. Para eso vamos al menú Tools => Options y en la ventana que nos aparece nos ubicamos en la sección del lado izquierdo: Debugging => General y desmarcamos las opciones:
Enable the exception assistant
Enable Just My Code (Managed only)
Y damos click en Ok



Ahora vuelvan a ejecutar el servicio y su aplicación cliente y todo debería funcionar correctamente.


Espero con esto poder ahórrales algunas horas o días :) 

No hay comentarios: