lunes, 9 de enero de 2017

Introducción a WCF

En alguna ocasiones me ha tocada mantener aplicaciones que utiliza las Windows Communication Foundation como herramienta de comunicación y siempre he tenido que sufrir lo complicado que es su mantenimiento, debido a la utilización de asistentes. Estos asistentes suelen funcionar muy bien para crear el servicio, ya que te crea todos los objetos de intercambio de datos. Pero complican terriblemente su mantenimiento. Desaprovechan la capacidad de .Net de funcionar en cualquier plataforma y compartir código. Y es muy complicado implementar pruebas unitarias.

Con esta entrada voy a iniciar una serie en la que trataré de explicar cual es la forma de sacar toda la potencia que tiene WCF.

Lo primero que hay que hacer para definir un servicio es crear una interfase que lo defina. Para que WCF la entienda se deberá marcar la interface con el atributo ServiceContractAttribute y cada propiedad con OperationContractAttribute.

[ServiceContract]
public interface IOperacioens
{
   [OperationContract]
   double Plus(double x, double y);
}


Y definimos la clase en el servidor que implementa la interfase.

public class OperacioensNetService : IOperacioen
{
   public double Plus(double x, double y)
   {
      return x + y;
   }
}
Construimos nuestra clase de servicio heredando de ServiceHost. En la que utilizamos la clase BasicHttpBinding para definir un servicio SOAP sobre Http.

public sealed class OperationsServiceHost : ServiceHost
{
   public OperationsServiceHost(Uri baseAddresses)
        :this(typeof(OperationsNetService), baseAddresses)
   {
   }

   public OperationsServiceHost(Type serviceType, params Uri[] baseAddresses)
        :base(serviceType, baseAddresses)
   {
        CreateBinding();
   }

   private void CreateBinding()
   {
        Binding binding = new BasicHttpBinding();
        base.AddServiceEndpoint(typeof(IOperations), binding, string.Empty);
    }
}

Creamos la clase de conexión en la parte del servidor, la cual nos creará el canal de comunicaciones.


public class OperationsConnection : IDisposable
{
    private ChannelFactory<IOperations> mFactory = null;

    public ChannelFactory<IOperations> Factory
    {
       get { return mFactory; }
    }

    private IOperations mChannel;

    public IOperations Channel
    {
       get
       {
           if (mChannel == null)
           {
              mChannel = Factory.CreateChannel();
           }
           return mChannel;
       }
    }

    public OperationsConnection(string service)
    {
        Binding binding;

        binding = new BasicHttpBinding();
        ContractDescription contract = ContractDescription.GetContract(typeof(IOperations));

        ServiceEndpoint endpoint = new ServiceEndpoint(
                    contract,
                    binding, new EndpointAddress(service));

        mFactory = new ChannelFactory<IOperations>(endpoint);
    }

    #region IDisposable
    public void Close()
    {
        if (mFactory != null)
        {
            mFactory.Close();
        }
     }

     public void Dispose()
     {
        Dispose(true);
        GC.SuppressFinalize(this);
     }

     protected virtual void Dispose(bool disposing)
     {
         if (disposing)
         {
             this.Close();
         }
     }
     #endregion
    }

Ya tenemos todas las piezas. Ahora solo nos queda montarlas. Para ello tenemos dos opciones en el lado del servidor. Montar nuestro propio Host auto hospedado. Lo cual nos permitirá crear un servidor con cualquier tipo de aplicación, ya sea aplicación de consola, servicio NT o una aplicación Windows. Utilizaremos la clase OperationsServiceHost anteriormente creada. En nuestro ejemplo se expondrá un servicio que escucha por el puerto 9085.

using (var operationsService = new OperationsServiceHost(
        new Uri("http://localhost:9085/OperationsService.svc")))
{
     operationsService.Open();
     Console.ReadLine();
}

Otra forma es hospedar nuestro servicio en un servidor IIS. Lo que nos permitirá aprovechar el del Pool de conexiones y el reciclaje de servicios de los que dispone el IIS. Para montar el servicio tendremos que crear un fichero con extensión svc, en el que se define el ServiceHost y una clase HostFactory que se encargará de crear la instancia del ServiceHost. Se definirá de la siguiente manera.



<%@ ServiceHost
     Service="OperacionesWCF.Server.OperationsNetService"
     Factory="OperacionesWCF.Server.OperationsServiceHostFactory" %>

Ya solo nos queda hacer las llamadas a nuestro servicio desde una aplicación cliente. Lo cual aremos con la clase anteriormente creada OperationConnection. La cual tiene una propiedad Channel, la cual nos devolverá una instancia virtual al servicio en el servidor.




using (OperationsConnection connection =

                new OperationsConnection(url))

{
    IOperations operations = connection.Channel;
    Console.WriteLine(operations.Plus(345, 23));
}


Podéis descargar un ejemplo en:
https://github.com/andrechi1/Blog-Examples/tree/master/OperationsWCF

No hay comentarios: