Overview do Windows Identity Foundation

Os desafios de desenvolver aplicações que exigem um alto nível de segurança e as soluções oferecidas pela Microsoft para transformar essa tarefa em algo bem mais simples e reutilizável do que existe atualmente.

Com a finalidade de introduzir esse novo framework, coloquei as dificuldades que temos atualmente, a proposta e o modelo básico de objetos que o WIF fornece, em um artigo na edição 26 da revista MundoDotNet. Gostaria de agradecer ao Daniel de Oliveira pela oportunidade.

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:

WCF Web API – Consumo de Serviços

O WCF-REST Starter Kit fornece uma classe chamada HttpClient, que tem a finalidade de facilitar o consumo de serviços REST em aplicações escritas em .NET (ASP.NET, Console, Windows, etc.). Apesar de ser possível efetuar o consumo de serviços utilizando as classes de baixo nível (HttpWebRequest e HttpWebResponse), a classe HttpClient acaba sendo uma classe “intermediária”, ou seja, não chega a ser tão simples como um proxy de um serviço e não tão complicada como as classes do namespace System.Net.

Essa classe possibilita o consumo deste tipo de serviço sem tirar do desenvolvedor, o controle de todo o protocolo onde as requisições e respostas trafegam, fornecendo outras classes que foram construídas com o intuito de compor e facilitar essa interação. A classe HttpClient já está disponível há algum tempo, e já falei sobre ela neste artigo.

O que quero com este breve post, é alinhar a evolução da mesma, que assim como está acontecendo com o restante do WCF-REST Starter Kit, ela também está sendo trazida para dentro do .NET/WCF, que por sua vez, se tornará a API para o consumo de serviços REST na plataforma .NET. Assim como comentei no artigo anterior, basta você adicionar o WCF Web API através do Nuget, que vários assemblies serão incluídos na aplicação, e com isso, já poderá fazer uso dela.

Ao adicionar este pacote, o assembly Microsoft.Net.Http.dll é referenciado na aplicação, o que nos permitirá fazer uso de classes como HttpClient, HttpRequestMessage (HttpRequestMessage<T>), HttpResponseMessage (HttpResponseMessage<T>), ObjectContent<T>, etc. Essas classes estão debaixo do namespace System.Net.Http, e para consumir aquele mesmo serviço de prospecção que foi criado no artigo anterior, poderíamos proceder da seguinte forma:

using (HttpClient http = new HttpClient(“http://localhost:1989/prospeccoes/&#8221;))
{
    using (HttpRequestMessage request1 = new HttpRequestMessage(HttpMethod.Post, “Adicionar”))
    {
        request1.Content = new ObjectContent<Empresa>(new Empresa() { Nome = “Empresa 1” });
        request1.Content.Headers.ContentType = new MediaTypeHeaderValue(“application/xml”);

        Console.WriteLine(http.Send(request1).StatusCode);
    }

    using (HttpRequestMessage request2 = 
        new HttpRequestMessage(HttpMethod.Get, “RecuperarEmpresasEmProspeccao”))
    {
        foreach (var item in http.Send(request2).Content.ReadAs<List<Empresa>>())
            Console.WriteLine(item.Nome);
    }
}

Como podemos perceber, grande parte do que existe no WCF-REST Starter Kit começa a ser transportado para esta nova API.