Reutilizando tipos entre serviços


Ao consumir um serviço SOAP, geralmente utilizamos o documento WSDL para montar todos os artefatos necessários para efetuar a comunicação com o serviço, que é executado remotamente. Esse documento traz todas as funcionalidades expostas por aquele serviço, diretivas de como essa comunição deve ser realizada, e ainda, informações que descrevem eventuais objetos complexos que fazem parte do contrato.

Em um cenário específico, podemos criar mais de um serviço que recebe ou expõe uma mesma classe. Essa classe é criada do lado do serviço, e este tipo pode ser utilizado por qualquer serviço que consiga acessá-la. Subindo estes dois serviços, ambos podem também ser referenciados em um mesmo cliente, e quando utilizamos o Visual Studio, ele faz o download do WSDL, constrói proxy e remonta todos os tipos deste lado, para que o cliente possa enviá-los e/ou recebê-los, conseguindo assim reconstruir os objetos no cliente, trabalhando de forma tipada.

Só que quando temos esse cenário, podemos nos deparar com um detalhe no cliente que pode parecer confuso em um primeiro momento. Para exemplificarmos, repare no simples código que temos abaixo. Há uma classe chamada Usuario com apenas uma propriedade. Temos dois contratos, onde cada um está implementado em um serviço diferente, e tudo o que as operações destes contratos fazem, é enviar e receber a instância da classe Usuario.

public class Usuario
{
    public string Nome { get; set; }
}

[ServiceContract]
public interface IContrato1
{
    [OperationContract]
    Usuario Metodo1(Usuario usuario);
}

public class Servico1 : IContrato1
{
    public Usuario Metodo1(Usuario usuario) { }
}

[ServiceContract]
public interface IContrato2
{
    [OperationContract]
    Usuario Metodo2(Usuario usuario);
}

public class Servico2 : IContrato2
{
    public Usuario Metodo2(Usuario usuario) { }
}

Aqui foi omitido, mas temos o código que expõe estes dois serviços através do protocolo HTTP, utilizando o binding BasicHttpBinding. Em primeiro lugar, referenciamos na aplicação cliente o Servico1. Isso faz com que o Visual Studio crie o tipo Usuario no cliente. Depois disso, decidimos referenciar o Servico2 também neste mesmo cliente, que como sabemos, também utiliza a classe Usuario. Ao fazer isso, o Visual Studio acaba recriando o tipo Usuario, mas agora para atender o segundo serviço.

Apesar de que do lado do servidor ambos serviços utilizam o mesmo tipo, ao referenciar no cliente, o Visual Studio não tem poder de identificar isso e, consequentemente, acaba sendo criado duas classes Usuario, onde cada um atende um serviço específico, e elas não podem ser compartilhadas, ou melhor, utilizar uma delas no lugar da outra. A imagem abaixo ilustra isso essa separação:

Para certificar da independência entre as classes Usuario dos servicos, podemos visualizar o código abaixo, que é uma versão resumida do que é gerado do lado do cliente para ambos os serviços referenciados. Para cada um dos deles, temos um namespace distinto, e debaixo destes, uma classe Usuario para cada. Mais adiante, podemos perceber que no interior de cada um dos métodos, eles referenciam a respectiva classe Usuario que está dentro de seu próprio namespace.

namespace Cliente.Servico1
{
    public partial class Usuario { }
    
    public interface IContrato1
    {
        Cliente.Servico1.Usuario Metodo1(Cliente.Servico1.Usuario usuario);
    }

    public partial class Contrato1Client
    {
        public Cliente.Servico1.Usuario Metodo1(Cliente.Servico1.Usuario usuario) { }
    }
}

namespace Cliente.Servico2
{
    public partial class Usuario { }
    
    public interface IContrato2
    {
        Cliente.Servico2.Usuario Metodo2(Cliente.Servico2.Usuario usuario);
    } 

    public partial class Contrato2Client
    {
        public Cliente.Servico2.Usuario Metodo2(Cliente.Servico2.Usuario usuario) { }
    }
}

O que vimos acima, é o suficiente para proibir que se use uma mesma classe Usuario para ambos os serviços. E, para que isso seja possível, temos algumas alternativas. A primeira delas seria, depois de referenciado ambos os serviços, elegermos uma das classes Usuario e levá-la para um local centralizado, talvez em um outra namespace, e depois disso, alterar os locais em que elas estão sendo referenciadas, e apontar para esta “nova” classe/local.

Uma outra opção que temos, que acredito ser até mais elegante, seria recorrer ao utilitário svcutil.exe, e gerar todos os recursos necessários para consumir um dos serviços. Depois das classes criadas, você deve criar um projeto do tipo Class Library, e colocar essas classes que foram geradas dentro dele. Com isso, você compila o projeto e gera uma DLL contendo o proxy e a classe Usuario. De posse desta DLL, você referencia na aplicação cliente que deve utilizar este serviço. Abaixo temos a linha de comando que gera as classes para o primeiro servico:

C:>svcutil http://localhost:8888

Depois da DLL referenciada, podemos agora adicionar a referência para o segundo serviço no próprio Visual Studio, que por padrão, ele é capaz, de antes de gerar os tipos que o serviço disponibiliza, analisar se esse tipo já existe referenciado na aplicação local, e caso exista, ele o reutilizará. Abaixo temos a imagem que ilustra essa configuração de reuso:

Finalmente, a última opção que temos é o compartilhamento do tipo entre o serviço e o cliente. Inclusive, isso evita a necessidade de fazer a referência para o serviço, pois todos os artefatos que você precisa para consumir o serviço (que são os contratos), já estarão disponíveis através do compartilhamento de uma DLL entre as pontas, o que obriga ambos os lados serem .NET. Qualquer uma dessas alternativas apontadas acima, tem como objetivo o compartilhamento/centralização de tipos do lado do cliente, assim como podemos visualizar na imagem abaixo:

Anúncios

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