En este artículo veremos cómo propagar excepciones desde nuestro servicio WCF a cualquier cliente, ya que las excepciones en servicios se manejan completamente diferente a las excepciones habituales.

Cuando escribimos un programa y queremos controlar lo inesperado en nuestros métodos utilizamos los bloques try/catch para capturar las excepciones y en base a eso se muestra un mensaje de error en la interfaz de usuario. Sin embargo, cuando trabajamos con servicios WCF, hay que tener en cuenta, que el cliente que consume el servicio puede ser Java, Php o cualquier otro lenguaje, por ello, nunca debemos devolver excepciones nativas .NET ya que el cliente no tiene el mismo concepto de excepciones.

Con este fin, precisamos tener una forma genérica para pasar el detalle de la excepción a todo tipo de clientes.

Toda excepción generada desde un Servicio WCF .NET 2. llegará a la capa de presentación como SoapException pero es imposible tipificar en el cliente cuál ha sido exactamente el error generado por la capa de negocio, entonces:

Con la etiqueta FaultContract de WCF  nos va a permitir crear nuestras propias clases de excepciones personalizadas con la información que nosotros queremos transmitir al cliente.

Vamos a trabajar con un ejemplo…

Supongamos que deseamos enviar de vuelta un código de error al cliente con un mensaje descriptivo “Division por cero” en un servicio de una calculadora básica.

En este ejemplo partiré de un servicio WCF creado con la siguiente estructura:

  • LogicaCalculadora (Libreria de clases)
  • HostCalculadora (Servicio Wcf)

imagen1

Empecemos

1. En primer lugar, creamos nuestra clase de excepción (ExcepcionPersonalizada) como si fuese un contrato de datos de nuestro servicio. Esto es para representar nuestro nuevo tipo de excepción, el cual será una clase etiquetada con el Atributo DataContract para que pueda ser serializada en WCF. Para ello, sobre el proyecto LogicaCalculadora Añadir/Nueva clase “ExcepcionPersonalizada“.

Debemos incluir el espacio de nombres System.Runtime.Serialization.

using System.Runtime.Serialization; 
 
namespace LogicaCalculadora
{ 
    [DataContract] 
    public class ExcepcionPersonalizada
    { 
        public ExcepcionPersonalizada(string detail, int code)
        {
            DetailError = detail;
            InternalCodeError = code;
        }

        [DataMember]
        public int InternalCodeError { get; set; }

        [DataMember]
        public string DetailError { get; set; }
    } 
} 

2.En el Interfaz del servicio en el método que queremos controlar la excepción, debemos introducir el atributo Faultcontract (IServicioCalculadora).

using System.ServiceModel;
namespace LogicaCalculadora
{ 
  
[ServiceContract] 
public interface IServicioCalculadora
{ 
   [OperationContract] 
   FaultContract(typeof(ExcepcionPersonalizada))] 
   float Division(float num1,float num2); 
} 

}

Con FaultContract, el error se incluye en el esquema XML, por lo que ya tenemos la posibilidad de incluir la excepción del lado del cliente para su manipulación.

3. Lo siguiente, es implementar el método de la Interfaz “Division” (ServicioCalculadora).

using System.ServiceModel;

namespace LogicaCalculadora
{
    public class ServicioCalculadora : IServicioCalculadora
    {
        public float Division(float num1, float num2)
        {
            if (num2 == 0)
                throw new FaultException(new ExcepcionPersonalizada("División por cero", 100));
            else
                return num1 / num2;
        }
     }
}

4. En en el behaivor del servicio (fichero de configuración web.config) indicamos para que habilite y exponga las excepciones al cliente.  (HostCalculadora).

<system.serviceModel>
  <behaviors>
    <serviceBehaviors>
      <behavior name="comportamiento">
        <serviceMetadata httpGetEnabled="true"/>
             <serviceDebug includeExceptionDetailInFaults="true"/>
     </behavior>
    </serviceBehaviors>
  </behaviors>
<system.serviceModel>

Ya tenemos todo preparado para manejar excepciones desde un cliente.

5.Ahora, vamos a crear un cliente MVC para consumir el servicio. Crear Nuevo Proyecto Visual C#/Web/de tipo MVC llamado (ClienteWCFCalculadora). Archivo/Nuevo/Proyecto.

imagen11

6. Agregamos la referencia a nuestro servicio. Botón derecho sobre el proyecto Agregar/Referencia Servicio.

imagen12

7. Arrancamos el servicio WCF (HostCalculadora), copiamos la url y le agregamos la referencia al cliente (ClienteCalculadora).

<servicio>
imagen13

<cliente>
imagen4

8. Creamos un nuevo controlador vació llamado CalculadoraController. Sobre el proyecto MVC botón derecho Agregar/Nuevo/Controlador.

9. Agregamos una vista. Sobre el método Index del controlador creado, botón derecho/Agregar vista/Plantilla Empty(sin modelo).

10. En la vista Index creamos un formulario para construir la interfaz gráfica de la calculadora.

imagen19

<Index>

@{
 ViewBag.Title = "Index";
}
<h2>CALCULADORA</h2>
<hr />
<form method="get">
 <div>
 <label>Número 1:</label>
 <input type="text" id="num1" class="form-control"/>
 </div>
 <div>
 <label>Número 2:</label>
 <input type="text" id="num2" class="form-control"/>
 </div>
 <hr />
 <div>
 <button type="button" id="sumar" class="btn-success">Sumar</button>
 <button type="button" id="restar" class="btn-success">Restar</button>
 <button type="button" id="multiplicar" class="btn-success">Multiplicar</button>
 <button type="button" id="dividir" class="btn-success">Dividir</button>
 </div> 
</form>
<div id="caparesultado"></div>

11. En el controlador agregamos el espacio de nombres del servicio y lo instanciamos.

using ClienteWCFCalculadora.ServiceCalculadora;
using System.ServiceModel;

namespace ClienteWCFCalculadora.Controllers
{
  public class CalculadoraController : Controller
  {
    ServicioCalculadoraClient client;

    public CalculadoraController()
    {
    client = new ServicioCalculadoraClient();
    }

    // GET: Calculadora
    public ActionResult Index()
    {
      return View();
    }
  }
}

12. Creamos el método División y lo tratamos de la siguiente manera.

       
        public ActionResult Division(string num1, string num2)
        {
            try
            {
                float n1 = float.Parse(num1);
                float n2 = float.Parse(num2);
                ViewBag.Resultado= client.Division(n1, n2);//llamando al método del servicio
                return View("_parcialresultado");
            }
            catch (FaultException<ServiceCalculadora.ExcepcionPersonalizada> ex)
            {
              String msn = "ERROR: "+ex.Detail.DetailError + " Código:" + ex.Detail.InternalCodeError + "" + ex.Detail;
              ViewBag.Resultado = msn;
              ViewBag.Error = true;
              return View("_parcialresultado");
            }
        }


13. En la vistacreamos un script jquery para que una vez pulsado el botón “Dividir”, se llame al método del controlador con ajax.

@section scripts
{
<script>

$(document).ready(function () 
{
  $("#dividir").click(function ()
   {
   var num1 = $("#num1").val();
   var num2 = $("#num2").val();
   $("#caparesultado").load("/Calculadora/Division?num1=" + num1+"&num2=" + num2);
  });
});

</script>
}

14. Creamos una vista parcial para mostrar el resultado de la operación. Botón derecho Vistas/Agregar/Vista la llamamos “_parcialresultado” 

imagen20

15. Implementamos la vista parcial.

<h2>
@if (ViewBag.Error==true)
{
<div class="text-center text-danger">
@ViewBag.Resultado
</div>
}
else
{
<div class="text text-danger text-info">
Resultado: @ViewBag.Resultado
</div>
}
</h2>

16. Arrancamos el servicio WCF (HostCalculadora)

imagen7

17. Arrancamos el cliente y forzamos una división por cero. Al pulsar el botón “Dividir” se lanza la excepción primero en el servicio y a continuación en el cliente.

<servicio>

imagen6

<cliente>

imagen18

Descargar código:

https://github.com/mireiadev/ClienteWCFCalculadora
https://github.com/mireiadev/LogicaWCFCaulculadora

Mireia Malonda Mayor
https://www.linkedin.com/in/mireiamalondamayor/
Microsoft MCSD
Tajamar 2016 – 2017