Cuando se manda llamar un servicio WCF desde una aplicación Silverlight y el servicio arroja un error, el
cliente de Silverlight regresa únicamente un error muy genérico:
The remote server returned an error: NotFound
Este mensaje no ayuda en mucho ni al usuario ni al desarrollador para conocer del error, aún más, es necesario por cuestiones de seguridad hacer una división de la información del error: un mensaje amistoso al usuario y un mensaje detallado al administrador del sistema o el desarrollador.
La primera parte del error dedicada al administrador de la aplicación consiste en escribir a detalles la excepción que se genera en el código. Hay muchas herramientas que permiten hacer este loggeo de errores (Log for Net, Microsoft Enterprise Library, entre otros). Para este ejemplo se establece un loggeo sencillo al Application Log del servidor donde se encontraría nuestro servicio. El método además captura dos parámetros: una “Entidad” que indica la entidad de negocio donde ocurrió el error (como por ejemplo País, Estado, Empleado, etc) y una acción, que indica la operación que no pudo ser realizada (Guardar, Seleccionar, Eliminar, etc). Con estos dos parámetros podemos entregar un mensaje amistoso que será enviado al usuario.
public class ExceptionLogger
{
public static string LogAndReturnError(Exception ex, string entidad, string accion)
{
StringBuilder cadenaError = new StringBuilder();
cadenaError.Append("Ocurrió un error en el servicio de la aplicación: \n\n
cadenaError.Append("Error: ");
cadenaError.Append(ex.Message);
cadenaError.Append("\n\nStackTrace: \n\n");
cadenaError.Append(ex.StackTrace);
EventLog.WriteEntry("NombreAplicación", cadenaError.ToString(), EventLogEntryType.Error);
cadenaError = new StringBuilder();
cadenaError.Append(string.Format("Ocurrió un error al intentar {0} {1}. Contacte al administrador del sistema.", accion, entidad));
return cadenaError.ToString();
}
}
Lo siguiente es generar una entidad como un DataContract para el objeto que almacene los errores que ocurran en el servicio.
[DataContract]
public class ServiceError
{
[DataMember]
public string Type { get; set; }
[DataMember]
public string Message { get; set; }
}
Lo que sigue es hacer que nuestras operaciones del servicio puedan arrojar un objeto de error hacia la capa de interfaz. Para ello utilizaremos un parámetro de salida en nuestros métodos de Servicio y utilizaremos la clase de loggeo de error.
[OperationContract]
public void DoWork(string Parameter1, out ServiceError errorService)
{
errorService = null;
try
{
//Operaciones a realizar
}
catch (Exception ex)
{
errorService = new ServiceError
{
Message = ExceptionLogger.LogAndReturnError(ex, "Acción", "Entidad"),
Type = "Aplicación"
};
}
}
Ahora necesitamos una aplicación Silverlight que consuma nuestro servicio. Para ello hay que agregar una aplicación Silverlight y agregar una referencia nuestro servicio. Una vez que llamamos nuestro servicio desde tendríamos lo siguiente:
MyServiceClient client = new MyServiceClient();
client.DoWorkCompleted += new EventHandler<DoWorkCompletedEventArgs>(client_DoWorkCompleted);
client.DoWorkAsync("Hola Mundo");
void client_DoWorkCompleted(object sender, DoWorkCompletedEventArgs e)
{
//Error propio de WCF
if (e.Error == null)
{
//Nuestro Parámetro de Error!!!
if (e.errorService == null)
{
if (e.Result != null)
{
//Manipular resultado
}
}
}
}
Esta es una manera sencilla de implementar el manejo de errores en Silverlight.