Autor: Samuel Casanova, Agile Project Manager en Raona
WCF permite a los desarrolladores controlar algunos de los aspectos de la ejecución de la aplicación como, por ejemplo, el flujo de excepciones.
Excepciones que se producen en el servicio pero que pueden capturarse a través de una traza en el servidor sin necesidad de codificar bloques try-catch en todos los servicios implementados.
Interfaz IErrorHandler
La interfaz IErrorHandler permite controlar en mayor detalle la respuesta de la aplicación WCF a los errores devueltos a los clientes.
Pongamos un ejemplo sencillo de servicio de envío de SMSs en WCF. Si existe algún error con este servicio queremos que se registre en un fichero de texto en el servidor y se propague el Fault al cliente.
Para ello crearemos una clase que implemente la interfaz IErrorHandler. En concreto en el método HandleError capturaremos el error y lo registraremos en un fichero de log mediante una traza.
public class ErrorHandler : IErrorHandler
{
public bool HandleError(Exception error)
{
Trace.TraceError(string.Format("There was an error in SMS Service: {0}", error.Message));
return true;
}
public void ProvideFault(Exception error, System.ServiceModel.Channels.MessageVersion version, ref System.ServiceModel.Channels.Message fault)
{
}
}
Interfaz IServiceBehavior
Ahora lo que haremos es crear una clase que herede de IServiceBehavior. Esta clase nos permitirá aplicar un cierto comportamiento a la clase que nosotros decidamos (nuestro servicio).
El método más importante es el de ApplyDispatchBehavior, que es el que nos permite modificar el comportamiento de la aplicación en ejecución. Lo que haremos será inyectar nuestro handler de excepciones al servicio. También lo haremos heredar de Attribute, de forma que podamos simplemente decorar la clase del servicio sin tener que añadir el comportamiento por código en tiempo de ejecución.
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public sealed class ErrorHandlerServiceBehavior : Attribute, IServiceBehavior
{
public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
{
dispatcher.ErrorHandlers.Add(new ErrorHandler());
}
}
public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{
}
}
Finalmente ya podemos implementar el servicio. Éste irá decorado con la propiedad ErrorHandlerServiceBehavior de forma que se aplique el comportamiento que hemos definido.
[ErrorHandlerServiceBehavior]
public class SMSService : ISMSService
{
public void SendSMS(int phoneNumber, string message)
{
if (phoneNumber < 600000000 || phoneNumber > 699999999)
throw new Exception("Provided telephone number is not valid.");
else if (message.Length > 140)
throw new Exception("Message is too long");
else
{
//DO SOME MAGIC STUFF TO SEND THE MESSAGE
Trace.TraceInformation(string.Format("Message [{0}] sent to number [{1}].", message, phoneNumber));
}
}
}
Una vez realizada toda esta implementación, cualquier excepción que se produzca en nuestro servicio se registrará en el fichero de log (que hemos definido en la configuración del servicio como TextWriterTraceListener).
En el siguiente link podéis descargar la aplicación de ejemplo que contiene además del código mostrado en el artículo una aplicación de consola cliente de ejemplo para probar el servicio.