Fala Pessoal, tudo bem?

Para aqueles que não me conhecem, meu nome é Leandro Elias Bichara, sou graduado em Análise e Desenvolvimento de Sistemas e atuante no mercado de TI a pelo menos 11 anos. Trabalho com desenvolvimento de sistemas Windows, Web e Mobile e posso confessar que sou fanático por tecnologia :-D.

Antes de iniciar este post gostaria de aproveitar o momento para agradecer ao André Paulovich e ao Luciano Lima, pela imensa ajuda na tentava de solucionarmos este problema e também pelo convite de participar aqui do 100loop.

Sem mais delongas, vamos ao post.

Em um cenário de aplicações distribuídas é muito comum termos uma separação lógica de camadas bem mais complexa do que um simples modelo 3 camadas, posso usar como exemplo um projeto que estou trabalhando que funciona da seguinte forma:

  • Um usuário faz a separação de alguns itens de seu interesse em uma aplicação que possui interfaces Mobile, Windows e Web (cada usuário escolhe sua interface);
  • A aplicação envia os dados para um WS (Web Service) que comunica com alguns subsistemas a titulo de validações e processamento das informações como:
    • Validações e verificação de dependências (feita por uma class library, camada de negócio)
    • Consulta de disponibilidade de itens (feito através de um WS no servidor de cada uma das empresas conveniadas)
    • Gravação de parte das informações em um servidor mainframe IBM (através de comunicação Socket)
    • Gravação em um banco de dados central com redundância das informações em um banco de dados local (contingência de dados para atuar em modo off-line)

Neste cenário, o mais comum e a necessidade de transportarmos uma mesma informação entre todos estes ambientes, permitindo que cada subsistema possa fazer a utilização destes dados e se necessário alterá-los.

Enquanto as comunicações entre estes projetos se fazem através do tradicional (passagem de argumento através de tipos de dados primitivos e/ou consumo direto de uma DLL referenciada) nós não problemas, mas, quando tentamos passar como argumento para um web service um tipo de dados composto (classe) que tem sua definição em um terceiro projeto, BOOOM… Houston, we have a problem.

Como exemplo criei um mini projeto para traduzir toda esta novela e mostrar como resolver este problema.

A solução é composta por 4 camadas lógicas, definidas como:

  • Entidade – Projeto class library, sua finalidade é fornecer tipos de dados compostos, capazes de serem transportados e consumidos entre todos os outros projetos.
  • Negocio – Projeto class library, visa aplicar todas as regras de negócio conforme a necessidade do seu projeto.
  • Servico – Projeto web, sua finalidade e fornecer interfaces WS capazes de permitir a integração da aplicação com outros ambientes.
  • Windows – Projeto Windows, tem como objetivo fornecer o acesso as informações em um ambiente desktop.

 

 

 

 

 

 

 

Neste exemplo o objetivo é bem simples, apenas autenticar um usuário, ou seja, a aplicação Windows solicita ao WS a autenticação de um usuário, conforme as regras da camada de negócio.

O detalhe, neste tipo de implementação, é que o parâmetro a ser passado para o web service, não será o login e a senha (variáveis do tipo string), será um tipo de dados composto, uma variável do tipo Usuario, lá do projeto class library, conforme vimos na imagem acima.

DETALHAMENTO DOS PROJETOS NA SOLUÇÃO

Projeto Entidade – Classe Usuario

Projeto class library, classe Usuario, namespace Entidade

 

Projeto Negocio – Classe Autenticacao

Projeto Negocio – Classe Autenticacao - Namespace Negocio

 

Projeto Servico – Classe Autenticacao (Autenticacao.asmx)

Projeto Servico – Classe Autenticacao (Autenticacao.asmx) - Namespace Servico

Projeto Windows – Classe Form1

Projeto Windows – Classe Form1 - Namespace Windows

Podemos observar na imagem anterior que ao tentarmos passar como argumento o usuário do tipo Entidade.Usuario o Visual Studio já informa que o método não suporta aquele tipo de parâmetro, como pode?

Vejam que a declaração do parâmetro no WS é do mesmo tipo do usuário que eu criei.

Este problema ocorre, assim que fazemos a referência do WS em um dos nosso projetos, o Visual Studio cria o que chamamos de Proxy, das classes que ele utiliza, ou seja ele faz uma redefinição dessas classes, dentro do projeto WS, a fim de ser fornecido como modelo pra quem for consumir este serviço.

Assim o argumento correto seria um Windows.Servico.Usuario, tipo criado automaticamente pela referencia do WS ( o tal Proxy ).

Como resolver este problema já que todo o resto do sistema utiliza dados do tipo Entidade.Usuario?

  • Fazer um cast de Windows.Servico.Usuario para Entidade.Usuario? Não, o Proxy não cria uma classe derivada da classe original, portanto não permite o cast.
  • Fazer uma conversão de dados? Não, daria muito trabalho e ficaria muito estranho uma conversão para manter o dado do mesmo tipo entre projetos diferentes.
  • Criar uma nova instância do tipo Windows.Servico.Usuario e transferir os dados do objeto original para esta? Nem pensar.

EM FIM, A SOLUÇÃO

A solução pra este problema é muito mais simples do que imaginávamos,  para isto precisamos apenas de 3 ações:

  1. Após referenciar o WS, abra o arquivo “Reference.cs”, que está dentro da subpasta “Web References/nome_do_servico” do seu projeto;
  2. Procure e exclua a declaração das classes que ele redefiniu, no nosso exemplo a classe Usuario.
  3. No topo do arquivo faça a referencia ao namespace da classe original, no nosso caso o namespace Entidade.Obs.: Caso não tenha feito referencia do projeto Entidade no projeto atual, faça-o antes destes três passos.

Neste momento já podemos consumir o web service sem nenhum problema de compatibilidade de tipos, pois agora usamos o mesmo tipo de dados em todos os projetos da solução 🙂

É importante saber que este três passos são necessários todas as vezes que você fizer uma update na referencia do WS ou quando recria-la.

Pra obter uma cópia deste projeto, já com o problema solucionado, basta acessar o link  goo.gl/BTir3.

Espero que essa dica possa ajudar a tantos outros que, assim como eu, ficaram dias e dias a procura de uma solução para este problema.

Um grande abraço e até a próxima!