WCF y OperationBehaviors

 

Windows Communication Foundation nos permite desarrollar servicios en .Net  de una manera rápida y sencilla, permitiendo soportar varios endpoints y esquemas de configuración. También ofrece un gran nivel de personalización, uno de ellos es poder escribir OperationBehaviors personalizados para nuestro servicio.

Un OperationBehavior nos permite cambiar y controlar el modo en que WCF ejecuta un método, por ejemplo podemos ejecutar código automáticamente antes de que se llame a una operación o después. Este es el caso que veremos en el siguiente ejemplo:

Creación del Servicio

Ok manos a la obra, lo primero es crear un nuevo proyecto WCF, el cual llamaremos “CalculatorService”

image

Luego agregamos dos operaciones a nuestro servicio, tanto en la interfaz como en la implementación: Add y Substract, como se ve en la siguiente figura:

image

Estas dos funciones lo que hacen es agregar y restar un valor de la variable de instancia _currentValue.

Ejecutamos el proyecto, y Visual Studio abrirá un cliente básico para poder probar nuestro servicio:

image

Behaviors

Ahora haremos algo interesante: Cada vez que se llame al método Add o Substract invocaremos de forma automática a un tercer método llamado “Audit”, esto lo hacemos usando OperationBehviors que nos permitirá tener acceso a personalizar la invocación de nuestros métodos.

En el proyecto de nuestro servicio WCF creamos una nueva carpeta llamada Behaviors ya agregamos una nueva clase llamada “MyOperationBehavior.cs” con el siguiente código:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;

namespace CalculatorService.Behaviors
{
    public class MyOperationBehavior : Attribute, IOperationBehavior
    {

        #region IOperationBehavior Members

        public void AddBindingParameters(OperationDescription operationDescription, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyClientBehavior(OperationDescription operationDescription, System.ServiceModel.Dispatcher.ClientOperation clientOperation)
        {
        }

        public void ApplyDispatchBehavior(OperationDescription operationDescription, System.ServiceModel.Dispatcher.DispatchOperation dispatchOperation)
        {

// Decorator pattern.
            dispatchOperation.Invoker = new MyOperationInvoker(dispatchOperation);
        }

        public void Validate(OperationDescription operationDescription)
        {
        }

        #endregion
    }

    class MyOperationInvoker : IOperationInvoker
    {
        private readonly IOperationInvoker _invoker;
        private readonly System.ServiceModel.Dispatcher.DispatchOperation _dispatchOperation;

        public MyOperationInvoker(System.ServiceModel.Dispatcher.DispatchOperation dispatchOperation)
        {
            this._invoker = dispatchOperation.Invoker;
            this._dispatchOperation = dispatchOperation;
        }

        private void HandleOperationRequest(object instance, object[] inputs)
        {
            Service1 srv = (Service1)instance;
            srv.Audit(_dispatchOperation.Name, inputs);
        }

        #region IOperationInvoker Members

        public object[] AllocateInputs()
        {
            return _invoker.AllocateInputs();
        }

        public object Invoke(object instance, object[] inputs, out object[] outputs)
        {
            HandleOperationRequest(instance, inputs);
            return _invoker.Invoke(instance, inputs, out outputs);
        }

        public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
        {
            HandleOperationRequest(instance, inputs);
            return _invoker.InvokeBegin(instance, inputs, callback, state);
        }

        public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
        {
            return _invoker.InvokeEnd(instance, out outputs, result);
        }

        public bool IsSynchronous
        {
            get { return _invoker.IsSynchronous; }
        }

        #endregion
    }
}

Ahora decoramos nuestros métodos Add y Substract con el atributo anterior y creamos el método “Audit”:

image

Lo que hemos hecho hasta el momento es crear una clase MyOperationBehavior que se encarga de conectar el MyOperationInvoker al servicio. Al aplicar el atributo  [MyOperationBehavior] en cada operación hacemos que WCF use nuestro Operation Invoker para llamar a las respectivas funciones.

Dentro de MyOperationInvoker estamos llamando primero al método Audit para imprimir en pantalla la operación que el usuario está a punto de ejecutar.

Esto nos da el control de poder ejecutar código adicional antes de que se ejecute el método que invocó el cliente (o incluso desués). Si volvemos a ejecutar el servicio podemos ver los resultados en la ventana “Output” de Visual Studio 2010.

image

Nota: Este mismo resultado se pudo obtener llamando desde los métodos Add y Substract al método Audit. Pero gracias a los OperationBehaviors podemos remover esta lógica de cada posible método que tengamos y ponerla en un solo lugar.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: