Início > WCF > WCF Routing – Parte 3 (Final)

WCF Routing – Parte 3 (Final)

21 de abril de 2011 Deixe um comentário Go to comments

Para entender o contexto do artigo, leia a parte 2

Criando o Serviço de Routing:

No projeto WCFRoute.Router, exclua todos os arquivos criados com o template exceto o web.config e o Service1.svc. Veja na imagem abaixo, como deverá ficar:

04-route

No arquivo Service1.svc altere a declaração do ServiceHost, conforme exemplo abaixo:

<%@ ServiceHost Language="C#" Debug="true" Service="System.ServiceModel.Routing.RoutingService,
System.ServiceModel.Routing, version=4.0.0.0, Culture=neutral,PublicKeyToken=31bf3856ad364e35" %>

Repare que a uma diferença os serviços comuns hospedados com o .SVC, pois no atributo Service normalmente declaramos a classe de nosso serviço e agora estamos declarando a classe RoutingService. No arquivo de configuração (web.config) iremos deixar nossas regras de Roteamento, também poderiamos criar nossa regra no código gerenciado (C# ou VB).

Feito o procedimento acima, abra o arquivo web.config do projeto WCFRoute.Router e declare o serviço do Routing, exemplo:

    <services>
      <service name="System.ServiceModel.Routing.RoutingService" behaviorConfiguration="routerSvc">
        <endpointaddress ="http://localhost:8734"binding="basicHttpBinding"  contract="System.ServiceModel.Routing.IRequestReplyRouter"/>
       
<endpointaddress="mex"binding="mexHttpBinding" contract="IMetadataExchange"/>
    </service>
</services>

Importante notar que o endpoint esta configurado com basicHttpBinding, ou seja, nosso roteador esta recebendo uma requisição em um binding diferente dos binding do serviços (Service1 e Service2) que são WsHttpBinding, este comportamento é perfeitamente normal. Outro ponto importante é que no contrato do nosso serviço estamos declaramos as interfaces que irão definir os modelos de operações que no nosso caso é o IRequestReplyRouter (veja no inicio do artigo mais informações do que faz cada interface/contrato). Também especificamos um behaviorConfiguration chamado routerSvc, este behavior irá conter a informação da tabela de filtro que iremos usar em nosso serviço.  Com nosso serviço e seus endpoint configurados iremos agora criar nosso Behavior chamado routerSvc, veja abaixo sua implementação:

   <behaviors>
      <serviceBehaviors>
        <behaviorname="routerSvc">
          <routingfilterTableName="mainRouterTable" routeOnHeadersOnly="False"/>
          <serviceMetadatahttpGetEnabled="True"></serviceMetadata>
          <serviceDebugincludeExceptionDetailInFaults="True" />
        </behavior>
      </serviceBehaviors>
    </behaviors>

Neste behavior associamos uma configuração do Routing e dentro desta configuração vinculamos uma tabela de filtros (iremos criar no próximo passo) chamada mainRouterTable. Por fim criaremos nossos filtros (critérios/condições) que irão identificar a mensagem e encaminhar para os respectivos serviços, esses filtros (<filter>) são uma seção dentro da configuração do Routing (<routing>) e são agrupados por uma tabela de filtros (<filtertable>) que é vinculada ao Behavior (exemplo acima). Veja abaixo um exemplo:

<routing>
      <filters>        <filtername="teste" filterType="Action" filterData="http://exemplo/Router/GetDataUsingDataContract"/>
        <filtername="teste1" filterType="Action" filterData="http://exemplo/Router/GetData"/>
      </filters>
</routing>

No exemplo acima estamos criando uma lista de filtros (<filters>) e inserindo nesta lista dois filtros (<filter>) sendo o teste e teste1. Ambos os filtros estão com o tipo de filtro por ação (“Action”), ou seja, iremos pegar a ação que veio do cliente e de acordo com a ação (operação) iremos encaminhar para os respectivos serviços, note que o filterType é o critério que irá utilizar para filtrar e o filterData é o valor do critério.

Poderiamos usar outro filterType ? Sim é possível, atualmente vários filterType, segue alguns:

Action: Filtro pela ação que esta sendo requisitada.
MatchALL: Filtro por qualquer mensagem recebida (como se fosse um sem filtro), utilizado para rotear mensagens para serviços sem nenhum criterio.
EndpointName: Filtro pela nome do endpoint.
EndpointAddress: Filtro pelo endereço de endpoint que a requisição foi recebida, neste caso ele usa o “fully qualified domain name” ou seja o nome completo do serviço (http://localhost/service1.svc/getData).
EndpointAddressPrefix: Similar ao EndpointAddress, no entanto você pode usar nomes relativos, podendo o mesmo filtrar por inicio de um nome (http://localhost/*)
And: Um filtro que você pode utilizar para fazer combinações de filtros.
XPath: Filtro que permite você especificar um XPath que ira inspecionar elementos da mensagem.
Custom: Filtro pela uma ação customizada, você pode criar um assembly com sua regra de filtro (contenha MessageFilter).

Depois de ter criado nossos filtros, vinculamos ele a uma tabela de filtros <filterTable> que irá fazer o mapeamento entre o filtro e o endpoint do serviço cliente para qual encaminharemos a mensagem.

<filterTablename="mainRouterTable">
          <addendpointName="getDataContract"filterName="teste" />
          <addendpointName="getDataWithoutContract"filterName="teste1" />
</filterTable>

 

 

 

 

No filtertable temos os seguintes atributos EndpointName que é o nome do endpoint cliente que iremos definir no próximo passo e o filterName que é o nome do filtro, para nosso exemplo iremos criar dois enpoints que irão apontar para o Servico1 e Servico2 e iremos vincular os filtros criados no passo anterior com cada um destes endpoint. Abaixo a criação dos nossos endpoints que irão apontar para os respectivos serviços, valelembrar que os endpoints ficam dentro da configuração de clientes, pois estes serviços serão consumidos pelo nosso serviço de Routing.

    <client>
      <endpointaddress="http://localhost:8732/WCFRoute.Service1/Service1/" contract="*" binding="wsHttpBinding"name="getDataContract"></endpoint>
      <endpointaddress="http://localhost:8731/WCFRoute.Service2/Service2/" contract="*"binding="wsHttpBinding" name="getDataWithoutContract" ></endpoint>
    </client>

Por fim, nosso arquivo web.config do nosso serviço de Router deverá ficar conforme o exemplo abaixo:

<?xmlversion="1.0"encoding="utf-8" ?>
<configuration>
  <system.web>
    <compilationdebug="true" />
  </system.web>
  <system.serviceModel>
    <services
      <servicename="System.ServiceModel.Routing.RoutingService" behaviorConfiguration="routerSvc">
      <endpointaddress ="http://localhost:8734"binding="basicHttpBinding"  contract="System.ServiceModel.Routing.IRequestReplyRouter"/>
        <endpointaddress="mex"binding="mexHttpBinding" contract="IMetadataExchange"/>
      </service>
    </services>
    <client>
      <endpointaddress="http://localhost:8732/WCFRoute.Service1/Service1/" contract="*" binding="wsHttpBinding"name="getDataContract"></endpoint>
      <endpointaddress="http://localhost:8731/WCFRoute.Service2/Service2/" contract="*"binding="wsHttpBinding"name="getDataWithoutContract"> </endpoint>
    </client>
    <behaviors>
      <serviceBehaviors>
        <behaviorname="routerSvc">
          <routingfilterTableName="mainRouterTable" routeOnHeadersOnly="False"/>
          <serviceMetadatahttpGetEnabled="True"> </serviceMetadata>
          <serviceDebugincludeExceptionDetailInFaults="True" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <routing>
      <filters>
        <filtername="teste"filterType="Action" filterData="http://exemplo/Router /GetDataUsingDataContract"/>
        <filtername="teste1"filterType="Action" filterData="http://exemplo/Router/GetData"/>
      </filters>
      <filterTables>
        <filterTablename="mainRouterTable">
          <addendpointName="getDataContract"filterName="teste" />
          <addendpointName="getDataWithoutContract"filterName="teste1" />
        </filterTable>
      </filterTables>
    </routing>
  </system.serviceModel>
</configuration>

Praticamente esta pronto nosso Router, agora iremos configurar nosso cliente para chamar o Router e fazer os devidos testes, para isso expanda o projeto WCFRouter.Client e altere o método Main da classe Program para efetuar as devidas chamadas:

namespace WCFRoute.Client
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                IService1 proxy = ChannelFactory<IService1>
.CreateChannel(new BasicHttpBinding(),
new EndpointAddress(http://localhost:8734/Service1.svc));
               CompositeType entity = new CompositeType();
                entity.StringValue = "Nelson";
                var retorno = proxy
.GetDataUsingDataContract(entity);             

                 IService2 proxy2 = ChannelFactory<IService2>
.CreateChannel(new BasicHttpBinding(),
new EndpointAddress(http://localhost:8734/Service1.svc));
                 var retorno2 = proxy2.GetData();
            }

            catch (Exception ex)
            {
                Console.WriteLine("Ocorreu um erro ao chamar o serviço");
            }
        }
    }
}

 
Repare que estamos chamando o serviço do Router (HTTP://localhost:8734/Service.svc) e o mesmo encaminha as requisições para os respectivos serviços, agora basta rodar e efetuar os devidos testes.

Nosso “encaminhador” de mensagens esta finalizado, para ficar ainda melhor, poderiamos criar um Serviço3 e deixar como backup de ambos os serviços, ou seja caso um dos serviços falhe (não esteja operante) ele iria encaminhar para o serviço de backup. Para fazer isso basta eu alterar o FilterTable para usar um BackupList que conteria um outro EndpointName:

<filterTables>
        <filterTablename="mainRouterTable">
          <addendpointName="getDataContract"filterName="teste" backupList="otherService"   />
          <addendpointName="getDataWithoutContract"filterName="teste1" backupList="otherService"   />
        </filterTable>
</filterTables>

Defina dentro da tag Routing a configuração do BackupList, e dentro dele insira o EndpointName:

<backupLists>
        <backupList>
            <addendpointName="EndpointServico3Backup"/>
        </backupList>
</backupLists>

Enfim, espero que tenham gostado desta série de artigos onde explico como Criar o WCF Routing, também estou disponibilizando os fontes para download.

Abraço e até a proxima.

Categorias:WCF
  1. Jeflley
    15 de março de 2012 às 10:16

    Você teria um exemplo que funcione utilizando filtro por EndPointName? Tentei utilizar e não consegui nada no google ou no msdn que me ajudasse.

  1. No trackbacks yet.

Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

%d blogueiros gostam disto: