Validação de Comandos

No artigo/vídeo anterior eu comentei como podemos expor comandos através do protocolo HTTP. O comando é serializado em JSON e enviado para o servidor que tenta encontrar a respectiva classe que representa o comando e, consequentemente, executa o seu respectivo handler para tratar a requisição. E como sabemos, os comandos são classes extremamente simples, contendo apenas poucas propriedades que parametrizam a tarefa a ser executada.

Só que os comandos podem chegar até o serviço sem as informações mínimas para a sua execução. Apesar de estarmos falando em comunicação entre sistemas, isso se aproxima muito do que temos em uma aplicação com interface com o usuário: apesar de termos uma validação sendo realizada no formulário, é uma boa prática reaplicar as validações quando ele é postado, já que do lado do cliente, a validação pode ser desabilitada, como é o caso de aplicações Web, que recorrem à JavaScript, que com algum esforço, podemos inativar no navegador e postar a mensagem sem devidas validações. A validação do lado do cliente serve para dar uma melhor experiência para o usuário, dando o feedback se alguma informação estiver inválida antes da requisição partir.

Isso é muitas vezes chamadas de validação superficial, e ela não substitui aquela que é feita pelo domínio, que por sua vez, é a qual garante a consistência da aplicação. Essa validação nos comandos devem garantir os parâmetros obrigatórios, que itens não sejam nulos ou iguais a zero, formatação de campos (e-mail, URLs, etc.), etc.

Agora, se a ideia é expor os comandos através de HTTP, temos também que tentar integrar as validações com os recursos que o protocolo fornece. Só que antes disso, precisamos incorporar nas classes dos comandos a estrutura da validação. Aqui existem diversas formas de se fazer, onde a mais comum, é declarar na classe base que representa o comando um método virtual que pode ser sobrescrito nas derivadas para customizar a validação de cada um deles.

public abstract class Command
{
    public virtual bool Validate() { }
}

A implementação do método pode ser feito de diversas formas, e uma delas sendo a forma “manual”, utilizando apenas recursos (tipos) da linguagem e criando classes que representam os erros. O método Validar retorna apenas um indicativo (bool) se a validação sucedeu ou não. Mas o que falhou? E vamos optar por retornar apenas quando a primeira falha for encontrada ou validaremos todo o objeto e retornaremos todos os problemas encontrados? Neste caso, ao invés do método retornar apenas um bool, teremos que customizar o tipo de retorno, com uma classe que totaliza todos os problemas encontrados.

public abstract class Command
{
    public virtual ValidationResult Validate()
    {
        return ValidationResult.Empty;
    }
}

public class ValidationResult
{
    public static ValidationResult Empty = new ValidationResult();
    private readonly IList<Error> errors = new List<Error>();

    public void Add(Error error) => this.errors.Add(error);

    public bool IsValid
    {
        get
        {
            return !this.errors.Any();
        }
    }

    public IEnumerable<Error> Errors
    {
        get
        {
            return this.errors;
        }
    }

    public class Error
    {
        public string Message { get; set; }
    }
}

A outra forma seria recorrer à algum framework de validação, como o FluentValidation, que já fornece diversos recursos para facilitar a validação. Depois disso, precisamos de alguma forma integrar com o HTTP, e a opção que temos é retornar o erro 400 (BadRequest), que serve justamente para representar alguma falha encontrada na postagem da requisição (onde o seu conteúdo não é válido). A resposta deve conter os dados da validação, para que o cliente consiga entender o problema e corrigir para as futuras requisições.

Por fim, ao receber a requisição, encontrar o respectivo comando e deserializar a mensagem, invocamos o método Validate e avaliamos a propriedade IsValid. Caso seja negativo, então configuramos o código de retorno do HTTP para 400 (BadRequest) e serializamos o resultado da validação  em JSON para ser devolvido ao cliente; caso o resultado da validação seja positivo, então a requisição é encaminhada para ser normalmente processada. O código na integra está disponível neste endereço.

var command = context.Request.ReadAsCommand(bus.Handlers[action]);
var validateResult = command.Validate();

if (!validateResult.IsValid)
{
    context.Response.StatusCode = 400;
    await context.Response.WriteAsync(validateResult.ToJson());
    return;
}

await bus.Send(command);

É importante dizer que isso que falamos aqui é uma validação superficial, e não deve ser utilizada sozinha, é só um complemento. O comando essencialmente não retorna resultado, mas a validação dele é algo que ocorre antes de sua execução. Agora se algo der errado durante a execução dele (pois está “tocando” o domínio, que pode estar protegido com o disparo de exceções), é muito provável que seja alguma regra de negócio que tenha sido violada, e para isso, há outras estratégias de notificação para reportar ao usuário ou à outras aplicações destas falhas, como o uso de eventos.

Web Commands

Quando falamos de CQRS, temos as consultas e os comandos. Esses comandos podem ser consumidos diretamente por aplicações, mas como expor publicamente para os clientes? Uma opção comum nos dias de hoje é utilizar o protocolo HTTP, facilitando assim o consumo pelas mais diversas linguagens e tecnologias. E quais as opções no .NET para fazermos esta exposição?

O ASP.NET é um candidato para isso, já que em sua versão core está modularizado e flexível, e assim podemos otimizar o pipeline de execução com somente aquilo que seja de fato necessário para executar os comandos. A finalidade do vídeo abaixo é exibir uma forma alternativa para incorporar os comandos do domínio no ASP.NET, utilizando o mínimo de recursos possível do hosting. Link para o código do exemplo.

Segregando Requisições no ASP.NET

No ASP.NET Core temos o conceito de middlewares, que nada mais são que plugins que podemos acoplar à execução para que eles sejam executados a medida em que uma nova requisição chega para o serviço ou para o site. Além de vários que já foram criados pela Microsoft, a criação destes middlewares é extremamente simples, e é a principal forma que temos de interceptar o momento antes e/ou depois das requisições.

Durante a inicialização da aplicação, devemos realizar as configurações necessárias para que ela funcione, e é neste momento que montamos o pipeline por onde cada uma delas deverá passar, e isso quer dizer que faremos uso constante de middlewares, mesmo que não se esteja explicitamente claro no código que vamos escrever. A execução ocorre de forma linear, onde a requisição é entregue para o primeiro middleware e este é responsável por fazer alguma atividade e passar adiante a requisição (leia-se para o middleware interno). Abaixo temos um exemplo de um simples middleware; note que temos algumas convenções que precisam ser respeitadas, tais como: receber no construtor o próximo middleware, ter o método chamado Invoke que será disparado pelo ASP.NET no momento adequado. É dentro deste método que você define quando quer invocar o próximo middleware.

public class LoggingMiddleware
{
    private readonly RequestDelegate next;

    public LoggingMiddleware(RequestDelegate next)
    {
        this.next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        //Ação Antes
        await next(context);
        //Ação Depois
    }
}

O problema aqui é que podemos hospedar na mesma aplicação dois conteúdos que demandam diferentes rotinas e características. É comum encontrarmos aplicações que expõe uma API web, e na mesma aplicação, fornece o acesso à um pequeno site com a documentação, tutoriais, central de suporte para a mesma. Do lado da API, é comum termos log de acesso, telemetria, controle de transações, etc., enquanto do “lado do UI” da aplicação, necessitamos de outros recursos, como a exposição de conteúdos estáticos e geração de HTML.

O ASP.NET possibilita uma forma de segregar as requisições (branch), roteando cada uma delas de acordo com um critério e, que se atendido, podemos customizar um pipeline de middlewares exclusivo para aquele cenário. Isso evita ter um único pipeline com todos os passos e ter que dar by-pass de acordo com a requisição que estamos processando naquele momento exige. Para isso, podemos recorrer ao método Map da interface IApplicationBuilder. Em sua versão mais simplista, ele aceita uma string que permite especificarmos a URL que, se atendida, deverá ser executada utilizando a configuração que especificamos no segundo parâmetro deste mesmo método. Há uma variação deste método chamado MapWhen, que nos permite inspecionar outros itens da requisição (headers, por exemplo) para tomar a decisão se deve ou não ser processada por aquele pipeline.

No exemplo abaixo, se a requisição conter /commands na URL, então o middleware de logging será disparado, na sequência o de transações, e por fim, a ação do controller será executada. Já quando a requisição for para /help, estamos permitindo o acesso à arquivos estáticos (imagens, PDFs, etc.) e também o uso do MVC para renderizar HTML com o conteúdo da documentação da API:

public void Configure(IApplicationBuilder app)
{
    app.Map("/commands",
        config =>
            config
                .UseMiddleware<LoggingMiddleware>()
                .UseMiddleware<TransactionMiddleware>()
                .UseMvc());

    app.Map("/help", 
        config => 
            config
                .UseMvc()
                .UseStaticFiles());
}

Se desejar ter acesso ao código completo deste artigo, consulte este endereço.

HTTPS no Kestrel

Sempre quando pensamos em hospedar uma aplicação desenvolvida em ASP.NET logo nos vem a mente o IIS. Apesar de uma infinidade de recursos que ele possui, o novo ASP.NET traz nativamente uma forma de hospedar as aplicações em um processo fora do IIS (self-hosting), chamado de Kestrel, qual foi construído com a finalidade de ser multi-plataforma e vem ganhando bastante evidência com alguns testes que demonstram grandes resultados em termos de performance.

Aos poucos a Microsoft vem adicionado nele algumas funcionalidades para que ele incorpore tudo que é necessário para utilizarmos em ambientes de produção. A finalidade deste artigo é demonstrar como configurar a aplicação para suportar o uso do protocolo HTTPS e, consequentemente, proteger os recursos que serão expostos pela aplicação.

Como sabemos, independentemente da tecnologia ou servidor que utilizamos para as nossas aplicações, para o uso do HTTPS se faz necessário a compra de um certificado de alguma entidade publicamente conhecida, para que possamos instalar em nosso servidor e configurar a nossa aplicação para utiliza-lo para estabelecer um túnel seguro de comunicação entre o cliente e o servidor e vice-versa. Como o foco é demonstrar a configuração, vou utilizar um certificado de testes emitido por uma ferramenta, sem valor para uso em ambiente de produção.

O primeiro passa em nossa aplicação é indicar ao runtime que o hosting a ser utilizado é o Kestrel, e para isso, recorremos ao método UseKestrel. Em um dos seus overloads é possível acessar algumas configurações e entre elas a possibilidade de indicar que queremos que o HTTPS seja utilizado, que é expressado através do método de estensão UseHttps. Para fazer uso deste método é necessário a instalação de um pacote NUGET chamado Microsoft.AspNetCore.Server.Kestrel.Https.

Uma vez que o certificado está criado e armazenado em um arquivo PFX (que inclui a sua chave privada) e o pacote acima mencionado esteja instalado na aplicação, utilizamos o código abaixo para indicar o local onde o arquivo PFX referente ao certificado está localizado no disco; note também que o “12345” é a senha para que o ASP.NET possa acessar o certificado.

public class Program
{
    public static void Main(string[] args)
    {
        new WebHostBuilder()
            .UseKestrel(opts => opts.UseHttps(@”C:tempAppTesteMeuWebSite.pfx”, “12345”))
            .UseUrls(“http://localhost:5000/&#8221;, “https://localhost:5001/&#8221;)
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseStartup<Startup>()
            .Build()
            .Run();
    }
}

Ao rodar, a aplicação estará disponível para acesso tanto através do HTTP quanto HTTPS, porém em portas diferentes.

MessageQueue e HTTP

Quando trabalhamos com o Microsoft Message Queue, serviço de mensagens fornecido pelo Windows, ele nos permite expor as filas através do protocolo HTTP. Isso permitirá apenas o envio de mensagens através deste protocolo (podendo também ser via HTTPS), e com isso, clientes que estiverem além dos limites da empresa, poderão enfileirar mensagens para o processamento interno de alguma rotina que rodará periodicamente.

Apenas o envio é permitido via HTTP, pois somente a porta 80 é necessária para executar esta ação; para recepcionar a mensagem, é exigido que outras portas também estejam abertas no firewall, e devido a isso, a Microsoft optou por não permitir o recebimento de mensagens sobre estes protocolos.

Para fazer uso deste recurso, ao instalar o Message Queue no computador que receberá as mensagens, você deve marcar a opção de suporte ao protocolo HTTP, conforme é mostrado na imagem abaixo. Vale lembrar que esta opção exige que o IIS (Internet Information Services) também esteja instalado nesta mesma máquina.
Depois de instalado, o Message Queue cria uma diretório virtual dentro do IIS, que servirá o ponto de acesso (HTTP/S) para as filas criadas nesta máquina. Abaixo vemos a fila chamada “Exemplo” criada e o diretório virtual chamado “MSMQ”.
Por fim, ao fazer uso da API System.Messaging, podemos apontar para o endereço HTTP, combinando o diretório virtual criado com o nome da fila para qual queremos enviar a mensagem.

using (var mq = new MessageQueue(“FormatName:DIRECT=http://localhost/msmq/private$/exemplo”))
    mq.Send(“Algo Aqui”, MessageQueueTransactionType.Single);

Apesar disso ser possível, considere o uso do WCF com MessageQueue.

Web Sockets com ASP.NET Web API

Há algum tempo eu comentei sobre a possibilidade do WCF expor serviços para serem consumidos utilizando a tecnologia de Web Sockets. Neste mesmo artigo eu falei sobre os detalhes do funcionamento deste protocolo, e que se quiser saber o seu funcionamento e implementação em um nível mais baixo, aconselho a leitura.

Como sabemos, o WCF é uma tecnologia que roda do lado do servidor. Da mesma forma que temos o ASP.NET Web API, que é uma tecnologia que utilizamos para criarmos APIs e expor para os mais diversos tipos de clientes. Assim como a Microsoft adicionou o suporte à web sockets no WCF, ela também fez o mesmo com o ASP.NET Web API e MVC, ou seja, incorporou no próprio framework o suporte para criação de recursos que são expostos utilizando web sockets.

É importante dizer que a Microsoft também criou uma outra tecnologia chamada de SignalR, que fornece diversos recursos para a criação de aplicações que precisam gerar e consumir informações que são consideradas de tempo real. Este framework já possui classes que abstraem a complexidade de exposição destes tipos de serviços, fornecendo classes de mais alto nível para trabalho.

Entre os novos tipos que foram adicionados, temos a propriedade IsWebSocketRequest (exposta pela classe HttpContext), que retorna um valor boleano indicando se a requisição está solicitando a migração do protocolo para web sockets. Caso seja verdadeiro, então recorremos ao método AcceptWebSocketRequest da mesma classe para especificarmos a função que irá periodicamente ser executada.

Para o exemplo, vamos criar um publicador de notícias, que quando o cliente optar por assiná-lo, ele irá receber as notícias de forma randômica em um banner a cada 2 segundos. Como podemos ver no código abaixo, o método Assinar da API é exposto para que os clientes cheguem até ele através do método GET do HTTP. Como se trata de uma solicitação de migração, retornamos o código 101 do HTTP indicando a troca do protocolo para web sockets.

public class PublicadorController : ApiController
{
    private static IList<string> noticiais;
    private static Random random;

    static PublicadorController()
    {
        noticiais = new List<string>()
        {
            “You can buy a fingerprint reader keyboard for your Surface Pro 3”,
            “Microsoft’s new activity tracker is the $249 Microsoft Band”,
            “Microsoft’s Lumia 950 is the new flagship Windows phone”,
            “Windows 10 will start rolling out to phones in December”,
            “Microsoft’s Panos Panay is pumped about everything (2012–present)”
        };

        random = new Random();
    }

    [HttpGet]
    public HttpResponseMessage Assinar()
    {
        var httpContext = Request.Properties[“MS_HttpContext”] as HttpContextBase;

        if (httpContext.IsWebSocketRequest)
            httpContext.AcceptWebSocketRequest(EnviarNoticias);

        return new HttpResponseMessage(HttpStatusCode.SwitchingProtocols);
    }

    private async Task EnviarNoticias(AspNetWebSocketContext context)
    {
        var socket = context.WebSocket;

        while (true)
        {
            await Task.Delay(2000);

            if (socket.State == WebSocketState.Open)
            {
                var noticia = noticiais[random.Next(0, noticiais.Count – 1)];
                var buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(noticia));

                await socket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
            }
            else
            {
                break;
            }
        }
    }
}

Já dentro do método EnviarNoticias criamos um laço infinito que fica selecionando randomicamente uma das notícias do repositório e enviando para o(s) cliente(s) conectado(s). É claro que também podemos receber informações dos clientes conectados. Para o exemplo estou me limitando a apenas gerar o conteúdo de retorno, sem receber nada. Se quiser, pode utilizar o método ReceiveAsync da classe WebSocket para ter acesso à informação enviada por ele. E, por fim, para não ficar eternamente rodando o código, avaliamos a cada iteração se o estado da conexão ainda continua aberto, caso contrário, encerramos o mesmo.

E do lado do cliente, se for uma aplicação web, vamos recorrer ao código Javascript para consumir este serviço. Temos também a disposição deste lado a classe WebSocket, que quando instanciada, devemos informar o endereço para o método que assina e migra o protocolo para web sockets. Repare que a instância é criada dentro do evento click do botão Conectar e também já nos associamos aos eventos – autoexplicativos – onopen, onmessage e onclose (e ainda tem o onerror).

<!DOCTYPE html>
<html xmlns=”http://www.w3.org/1999/xhtml”&gt;
<head>
    <title></title>
    https://code.jquery.com/jquery-2.1.4.min.js
   
        var ws;

        $().ready(function ()
        {
            $(“#Conectar”).click(function () {
                ws = new WebSocket(“ws://localhost:2548/api/Publicador/Assinar”);

                ws.onopen = function () {
                    $(“#Status”).text(“Conectado. Recuperando Notícias…”);
                };

                ws.onmessage = function (evt) {
                    $(“#Status”).text(“”);
                    $(“#Banner”).text(evt.data);
                };

                ws.onclose = function () {
                    $(“#Banner”).text(“”);
                    $(“#Status”).text(“Desconectado”);
                };
            });

            $(“#Desconectar”).click(function () {
                ws.close();
            });
        });
   
</head>
<body>
    <input type=”button” value=”Conectar” id=”Conectar” />
    <input type=”button” value=”Desconectar” id=”Desconectar” />
    <br /><br />
    <span id=”Status”></span>
    <span id=”Banner”></span>
</body>
</html>

Quando acessar a página HTML e clicar no botão Conectar, o resultado é apresentado abaixo. A qualquer momento podemos pressionar no botão Desconectar e indicar ao servidor que não estamos mais interessados no retorno das informações. A cada envio de mensagem do servidor para o cliente, o evento onmessage é disparado, e estamos exibindo a mensagem em um campo na tela.

Apenas para informação, o Fiddler é capaz de identificar quando a conexão é migrada para web sockets, e a partir daí consegue capturar as mensagens que são enviados para o cliente. A imagem abaixo é possível visualizar o log capturado depois da assinatura realizada:

Performance com Server Push

No post anterior eu comentei sobre os benefícios da utilização do server push, recurso que foi disponibilizado a partir do HTTP/2. Lá mencionei sobre a melhor reutilização da conexão TCP quando ela é estabelecida para extrair algum recurso que desejamos solicitar, como por exemplo, uma página HTML.

É comum qualquer página HTML depender de recursos extras, tais como arquivos de scripts, estilos (CSS) e imagens. Considere o exemplo abaixo, que é uma página extremamente simples que referencia cinco arquivos de estilos.

<html>
    <head>
        <link href=”Estilos1.css” rel=”stylesheet” type=”text/css” />
        <link href=”Estilos2.css” rel=”stylesheet” type=”text/css” />
        <link href=”Estilos3.css” rel=”stylesheet” type=”text/css” />
        <link href=”Estilos4.css” rel=”stylesheet” type=”text/css” />
        <link href=”Estilos5.css” rel=”stylesheet” type=”text/css” />
    </head>
    <body>
        Testando
    </body>
</htm>

Quando fazemos a requisição para esta página HTML, é possível notar no log abaixo uma barra cinza em cada linha de acesso para os arquivos *.css. Essa cor indica o período de tempo em que o navegador fica aguardando para iniciar a requisição para o respectivo recurso. É importante notar que neste exemplo estamos utilizando o HTTP 1.1.

Já agora se fizermos a requisição utilizando o HTTP/2, podemos perceber que não existe mais a barra cinza, ou seja, isso indica que os recursos são carregados de forma concorrente, sem a necessidade de ter um delay. Isso tudo é possível perceber na imagem abaixo.

Server Push no HTTP/2

Quando fazemos a solicitação para alguma página de um site, além de seu próprio conteúdo, ela referencia alguns outros recursos (tais como arquivos de scripts, imagens, estilos (CSS), etc.), e para cada um destes itens, novas requisições partem do navegador do cliente para baixa-los e, finalmente, apresentar o resultado final do usuário que a solicitou.

Na maioria das vezes estes recursos extras estão debaixo do mesmo servidor, e como sabemos, os navegadores limitam o número máximo de conexões simultâneas para um determinado domínio, o que gera certa lentidão no acesso, pois dependendo do tamanho e tempo de download destes arquivos, o resultado levará ainda mais tempo para ser exibido.

Como alternativa, é comum utilizarmos uma técnica conhecida domain-sharding, que nos permite espalhar os recursos extras por diferentes domínios e permitir o download simultâneo de todos eles; a outra opção é utilizar scripts ou estilos inline, que evita round-trips extras, mas acaba dificultando a manutenção e reutilização de código, e ainda, perdemos a opção de realizar caching destes recursos do lado do cliente.

Entre os novos recursos que o HTTP/2 fornece, um deles é o server push, que nos permite otimizar os problemas descritos acima, fornecendo uma opção que viabiliza o uso de referências externas sem comprometer a performance. A versão HTTP/2 faz um melhor uso das conexões TCP, e devido a restruturação de como a mensagem é enviada e recebida, passa a ser possível utilizar uma mesma conexão para requisitar e receber o resultado da solicitação e também dos recursos por ela utilizados e que não solicitados explicitamente.

Quando o servidor entende que o recurso solicitado faz uso de outras referências, ele é capaz de empurrar ao cliente essas referências indicando que elas serão utilizadas no futuro; na sequência ele devolve o resultado (HTML) da página e quando o navegador percebe que há imagens, CSS ou scripts, antes dele fazer a requisição para cada um deles, ele percebe que os mesmos já foram entregues, evitando o round-trip para cada um destes recursos extras, diminuindo consideravelmente o tempo de exibição do conteúdo como um todo.

Apesar de que isso não afete em nada as aplicações que já estão rodando ou que serão desenvolvidas, é importante saber da existência e comportamento desta funcionalidade para tirar proveito destas novas funcionalidades de mais baixo nível. Com o Windows 10, Internet Information Services (IIS) e o Edge, é possível ver isso em funcionamento. É importante mencionar que, por enquanto, a Microsoft apenas implementou este recurso apenas quando o site está sendo acessado através de HTTPS. É possível visualizar o HTTP/2 sendo usado através do log do Edge. E claro, se o cliente não suportar o HTTP/2, ele utilizará o HTTP 1.1 como fallback.

Criação e Gerenciamento de Conexões HTTP

Desde o início do .NET Framework temos uma classe chamada HttpWebRequest, que tem a finalidade de realizar requisições HTTP para algum recurso disponível. E como era de se esperar, ela expõe diversos métodos e propriedades para configurar as requisições que partem da instancia desta classe.

A cada requisição que é realizada, internamente ela recorre a classe ServicePointManager para criar a conexão até o recurso desejado, e a partir dai passa a reutilizar a mesma conexão nas chamadas subsequentes, poupando recursos da máquina de onde a requisição esta sendo feita. O objeto de conexão é criado considerando o protocolo, o host e a porta; se algum destes parâmetros variar, uma nova conexão é criada para atender este novo endereço e, consequentemente, reutilizada nas próximas requisições.

Só que existe a possibilidade de interferir na criação e gestão destas conexões. A classe HttpWebRequest define uma proprieade chamada ConnectionGroupName, e como o próprio nome sugere, ele considera o valor especificado nesta propriedade para criar a conexão, ou seja, para cada valor distinto definido nesta propriedade, uma nova conexão é criada. Se o valor se repetir, a conexão criada previamente é reutilizada.

Como sabemos, o WCF utiliza a classe HttpWebRequest nos bastidores quando acessa um serviço através do protocolo HTTP, e até então ele não disponibilizava qualquer propriedade no binding para configurar este pool de conexões HTTP. A partir da versão 4.6 do .NET Framework, a Microsoft permite ajustar este parâmetro (adicionando um prefixo) a fim de fazer uma melhor gestão e reuso das conexões HTTP pelos serviços WCF.

Por padrão, uma única conexão é mantida e compartilhada por todos os channels factories (proxy) que são instanciados pelo cliente. O que essa nova configuração irá fazer é criar uma conexão dedicada para cada channel factory criado pelo cliente, utilizando uma espécie de contador de instâncias para definir a propriedade ConnectionGroupName.

Para isso funcionar, basta ligar o flag useUniqueConnectionPoolPerFactory através do arquivo de configuração (app.config ou web.config) da aplicação cliente, assim como é mostrado no código abaixo.

<appSettings>
    <add key=”wcf:httpTransportBinding:useUniqueConnectionPoolPerFactory”
         value=”true” />
</appSettings>

Agora, se quiser um controle mais refinado e, de repente, variar a conexão de acordo com alguma regra ou parâmetro de negócio, você pode extrair e definir o nome do pool de conexões através das propriedades da mensagem do WCF, que em baixo nível, também vai utilizar o valor definido aqui para configurar a propriedade ConnectionGroupName.

OperationContext
    .Current
    .OutgoingMessageProperties
    .Add(“HttpTransportConnectionGroupNamePrefix”, “ValorCustomizado”);

Por fim, para ver isso em funcionamento, considere o código a seguir, que cria um laço e dentro dele instancia o channel factory e invoca o método do serviço. Antes de rodar, vamos configurar o flag como True para ver o impacto causado, provocando a criação de uma conexão dedicada para cada proxy. Por fim, é possível visualizar as conexões criadas através do utilitário TCPView.

var endereco = “http://localhost:9388&#8221;;

using (var host = new ServiceHost(typeof(Teste), new Uri(endereco)))
{
    host.AddServiceEndpoint(typeof(IServico), new BasicHttpBinding(), “”);
    host.Open();

    for (int i = 1; i < 11; i++)
        using (var srv = new ChannelFactory<IServico>(
            new BasicHttpBinding(), new EndpointAddress(endereco)))
                Console.WriteLine(srv.CreateChannel().Ping(“Teste ” + i.ToString()));
}

Cancelando Requisições do HttpClient

Como sabemos, a classe HttpClient é uma espécie de proxy para o consumo de serviços REST a partir de aplicações .NET. Durante a sua criação é possível realizar diversas configurações, e as requisições que saem e chegam, compartilham estas configurações, evitando que se faça isso a cada nova requisição/resposta que é enviada/processada.

Entre os diversos métodos que esta classe fornece, o mais completo, ou melhor, “de mais baixo nível”, é o SendAsync, que onde podemos (e devemos) configurar completamente a mensagem, especificando desde a URL até o método HTTP que será utilizado. Como facilitador, existem alguns métodos que foram criados sobre o método SendAsync, e foram nomeados utilizandos os verbos do HTTP (GET (GetAsync), POST (PostAsync), etc.).

A classe HttpClient fornece um método chamado CancelPendingRequests, que como o próprio nome sugere, solicitará o cancelamento de todas as requisições que estão sendo realizadas pela respectiva instância do HttpClient. Mas é provável que queremos ter um controle individual das requisições e conseguirmos cancelar especificamente uma delas.

Felizmente todos os métodos que iniciam uma nova requisição possuem um parâmetro onde é permitido controlar e, principalmente, cancelar a execução da mesma. Eles fazem uso de uma classe chamada CancellationTokenSource, que faz parte do .NET Framework, e possibilita ao chamador informar ao runtime que deseja cancelar a requisição que está em andamento.

Para exemplificar o seu uso, vamos utilizar uma aplicação WPF para iniciará a requisição, e enquanto ela estiver sendo executada, vamos dar a possibilidade ao usuário dele conseguir cancelar a mesma. Note no código abaixo que criamos em nível da classe um membro chamado status, qual será o responsável por gerenciar um eventual cancelamento. No clique do botão Requisitar, estamos recorrendo ao método GetAsync (chamando-o de forma assíncrona) e passamos o CancellationTokenSource. É importante notar que temos que envolver este código em um bloco try/catch para interceptar a exceção do tipo TaskCanceledException, que será disparada quando o cancelamento for efetivamente realizado.

public partial class MainWindow : Window
{
private CancellationTokenSource status;
private HttpClient proxy = new HttpClient();

    private async void Requisitar_Click(object sender, RoutedEventArgs e)
{
Reinicializar();

        try
{
var resposta = await proxy.GetAsync(Url.Text, status.Token);

            if (resposta.IsSuccessStatusCode)
Conteudo.Text = await resposta.Content.ReadAsStringAsync();
}
catch (TaskCanceledException)
{
Conteudo.Foreground = Brushes.Red;
Conteudo.Text = “*** A REQUISIÇÃO FOI CANCELADA ***”;
}
}

    private void Reinicializar()
{
Conteudo.Text = null;
Conteudo.Foreground = Brushes.Black;

        status = new CancellationTokenSource();
}

    private void Cancelar_Click(object sender, RoutedEventArgs e)
{
status.Cancel();
}
}

Agora o cancelamento pode ser solicitado ao clicar no botão Cancelar, e através do método Cancel da classe CancellationTokenSource, o código para o qual passamos este token (que foi o GetAsync) identifica a solicitação e cancela a execução, disparando a exceção que falamos acima. As imagens abaixo ilustram tanto a requisição sendo executada com sucesso quanto um cancelamento sendo solicitado e acatado, abortando o processamento.