Utilizando o DataReader Assincronamente

by Israel Aece 22. April 2012 21:58

Na versão 2.0 do .NET Framework, a Microsoft incluiu uma série de novas funcionalidades em sua API de acesso a dados, o ADO.NET. Entre elas, podemos destacar o código genérico, MARS, Bulk-Copy e execução assíncrona de comandos e consultas.

O que tínhamos disponível naquela época é a implementação através do modelo assíncrono do .NET, que era implementado utilizando um par de métodos BeginXXX/EndXXX. Sendo assim, o método ExecuteReader passou a ter os métodos BeginExecuteReader e EndExecuteReader, enquanto o método ExecuteNonQuery, ganhou os métodos BeginExecuteNonQuery e EndExecuteNonQuery.

Da mesma forma, para ficar alinhado a nova forma de se trabalhar assincronamente nas linguagens, a execução assíncrona de comandos e consultas no ADO.NET 4.5 sofreu algumas mudanças, para seguir o modelo baseado em Tasks. Além das mudanças em nível das interfaces das classes, um detalhe importante é que não é mais necessário definir o flag Asynchronous Processing para True no arquivo de configuração, algo que sempre era descoberto somente depois que a aplicação estava em execução.

Para iniciar, a classe que representa a conexão (SqlConnection/DbConnection) fornecem a versão assíncrona do método Open, que é o OpenAsync. Este método retorna uma Task, o que a torna "aguardável", e com isso, podemos utilizar a keyword await para que a abertura possa ser realizada de forma assíncrona. Abaixo o código ilustra o uso deste método:

private async static Task Executar()
{
    using (var conn = new SqlConnection("..."))
    {
        await conn.OpenAsync();

        //...
    }
}

Como já era de se esperar, os mesmos métodos fornecidos na versão 2.0 do ADO.NET para processamento assíncrono, ganharam na versão baseada em Tasks na versão 4.5. No caso do ExecuteReader, temos o ExecuteReaderAsync. Já para o método ExecuteNonQuery, temos o ExecuteNonQueryAsync e, finalmente, para o ExecuteScalar, existe o ExecuteScalarAsync.

Todos estes métodos tratam-se da nova versão assíncrona, que basicamente retornam um objeto do tipo Task, que representa a tarefa que está sendo executada assincronamente. E, qualquer exceção que eventualmente ocorra dentro do processo assíncrono, ela será retornada/acessada através da Task que foi retornada pelo método. Abaixo temos um exemplo de como ler os dados através de DataReader, utilizando este novo modelo assíncrono:

private async static Task Executar()
{
    using (var conn = new SqlConnection("..."))
    {
        await conn.OpenAsync();

        using (var cmd = new SqlCommand("SELECT * FROM Cliente", conn))
            using (var dr = await cmd.ExecuteReaderAsync())
                while (await dr.ReadAsync())
                    if (!await dr.IsDBNullAsync(1))
                        Console.WriteLine(dr.GetString(1));
    }
}

Acima utilizamos o método ExecuteReaderAsync, mas ao percorrer o result-set retornado, utilizamos o - também novo - método ReaderAsync, que é a versão assíncrona, também baseada em Task,  do método Read do DataReader. Esse método em conjunto os métodos NextResultAsync, IsDBNullAsync e GetFieldValueAsync<T>, fornecem um controle muito mais refinado aos dados que estão sendo extraídos, pois quando olhamos um pouco mais de perto os internals de cada um deles, percebemos que a versão síncrona pode custar caro, prejudicando assim a escalabilidade.

Além disso, todos os métodos que vimos até aqui, possuem um segundo overload que suporta o cancelamento da tarefa custosa que está sendo executada. Para controlar o cancelamento, eles fazem uso da estrutura CancellationToken, e que podemos criar e informar ao invocar o método. Com uma pequena mudança na assinatura do método de exemplo que criamos acima (Executar), ele passará a receber o token que controla e propaga a notificação de cancelamento. Uma vez que o mesmo é repassado às tarefas que são executadas internamente, periodicamente o token é consultado para ver se o cancelamento foi ou não solicitado. A mudança é ligeira:

private async static Task Executar(CancellationToken ct)
{
    using (var conn = new SqlConnection("..."))
    {
        await conn.OpenAsync(ct);

        using (var cmd = new SqlCommand("SELECT * FROM Cliente", conn))
            using (var dr = await cmd.ExecuteReaderAsync(ct))
                while (await dr.ReadAsync(ct))
                    if (!await dr.IsDBNullAsync(1, ct))
                        Console.WriteLine(dr.GetString(1));
    }
}

Como percebemos, para preparar o método para permitir o cancelamento, é receber no parâmetro um CancellationToken, e propagá-lo para os métodos internos. Abaixo, estamos consumindo o método Executar que criamos, só que agora estamos passando um token que que será cancelado em dois segundos. Se depois deste tempo o método não concluir, uma exceção será disparada, informando que a tarefa foi cancelada.

var cts = new CancellationTokenSource();

try
{
    cts.CancelAfter(TimeSpan.FromSeconds(2));
    Executar(cts.Token).Wait();
}
catch (Exception ex)
{
    //trata exceção
}

Tags: , ,

Async | Data

Microsoft Fakes no Visual Studio 2011

by Israel Aece 18. April 2012 23:13

Ao escrever testes unitários antes do código que define as regras dos negócios, conseguimos identificar uma série de detalhes que nos ajuda a definir uma interface clara e consistente para nossos tipos, afinal, já estamos tendo uma visão do consumidor dos mesmos.

Além disso, essa técnica nos ajuda a identificar eventuais dependências que nossos tipos exigem e, consequentemente, isolá-las para que tenham certa flexibilidade, que com isso conseguiremos alternar facilmente entre uma implementação dummy e outra real. E mesmo durante a execução dos testes, é comum utilizarmos uma implementação fictícia, para que ela nos auxilie a testar uma regra específica, onde é irrelevante o uso de uma dependência real.

Outra questão que geralmente ocorre ao escrever testes, é o uso (dependência) de recursos estáticos ou de alguma outra coisa que é díficil simular, como uma classe que não permite sobrescrever seus membros. Um outro grande exemplo dessa dificuldade, é quando temos um código a ser testado que é sensível à data/hora. Como a propriedade Now da estrutura DateTime sempre retorna o horário atual, chamá-la duas vezes, sempre retornará valores diferentes, o que fica difícil definir se o teste sucedeu ou não.

Como parte de diversas melhorias que foram adicionadas na parte de testes do Visual Studo 2011, a Microsoft também incluiu novos recursos para resolver estes pequenos problemas que vimos acima. Microsoft Fakes é framework que ajuda na criação de implementações dummies em nossos testes, onde podemos facilmente simular certas situações injetando um código customizado.

Primeiramente vamos analisar um cenário em que essas novas funcionalidades podem ser interessantes. A classe abaixo, Log, define a estrutura de um item a ser logado. Recebemos em seu construtor a mensagem, e na sequência ele atribui a data atual à propriedade Data.

public class Log
{
    public Log(string mensagem)
    {
        this.Mensagem = mensagem;
        this.Data = DateTime.Now;
    }

    public string Mensagem { get; private set; }

    public DateTime Data { get; set; }
}

Ao escrever um teste que avalie se a data é mesmo atribuída, ele não vai passar. Note que como recorremos à propriedade Now, ela sempre retorna uma data diferente, e por mais que sejam poucos milisegundos, é o suficiente para ser diferente e, consequentemente, o teste falhará.

[TestMethod]
public void DeveAtribuirDataAtualAoLogCriado()
{
    Assert.AreEqual(DateTime.Now, new Log("Mensagem de Log").Data);
}

Eis que entra em cena os Shims. Esse tipo de fake nos permite fornecer uma implementação alternativa a membros estáticos ou tipos que não podem ser facilmente customizados (via herança, por exemplo). Para habilitá-o, temos que ir até o projeto de testes, onde o assembly com os tipos que estão sendo testados está referenciado, e clicar com o botão direito em cima daquele que queremos criar os fakes, e em seguida, na opção "Add Fakes Assembly", assim como vemos na imagem abaixo:

Isso pode ser feito em nossos próprios assemblies ou naqueles do .NET Framework, e independente de qual você escolha, um novo assembly será criado com a infraestrutura necessária para guiar e realizar essa simulação. Os shims são baseados em delegates, o que nos permitirá interceptar a chamada para qualquer método/propriedade, definindo uma "nova" implementação para eles, e que durante a execução, ela será executada, retornando assim, o resultado de acordo com a nossa necessidade. Abaixo a imagem ilustra os assemblies fakes que foram criados para os exemplos:

Logicamente que com esse procedimento, novos tipos foram criados. Como precisamos intervir no retorno da data atual, um novo tipo está disponível: ShimDateTime. A estrutura DateTime fornece a propriedade Now, e neste novo tipo, temos a propriedade NowGet (Get porque Now é somente leitura). Essa propriedade recebe a instância de um delegate do tipo Func<DateTime>, ou seja, deve apenas retornar um DateTime. Abaixo temos o código que exibe como configurá-la para retornar uma data específica.

[TestMethod]
public void DeveAtribuirDataAtualAoLogCriado()
{
    using (ShimsContext.Create())
    {
        ShimDateTime.NowGet = () => new DateTime(2012, 4, 18);

        Assert.AreEqual(DateTime.Now, new Log("Mensagem de Log").Data);
    }
}

Além dos tipos que foram criados durante o procedimento de criação dos fakes, existem alguns outros tipos que dão suporte à configuração e execução destes testes. O principal deles é ShimContext, que controla o tempo de vida dos shims. A forma mais fácil de criá-la é através do método estático Create, mas é extremamente importante envolve-lo em um bloco using, para delimitar claramente o bloco onde eles serão utilizados e, principalmente, encerrar o contexto quando os shims não forem mais necessários. Se não fizer isso, a propriedade NowGet retornará sempre 18 de abril de 2012.

Em uma outra situação, imaginemos uma classe que é responsável por avaliar certos índices, e quando eles ultrapassarem um certo valor, uma mensagem deve ser logada para posterior análise. O nosso monitor deverá depender de uma definição e não de uma implementação do repositório de logs, ou em outras palavras, a ideia é durante os testes, injetar um repositório que armazena os logs em memória, mas ao consumir isso por uma aplicação, utilizamos um repositório real, onde por exemplo, poderia gravar isso em um banco de dados. Abaixo temos a estrutura da interface IRepositorioDeLogs e da classe Monitor:

public interface IRepositorioDeLogs
{
    void Adicionar(Log log);

    IEnumerable<Log> Todos { get; }
}

public class Monitor
{
    private IRepositorioDeLogs repositorioDeLogs;

    public Monitor(IRepositorioDeLogs repositorioDeLogs)
    {
        this.repositorioDeLogs = repositorioDeLogs;
    }

    public void AvaliarIndice(double indice)
    {
        if (indice > 75)
            repositorioDeLogs.Adicionar(
                new Log(string.Format("O índice está acima dos 75.", indice)));
    }
}

Para efetuar o teste, precisamos passar uma classe que implemente a interface IRepositorioDeLogs, onde neste caso, adicionará os logs em uma lista na memória. Vale lembrar aqui, que os testes garantem que se o índice estiver acima, ele deve gravar o log, independente se está armazenado na memória ou não.

Ao invés de criar uma implementação dummy, podemos recorrer aos stubs, que também são fornecidos por este novo recurso do Visual Studio 2011. Stubs fornecem uma implementação padrão para cada um dos membros fornecidos, neste caso, pela interface IRepositorioDeLogs. Novamente, aqui também recorreremos ao uso de delegates para customizar a funcionalidade de cada membro.

Como criamos também os fakes para o assembly que contém nossos tipos, ele já criou a classe StubIRepositorioDeLogs. Essa classe fornece os campos AdicionarLog e TodosGet. O primeiro recebe um delegate do tipo Action<Log>, enquanto o segundo define um delegate do tipo Func<IEnumerable<Log>>. Com uma implementação simples, conseguiremos simular um repositório que conseguirá acomodar o log que será adicionado ao mesmo, mas isso se a regra da classe Monitor, alvo do teste, estiver em correta.

Para o exemplo, criamos uma coleção do tipo List<Log>, e no delegate do campo AdicionarLog, invocamos o método Add da coleção, enquando ao acessar a propriedade Todos, irá retorná-la na íntegra, e é justamente a propriedade Count que determinará o sucesso ou a falha do teste. O código abaixo ilustra esse procedimento utilizando o stub recém criado:

[TestMethod]
public void SeIndiceEstiverAcimaDe75DeveIncluirLog()
{
    var repositorio = new List<Log>();
    var stub = var StubIRepositorioDeLogs()
    {
        AdicionarLog = log => repositorio.Add(log),
        TodosGet = () => repositorio
    };

    var indice = 78D;
    new Monitor(stub).AvaliarIndice(indice);

    Assert.AreEqual(1, repositorio.Count);
}

Tags: , ,

.NET Framework

Autenticação - Mix entre WebApi e Interfaces

by Israel Aece 16. April 2012 22:15

Para criar controllers que representem uma Web Api, trabalhamos de forma parecida com a criação de controllers para o ASP.NET MVC. Como trata-se apenas de um tipo específico de controller, podemos facilmente disponibilizar esta Api para consumo dentro da própria aplicação, para seu próprio consumo ou acesso por terceiros.

Apesar de suportado, podemos nos deparar com um problema específico ao hospedar a Api em uma aplicação que já possua uma interface com o usuário, e que controla a autenticação da mesma através do Forms Authentication.

Por padrão, as Web Apis possuem em sua rota um prefixo chamado /api/, mas independentemente disso, toda e qualquer requisição às ações (do Web Api ou não), serão interceptadas pelo módulo FormsAuthenticationModule, qual identifica se o usuário está ou não logado (baseando-se em um cookie), e se não estiver, irá redirecioná-lo para a página que login. Ele retorna para o navegador o código de 302 do HTTP, e quando ele (o navegador) receber este código, irá redirecionar para o endereço definido no header Location. Abaixo vemos o fluxo capturado pelo Fiddler:

A questão é que um serviço não espera que alguém se identifique "manualmente"; nem saberemos se estamos acessando-o via navegador ou através de uma outra aplicação. Sendo assim, a autenticação deve ser tratada pela própria requisição.

Remover ou "desligar" o FormsAuthenticationModule seria uma alternativa, mas isso faria com que a aplicação toda ficasse disponível para qualquer um acessar, inclusive de forma anônima. A solução mais simples seria separar fisicamente as aplicações, onde você teria uma para servir as aplicações que fornecem uma interface com o usuário, enquanto a outra, seria responsável apenas por hospedar as Apis que serão consumidas pelas outras aplicações (internas ou externas). Essa última opção, permitiria você tratar de forma independente cada uma delas, optando por qualquer meio de autenticação, sem que uma afeta no bom comportamento da outra.

Ainda há alguns truques que podemos recorrer para conseguir realizar esse mix de recursos em uma mesma aplicação, onde podemos identificar o código 302, e alterá-lo para 401 (Unauthorized), mas isso, tendo que escrever alguma customização, e em seguida, acoplar à execução para que ela funcione.

Tags: , ,

ASP.NET | Security

Co e Contra Variância em Interfaces

by Israel Aece 12. April 2012 21:25

Os parâmetros genéricos foram recursos que foram incluídos no C# em sua versão 2.0. Desde então, podemos criar classes, interfaces, delegates, etc., que podem determinar um ou vários parâmetros e, consequentemente, utilizá-los definindo o tipo que acharmos necessário. No momento da criação/uso deste tipo, definimos o tipo do(s) parâmetro(s), e todos os membros em que o mencionamos passam a operar com ele, mas já fazendo diversas verificações ainda em tempo de compilação.

A partir do momento que podemos definir qualquer tipo, é comum queremos mencionar tipos que estão relacionados por herança, mas apesar disso ser suportado, algumas coisas que são comuns e fazemos normalmente, são barrados se utilizarmos em conjunto com tipos genéricos. Um caso específico que quero mencionar aqui, é o uso deste tipo genérico com interfaces. Para melhor ilustrar isso, vamos nos basear na estrutura de classes abaixo:

Note que Documento serve como base para todo e qualquer documento controlado pelo sistema. A partir deste momento, podemos criar interface que será responsável por definir um criador de objetos, e o tipo passa a ser determinado pelo parâmetro genérico T. Note que T é usado como retorno pelo método Criar.

interface ICriador<T>
{
    T Criar();
}

Com esta interface, podemos construir uma classe que representará o criador de objetos padrão do sistema, e para demonstração, tudo o que vamos fazer é instanciar o tipo definido em T, o que nos obriga a defnir uma constraint, ou seja, que o tipo T possua um construtor público.

class CriadorPadrao<T> : ICriador<T> where T : new()
{
    public T Criar()
    {
        return new T();
    }
}

A ideia desta classe, é concentrar a criação do objetos, ou melhor, dos documentos utilizados pelo nosso sistema. Sendo assim, como queremos trabalhar da forma mais genérica possível, ou seja, não quero lidar diretamente em meu código com ICriador<Cnpj>, ICriador<Cpf>, etc., isso me obriga a criar uma variável do tipo ICriador<Documento> (Documento é a classe base). Com isso, a qualquer momento atribuimos à esta variável a instância do criador genérico, apontando em T o tipo Cnpj, Cpf, etc., assim como sugere o código abaixo:

ICriador<Documento> c = new CriadorPadrao<Cnpj>();
Console.WriteLine(c.Criar());

Apesar de CriadorPadrao implementar a interface ICriador, e mesmo pelo fato de Cnpj (tipo genérico definido em T) herdar de Documento, o C# não permite a compilação deste código. O fato aqui é que toda interface genérica, até a versão 3.0 do C#, é sempre invariante. Apesar dos tipos - isoladamente - estarem relacionados, CriadorPadrao<Cnpj> não implementa a interface ICriador<Documento>, o que viola a regra do polimorfismo.

A versão 4.0 do C# introduziu um recurso chamado de covariância. Ele nos permitirá, com um ligeira mudança na interface, fazer com que o código acima seja compilado e executado com sucesso. A mudança qual me refiro, é a introdução da keyword "out" antes do tipo genérico T, assim como mostrado abaixo:

interface ICriador<out T>
{
    T Criar();
}

Isso dirá ao compilador que T somente será usado como retorno de métodos e/ou propriedades de somente leitura. Como o CriadorPadrao<Cnpj> vai retornar a instância da classe Cnpj no método Criar, ela pode ser acessada através da interface ICriador<Documento>, afinal, Documento é a classe base dela. Se definirmos na interface um parâmetro do tipo T, como o acesso à instância é através de ICriador<Documento>, poderia entrar qualquer coisa, ou seja, uma instância da classe Cnh, o que fará com que uma exceção seja disparada. Abaixo temos uma imagem que ajuda a entender:

Em um outro cenário, poderíamos ter uma interface que ao invés de retornar, passa a receber um tipo T. Dado um tipo, a interface define a estrutura de validação, que em seu método Validar recebe um parâmetro T, e devolve um bool indicando o resultado da validação. Abaixo temos a definição desta interface:

interface IValidador<T>
{
    bool Validar(T documento);
}

Teremos também um validador padrão, que define a estrutura de validação genérica para qualquer tipo. Note que temos a classe ValidadorPadrao, que define T e propaga para a interface e, consequentemente, para o método Validar. Note que neste momento, o T está entrando.

class ValidadorPadrao<T> : IValidador<T>
{
    public bool Validar(T documento)
    {
        //Validação
        return true;
    }
}

Agora a situação é que temos em mãos um validador exclusivo para Cnpj, e atribuímos a ele a instância da classe ValidadorPadrao, definindo T como Documento, ou seja, a classe base de todos os documentos, incluindo o próprio Cnpj.

IValidador<Cnpj> v = new ValidadorPadrao<Documento>();
v.Validar(new Cnpj());

Ao compilar o código, novamente temos um erro. Novamente, apesar de ValidadorPadrao implementar a interface IValidador, a atribuição não será possível. Apesar de estarmos tomando cuidado de passar para o método Criar um Cnpj (que herda de Documento), isso daria margem para definir o validador com um tipo sem relação alguma, como por exemplo, uma string, e através do método Validar passar a instância de CNPJ, e durante a execução, um erro ocorreria porque não é possível fazer tal conversão.

Para resolver isso, temos a contravariância. Também com uma pequena mudança na criação da interface, teremos um código mais flexível. Aqui teremos que adicionar antes do parâmetro T a keyword "in", assim como é mostrado abaixo:

interface IValidador<in T>
{
    bool Validar(T documento);
}

Isso dirá ao compilador que T somente será usado como parâmetros de entrada em métodos e/ou propriedades de somente escrita. Como o ValidadorPadrao<Documento> vai receber uma instância da classe Documento no método Validar, ela pode ser definida através da interface IValidador<Cnpj>, afinal, Cnpj é um tipo de Documento. Se definirmos na interface uma saída do tipo T, como o acesso à instância do validor é através de IValidador<Cnpj>, poderia retornar qualquer coisa, ou seja, uma classe Cnh, o que fará com que uma exceção seja disparada, pois não é possível converter Cnh em Cnpj. Abaixo temos uma imagem que ajuda a entender:

Tags:

C#

Contratos Assíncronos no WCF 4.5

by Israel Aece 8. April 2012 19:33

Há algum tempo eu mencionei aqui como criar um contrato assíncrono para um serviço WCF. A finalidade deste tipo de contrato é permitir a sua implementação de forma, também, assíncrona, para que possamos tirar um hor proveito dos recursos (leia-se threads), do servidor onde o serviço estará sendo hospedado.

Como o formato segue o padrão estabelecido pelo .NET Framework, somos obrigados a construir o contrato nos mesmos moldes do padrão definido por ele, ou seja, um par de métodos Begin/End. Além disso, ainda temos a necessidade de uma eventual implementação da interface IAsyncResult, callbacks, etc., ou seja, com toda a complexidade que estamos acostumados quando precisamos lidar com programação assíncrona no .NET.

As linguagens (C# e VB.NET) redefiniram a forma como escrevemos código assíncrono, e para tirar proveito disso, o WCF sofreu algumas mudanças internas, e agora a criação e implementação de contratos assíncronos são bem mais fáceis de serem implementados do que anteriormente.

Apesar das mudanças serem internas, para que seja possível esse tipo de utilização, algumas regras são exigidas ao (re)escrever o contrato. É necessário que a operação retorne um objeto do tipo Task (quando a mesma não retorna nenhum resultado) ou Task<T> (quando a mesma deve retornar um resultado (T refere-se ao tipo de resultado)). Abaixo temos a interface que define o contrato do serviço:

[ServiceContract]
public interface IContrato
{
    [OperationContract]
    Task<string> Ping(string value);
}

Ao implementar esse contrato na classe que representará o serviço, entre em cena as keywords do C# que faz toda a mágica para executar de forma assíncrona: async e await, quais já falamos aqui, e que em conjunto com os ajustes internos que a Microsoft fez no WCF (a crição de um operation invoker chamado TaskMethodInvoker), faz com que a operação seja executada sem qualquer grande impacto ao desenvolvedor. Abaixo temos um exemplo de implementação do contrato acima criado:

public class Servico : IContrato
{
    public async Task<string> Ping(string value)
    {
        return await Task.Factory.StartNew(() => value + " ping");
    }
}

Em termos que hosting, nada é necessário. Por fim, como já mencionado, em tempo de execução, teremos uma melhor reusabilidade das threads, o que nos permite executar algum recurso custoso, como por exemplo, chamado à bancos de dados, outros serviços, sem que a thread fique bloqueada esperando pelo resultado que não depende das capacidades do processamento local.

Já o consumo por parte de uma aplicação também .NET, temos uma ligeira mudança. Trata-se de uma nova opção chamada "Generate task-based operations". Ao efetuar a referência para um serviço e se esta opção estiver selecionada, fará com que a versão assíncrona das operações do proxy, sejam criadas utilizando o modelo baseado em tasks. Enquanto a outra opção, fará com que ele crie no modelo tradicional, ou seja, baseado em eventos XXXCompleted para cada uma das operações expostas pelo serviço. A imagem abaixo ilustra esta nova opção:

Tags: , ,

Async | WCF

Compressão em Serviços WCF 4.5

by Israel Aece 8. April 2012 16:58

Serviços WCF que são hospedados no IIS sempre puderam usufruir da compactação de mensagens, já que bastar habilitar, pois o próprio servidor fornece este recurso. Serviços que são hospedados em seu próprio servidor (self-hosted), como é o caso de aplicações Windows (Windows Forms, WPF, Console ou Windows Service), precisam de um trabalho extra, que consiste em criar um message encoder customizado para isso. Inclusive uma implementação padrão é fornecida no pacote de demonstrações oferecidos pela própria Microsoft.

A partir do WCF 4.5, nós teremos esse recurso nativamente, ou seja, o codificador binário (BinaryMessageEncoding) passa a fornecer uma propriedade chamada CompressionFormat, que determina o formato da compressão, podendo escolher entre GZip, Deflate ou None. Como essa é uma propriedade fornecida pelo encoder, temos que customizar a criação da binding, para que assim tenhamos acesso à propriedade que define o padrão da compressão. O código abaixo ilustra a criação deste binding, e logo na sequência, temos a mesma configuração, só que através do modelo declarativo (via arquivo de configuração):

var binding = 
    new CustomBinding
    (
        new BinaryMessageEncodingBindingElement()
        {
            CompressionFormat = CompressionFormat.GZip
        },
        new HttpTransportBindingElement()
    );

<customBinding>
  <binding name="BinaryCompressionBinding">
    <binaryMessageEncoding compressionFormat ="GZip"/>
    <httpTransport />
  </binding>
</customBinding>

Se interceptarmos a requisição para um serviço sem qualquer configuração de compactação, enviando uma string com 5000 caracteres, temos a requisição abaixo (removendo alguns elementos por questões de espaço):

POST http://127.0.0.1:9291/srv HTTP/1.1
Content-Type: application/soap+msbin1
Host: 127.0.0.1:9291
Content-Length: 5157
Accept-Encoding: gzip, deflate

Agora, se optarmos pelo modelo de compactação GZip, ao analisarmos a requisição para o mesmo serviço, podemos reparar que a quantidade de bytes trafegados é bem menor quando comparado à primeira requisição:

POST http://127.0.0.1:9291/srv HTTP/1.1
Content-Type: application/soap+msbin1+gzip
Host: 127.0.0.1:9291
Content-Length: 185
Accept-Encoding: gzip, deflate

Apesar de um ganho significativo, é importante avaliar corretamente o ambiente em qual o serviço será disponibilizado. Enquanto a compactação é interessante quando o gargalo é a rede, a mesma exige muito mais da CPU para realizar o processo de compactação e descompactação. Sendo assim, o melhor é analisar e realizar alguns testes, e mensurar o que realmente importa durante a execução no ambiente de produção.

Tags: ,

WCF

Claims em todo lugar

by Israel Aece 19. March 2012 09:40

Há algum tempo eu falei aqui sobre o WIF (Windows Identity Foundation), que consiste em um framework para tornar o gerenciamento de identidades em aplicações .NET mais simples. Ele traz uma série de funcionalidades, que quando utilizado nas aplicações, nos permite lidar com a autenticação e autorização de uma forma mais poderosa, conseguindo inclusive, terceirizar/centralizar isso para uma outra aplicação.

O modelo de objetos do WIF, definia duas novas interfaces: IClaimsIdentity e IClaimsPrincipal, que herdavam de duas interfaces já existentes no .NET Framework desde a sua primeira versão (IIdentity e IPrincipal, respectivamente). Apesar de indiretamente compatíveis com os principals do .NET (WindowsPrincipal e GenericPrincipal), havia um trabalho extra a se fazer quando a conversão fosse necessária, ou melhor, quando a aplicação queria trabalhar com claims ao invés do modelo tradicional.

Com o .NET Framework 4.5, a Microsoft decidiu incorporar o modelo de claims diretamente no .NET Framework ao invés disso ser fornecido exclusivamente pelo WIF. A partir da versão 4.5, o .NET Framework passa a fornecer nativamente os tipos necessários para trabalhar com claims, e ainda, fez com que as classes WindowsPrincipal e GenericPrincipal herdem de ClaimsPrincipal e, consequentemente, toda e qualquer aplicação ao ser migrada para a versão 4.5 do .NET, automaticamente poderá fazer uso de claims. O diagrama abaixo mostra a hierarquia da herança entre essas classes:

System.Security.Claims é um novo namespace que foi adicionado ao .NET Framework, com a finalidade de agrupar os tipos disponíveis para realizar o trabalho via claims. Abaixo temos um exemplo de como podemos fazer o uso de claims em aplicações que utilizam, por exemplo, um modelo de autenticação customizado:

using System;
using System.Security.Claims;
using System.Security.Principal;

namespace App
{
    class Program
    {
        static void Main(string[] args)
        {
            var principal = 
                new GenericPrincipal(new GenericIdentity("Israel Aece"), new [] { "Admin", "IT" });

            foreach (var item in principal.Claims)
                Console.WriteLine("{0}: {1}", item.Type, item.Value);
        }
    }
}

Tags: ,

.NET Framework | Security | WIF

ASP.NET Web API: Implementação Assíncrona

by Israel Aece 12. March 2012 14:27

A Microsoft trabalha para que na próxima versão do C# e do VB.NET, eles já saiam com suporte para programação assíncrona. Como eu já havia mencionado em um post anterior, a ideia é facilitar a programação assíncrona, que não é nada trivial. A ideia é tornar a escrita de um código assíncrono, muito próximo a escrita de um código síncrono, e nos bastidores, o compilador faz grande parte do trabalho. Grande parte das funcionalidades do .NET Framework que já possuem suporte nativo ao consumo em formato assíncrono, foram readaptados para que assim, os desenvolvedores possam fazer uso dos recursos oferecidos pela linguagem para consumi-los.

Desta mesma forma, algumas tecnologias que dão suporte à construção de funcionalidades assíncronas, também sofreram adequações para este novo modelo. Para citar um caso, o WCF permite agora a construção de um serviço assíncrono de forma muito mais tranquila que antes, onde tínhamos que implementar um contrato assíncrono.

Já o ASP.NET merece algumas considerações: o ASP.NET Web Forms traz o conceito de páginas assíncronas, que também farão uso dos recursos das linguagens para implementa-las. O ASP.NET MVC possui uma classe chamada AsyncController, de qual herdamos e com pequenos ajustes, conseguimos ter ações sendo disparadas de forma assíncrona. Na próxima versão, o ASP.NET MVC também flexibilizará a criação das ações assíncronas, deixando, novamente, o trabalho árduo para o compilador.

Agora, ao utilizar o ASP.NET Web API, também podemos fazer com que as ações expostas pela API sejam processadas assincronamente. Como é a primeira versão desta tecnologia, a forma de escrevermos as ações assincronamente, é somente através dos recursos das linguagens. Só que antes de exibir como procedemos para criar o código assíncrono, vamos primeiramente criar a versão síncrona desta ação:

public class NoticiasRegionaisController : ApiController
{
    private const string ServicoDeNoticias =
        "http://localhost:1256/api/noticias/recuperar";

    [HttpGet]
    public IEnumerable<NoticiaDaRegiao> Recuperar()
    {
        return
            JsonArray.Parse
            (
                new WebClient().DownloadString(ServicoDeNoticias)
            ).ReadAsType<IEnumerable<NoticiaDaRegiao>>();
    }
}

Note que há um serviço chamado NoticiasRegionais, qual recorre à um outro serviço que é mais abrangente, para extrair as notícias de uma determinada região ou cidade. No interior do método Recuperar, propositalmente fazemos a chamada para o serviço e esperamos pelo resultado, que ao voltar, efetuamos o parser e, finalmente, convertemos para o formato esperado e retornamos ao cliente.

Ao rodar esse código, a requisição será bloqueada pelo runtime até que o resultado seja devolvido pelo serviço. Isso prejedica, e muito, a escalabilidade do serviço. O fato da thread ficar bloqueada enquanto espera pelo resultado do serviço, ela poderia estar atendendo à outras requisições, que talvez não exijam recursos de terceiros (I/O bound). O fato de disponibilizar a thread para que ela possa atender à outras requisições, farão com que elas não esperem por um - longo - tempo indeterminado, pois como dependemos do resultado de um terceiro, poderíamos arranjar muito trabalho para esta thread, até que ela precise retomar o trabalho da requisição anterior.

O gráfico abaixo apresenta algumas medições que foram feitas no serviço acima, que foi implementado de forma síncrona. Entre os contadores podemos visualizar a média do tempo gasto para que a requisição retorne, e além disso, a quantidade de requisições que o serviço de notícias regionais é capaz de atender por segundo.



Como mencionado acima, podemos implementar o controller da API de forma assíncrona, o que exigirá algumas mudanças, mas nada que faça com que seja necessário escrever e/ou gerenciar uma porção de código para garantir o assincronismo. Com isso, o primeiro detalhe a notar na escrita da ação assíncrona, é a exigência da keyword async, que faz parte do C#. Além disso, uma das grandes diferenças aqui, é com relação ao tipo de retorno da ação. No exemplo anterior, retornávamos um IEnumerable<T>, onde o tipo T é representado pela classe NoticiaDaRegiao. Aqui, ao invés disso, vamos retornar um Task<TResult>, onde TResult será definido com o mesmo tipo de retorno da ação síncrona, ou seja, IEnumerable<NoticiaDaRegiao>.

Internamente a implementação também mudará. Passamos a recorrer a classe HttpClient, que fará parte do .NET Framework, utilizado para consumir serviços REST, fornecendo vários facilitadores. Além disso, o fato de colocarmos a keyword async na assinatura do método, o compilador já nos obriga a definir o local que vamos aguardar pelo resultado, e para isso, utilizamos uma segunda keyword, chamada de await. No exemplo abaixo aguardamos a resposta voltar, e além disso, também invocamos a leitura do corpo da mensagem de forma assíncrona. Com isso, a ação que tínhamos foi rescrita e ficou da seguinte forma:

public class NoticiasRegionaisController : ApiController
{
    private const string ServicoDeNoticias =
        "http://localhost:1256/api/noticias/recuperar";

    [HttpGet]
    public async Task<IEnumerable<NoticiaDaRegiao>> Recuperar()
    {
        using (var client = new HttpClient())
            return await
                (await client.GetAsync(ServicoDeNoticias))
                .Content
                .ReadAsAsync<IEnumerable<NoticiaDaRegiao>>();
    }
}

Com isso, ao executarmos novamente os testes, agora contra o serviço implementado de forma assíncrona, veremos um ganho considerável, onde o tempo de resposta diminui e a quantidade de requisições atendidas por segundo aumenta. O gráfico abaixo já reflete essa mudança:

A implementação assíncrona trouxe um resultado interessante, aumentando a capacidade da aplicação de lidar com muitas requisições, e isso tende a aumentar dependendo das características do ambiente, como máquina, recursos, funcionalidades do serviço, etc.

Tags: , ,

ASP.NET | Async

Powered by BlogEngine.NET 1.5.0.0
Theme by Mads Kristensen

Sobre

Meu nome é Israel Aece e sou especialista em tecnologias de desenvolvimento Microsoft, atuando como desenvolvedor de aplicações para o mercado financeiro utilizando a plataforma .NET. [ Mais ]

Twitter

Host