Expondo e Consumindo POCO como Serviço WCF usando Spring Framework

Publicado por Ricardo Ushisima
04/11/2011
Categoria:
Tags: , , , , , ,

Há quase 1 anos atrás, postei uns artigos sobre Web Services com Spring Framework. Naquela época estavamos começando a adotar o WCF (Windows Communication Framework) para implementação de nossos serviços remotos em substituição aos tradicionais Web Services. O WCF é interoperável com serviços Web Services mas a funcionalidade que nos interessava mais é o maior controle sobre o canal de comunicação que o WCF permite. Não vou entrar em detalhes agora sobre WCF (fica para artigos futuros), mas vou revisitar meus artigos sobre Web Services mas agora usando o WCF.

Logo, neste artigo, vou mostrar rapidamente como expor e consumir um POCO como um serviço WCF usando o Spring Framework. Vou usar o mesmo exemplo que dei quando escrevi o primeiro artigo Expondo POCO como Web Services usando Spring Framework. No meu exemplo, o serviço é hospedado em um IIS, mas o serviço poderia ser self-hosted, como demostrado no artigo Criando serviços WCF com Spring.NET.

Expondo POCO como serviço WCF.

Expor o POCO como serviço WCF usando Spring Framework não é tão limpo quanto expor como Web Service. É necessário “anotar” o POCO com os atributos requeridos pelo framework do WCF. O Spring Framework ainda não é capaz de lidar com esses atributos.

Na interface do serviço, é preciso declarar o contrato do serviço:

using System;
using System.ServiceModel;
using System.Runtime.Serialization;

namespace SpringTutorial
{
    [ServiceContract(Namespace="http://zbra.com.br/SpringTutorial")]
    public interface ICurrencyService
    {
        [OperationContract]
        decimal Convert(string from, string to, decimal value);
    }
}

Na implementação do serviço, é necessário configurar alguns aspectos do serviço WCF (não vou entrar em detalhes da configuração neste artigo):

using System;
using System.Collections.Generic;

namespace SpringTutorial.Core
{
    [ServiceBehavior(Namespace = "http://zbra.com.br/SpringTutorial", ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.Single)]
    public class CurrencyService : ICurrencyService
    {
        private readonly Dictionary<string, decimal> exchangeRates = new Dictionary<string, decimal>();

        public CurrencyService()
        {
            InitCurrencyExchangeRates();
        }

        private void InitCurrencyExchangeRates()
        {
            exchangeRates.Add("BRL", 1); //Base Rate
            exchangeRates.Add("USD", 1.68m);
            exchangeRates.Add("EUR", 2.24m);
        }

        public decimal Convert(string from, string to, decimal value)
        {
            decimal fromRate = exchangeRates[from];
            decimal toRate = exchangeRates[to];
            decimal baseValue = value * fromRate;
            return baseValue / toRate;
        }
    }
}

No Web.config é necessário configurar os endpoint do WCF:

<configuration>
  <configSections>
    <sectionGroup name="spring">
      <section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/>
    </sectionGroup>
  </configSections>
  <spring>
    <context>
      <resource uri="~/Spring.xml"/>
    </context>
  </spring>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <services>
      <service name="currencyService">
        <endpoint address="" binding="basicHttpBinding" bindingNamespace="http://zbra.com.br/SpringTutorial" contract="SpringTutorial.ICurrencyService"/>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
      </service>
    </services>
    <!-- (...) -->
  </system.serviceModel>
 <!-- (...) -->
</configuration>

O Spring.xml é o mesmo da versão Web Service:

<objects xmlns="http://www.springframework.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd">

  <object id="currencyService" type="SpringTutorial.Core.CurrencyService, SpringTutorial.Core" singleton="false">
  </object>

</objects>

Na versão Web Service, o Spring Framework intercepta chamadas para a extensão asmx para fazer seu trabalho. Não é necessário um arquivo com a extensão asmx. Mas na versão WCF, é necessário um arquivo com a extensão SVC (extensão padrão dos serviços WCF). É nesse arquivo (CurrencyConverter.svc) que esta configuração do Spring para expor um objeto como serviço WCF.

<%@ ServiceHost Language="C#" Debug="true" Service="currencyService" Factory="Spring.ServiceModel.Activation.ServiceHostFactory" %>

Nesse arquivo, o factory padrão do WCF é substituido por um do Spring Framework e o nome do serviço é o nome do objeto no spring que implementa o contrato do serviço.

Consumindo o serviço WCF

No lado cliente, a alteração é somente de configuração (endpoints WCF e Spring.xml). Não há alteração de código.

No Web.config, configura-se os endpoint WCF:

<configuration>
  <configSections>
    <sectionGroup name="spring">
      <section name="context" type="Spring.Context.Support.WebContextHandler, Spring.Web"/>
    </sectionGroup>
  </configSections>
  <spring>
    <context>
      <resource uri="file://~/Spring.xml"/>
    </context>
  </spring>
  <system.serviceModel>
    <client>
      <endpoint binding="basicHttpBinding" contract="SpringTutorial.ICurrencyService" name="BasicHttpBinding_ICurrencyService" />
    </client>
  </system.serviceModel>
  <system.web>
    <compilation debug="true" targetFramework="4.0"/>
    <httpHandlers>
      <remove verb="*" path="*.aspx"/>
      <add verb="*" path="*.aspx" type="Spring.Web.Support.PageHandlerFactory, Spring.Web"/>
    </httpHandlers>
    <httpModules>
      <add name="Spring" type="Spring.Context.Support.WebSupportModule, Spring.Web"/>
    </httpModules>
  </system.web>
</configuration>

No Spring.xml, muda a configuração da WebServiceProxyFactory que ao inves de acessar a URL do serviço remoto diretamente, obtem uma instancia do serviço atraves de uma fábrica do próprio WCF. Nesse fábrica esta configurado qual configuração endpoint é utilizada e qual é a url do serviço WCF.

<objects xmlns="http://www.springframework.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd">

  <object id="ClientSideFaultAdvice" type="SpringTutorial.Util.ClientSideExceptionAdvice, SpringTutorial.Util">
  </object>

  <object id="currencyService" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">
    <property name="proxyInterfaces" value="SpringTutorial.ICurrencyService"/>
    <property name="target" ref="currencyServiceTarget"/>
    <property name="InterceptorNames">
      <list>
        <value>ClientSideFaultAdvice</value>
      </list>
    </property>
  </object>
  <object id="currencyServiceTarget" type="SpringTutorial.ICurrencyService, SpringTutorial"
          factory-object="currencyServiceFactory"
          factory-method="CreateChannel" />
  <object id="currencyServiceFactory"
          type="System.ServiceModel.ChannelFactory&lt;SpringTutorial.ICurrencyService&gt;, System.ServiceModel">
    <constructor-arg name="endpointConfigurationName" type="System.String" value="BasicHttpBinding_ICurrencyService" />
    <constructor-arg name="remoteAddress" type="System.ServiceModel">
      <object type="System.ServiceModel.EndpointAddress">
        <constructor-arg value="http://localhost:59111/CurrencyConverter.svc"/>
      </object>
    </constructor-arg>
  </object>

  <object type="Default.aspx">
    <property name="CurrencyService" ref="currencyService" />
  </object>
</objects>

Como você pode notar, a maior diferença entre a versão Web Service e a versão WCF é a configuração dos endpoints WCF e das anotações nos POCO’s expostos como serviço. A alteração da minha aplicação cliente para utilizar WCF ao invés de Web Services foi feita apenas por configuração, sem qualquer alteração no código do cliente. Ponto para a arquitetura básica da aplicação que isola a camada de serviço atrás de interfaces (API) e o uso do Spring Framework.

Referencias:





Desenvolvido por hacklab/ com WordPress