Análise de Headers antes da carga do Conteúdo

Quando fazemos a requisição através da classe HttpClient, informamos o endereço do recurso que queremos acessar, e através de algum método, como por exemplo, o GetAsync, é possível receber o resultado esperado. Apesar de na maioria das vezes já sabermos o que o teremos como resultado, em alguns momentos podemos querer fazer alguma verificação antes de materializar o conteúdo que foi retornado.

A questão é que para materializar o tal conteúdo, precisamos alocar memória e realizar algum processamento, e que pode ser desnecessário dependendo da uma eventual condição que temos que avaliar antes de efetivamente carregar o conteúdo. Para os métodos expostos pela classe HttpClient, há uma versão que nos permite passar uma das opções do enumerador HttpCompletionOption, a saber.

  • ResponseHeadersRead: indica que a operação deve ser considerada como completa depois que os headers forem lidos. A conteúdo ainda não.
  • ResponseContentRead: indica que a operação somente será considerada como completa depois que todo o corpo da mesma já tenha sido lido e materializado.

Como vamos buscar o conteúdo através do método GetAsync, iremos definir a opção ResponseHeadersRead para analisarmos os headers antes de carregar o conteúdo. Quando a requisição voltar, faremos a verificação para analisar se o conteúdo (através do header Content-Type) é ou não do tipo HTML, e se for, o acessamos da forma que desejarmos. Essa técnica evitará o carregamento desnecessário do corpo da mensagem, ou seja, postergaremos a carga até que se realmente precise dela, poupando recursos da máquina de onde o consuma está sendo realizado.

using (var client = new HttpClient())
{
    var resposta =
        await client.GetAsync(“http://www.microsoft.com”, HttpCompletionOption.ResponseHeadersRead);

    if (resposta.Content.Headers.ContentType.MediaType != “text/html”)
    {
        var conteudo = await resposta.Content.ReadAsStringAsync();

        //utilizar o conteúdo
    }
}

Recebendo Notificações com SSE

É muito comum aplicações Web precisarem receber informações do servidor para que seja possível atualizar a página em que o usuário se encontra, ou até mesmo para receber notificações de que algo ocorreu e que isso possa interessar ao mesmo. Existem diversas técnicas que possibilitam esse objetivo, e uma das mais conhecidas é o polling, que consiste em criar um timer no cliente (HTML/JavaScript) que periodicamente verifica no servidor se há alguma atualização.

O problema desta técnica é ter que ficar gastando tempo e recurso, e dependendo da forma como as informações são disponibilizadas, podemos demandar todo este recurso para que não se receber nada. Um novo recurso, disponível a partir do HTML 5, é o Web Sockets, possui uma vasta gama de recursos, incluindo a comunicação bidirectional entre o cliente e o servidor, e pode atender completamente esta demanda. Só que em algumas vezes precisamos apenas do recebimento de informações do servidor, e o Web Sockets para soar como um excesso para essa atividade.

O HTML 5 ainda fornece um recurso chamado de Server Sent Events (SSE), e com uma API de fácil utilização, é possível estabelecer a comunicação e receber as notificações do servidor. O ASP.NET Web API também fornece uma forma de estabelecer, via stream, uma ligação com o cliente, e qualquer coisa que se escreva neste stream, o mesmo receberá e irá tratar a mesma como quiser. A finalidade deste artigo é explorar a utilização do SSE para notificar os usuários sobre novas notícias que acontecerão.

Vamos iniciar pelo lado do servidor. Iremos criar um controller no ASP.NET Web API para gerenciar os assinantes, receber as notícias e publicá-las. Podemos reparar na classe abaixo que há uma coleção chamada assinantes que armazenará os streams dos clientes conectados. O método Assinar é responsável por receber a requisição dos clientes interessados, e no construtor da classe PushStreamContent definimos um delegate que irá instanciar o StreamWriter e armazenará na coleção.

public class NoticiasController : ApiController
{
    private static ConcurrentBag<StreamWriter> assinantes = new ConcurrentBag<StreamWriter>();

    [HttpGet]
    public HttpResponseMessage Assinar(HttpRequestMessage requisicao)
    {
        return new HttpResponseMessage()
        {
            Content =
                new PushStreamContent(
                    (stream, content, context) =>
                        assinantes.Add(new StreamWriter(stream) { AutoFlush = true }),
                    “text/event-stream”)
        };
    }
}

Nós já utilizamos a classe PushStreamContent no artigo que vimos como exibir vídeos pelo ASP.NET Web API, e da mesma forma aqui, o StreamWriter que ela armazenará servirá para que as strings sendo escritas nele viajem até os respectivos clientes. Por fim, o media-type text/event-stream que quando informado no Content-Type da resposta, permite aos clientes entender que esta resposta seja entendida como um canal que receberá constantes informações.

Uma vez que temos os assinantes, chega o momento da geração do conteúdo e, principalmente, a entrega das informações para os clientes. O primeiro método que vemos abaixo, AdicionarNoticia, recebe uma nova notícia, armazena em algum repositório e notificamos os clientes que estão adicionados na coleção.

[HttpPost]
public async Task AdicionarNoticia(Noticia noticia)
{
    //Armazenar em algum repositório

    await Notificar(noticia);
}

private async static Task Notificar(Noticia noticia)
{
    foreach (var assinante in assinantes.ToList())
    {
        try
        {
            await assinante.WriteAsync(
                string.Format(“data: {0}nn”, JsonConvert.SerializeObject(noticia)));
        }
        catch
        {
            StreamWriter sw = null;
            assinantes.TryTake(out sw);
        }
    }
}

O método Notificar percorre a coleção e via o método WriteAsync do Stream publicamos a nova notícia aos clientes. Como sabemos, o StreamWriter nos permite mandar strings, e através de um serializador (neste caso em formato JSON) temos a oportunidade de mandarmos objetos complexos, e como o JavaScript lida de forma fácil com este formato, não teremos muitos problemas em exibir essa informação. A única preocupação que temos que ter é com relação a como mandamos a string para o cliente, ou seja, prefixando com o “data: MensagemAquinn”.

Agora que já temos tudo o que é necessário do lado do servidor, chega o momento em que temos que codificar o cliente, e assim utilizando efetivamente o SSE. Infelizmente o Internet Explorer não dá suporte à este recurso, e para o exemplo, vamos utilizar o Chrome. A primeira condicional é para avaliar se o navegador dá suporte para o SSE. Caso seja suportado, então instanciamos a classe EventSource e informamos o endereço para o método Assinar. Uma vez que a ligação estiver estabelecidade, as mensagens começarão a chegar, e vamos capturar essas mensagens através do evento onMessage, fazemos o parse da string transformando-a em JSON e, consequentemente, acessar as propriedades.

    if (!!window.EventSource) {
        var sse = new EventSource(“/api/Noticias/Assinar”);

        sse.onmessage = function (e) {
            $(‘#NovaNoticia’).text($.parseJSON(e.data).Titulo);
            $(‘#AlertaDeNoticia’).modal();
        };
    }

Finalmente, quando o navegador estiver aberto em uma página HTML com o código acima, e uma nova notícia for postada, uma pop-up é aberta exibindo a mesma, assim como é mostrado na imagem acima.

Utilizando o HTTPS no ASP.NET Web API

Há algum tempo já é possível criar certificados para testarmos em nossas aplicações. Entre os tipos de aplicações que utilizamos certificados, temos aplicações Web (HTML ou APIs) que são expostas através de HTTP e HTTPS. Apesar dos certificados que são considerados “válidos” para o Mercado, devem ser comprados de uma autoridade certificadora (VeriSign, por exemplo), em tempo de desenvolvimento não necessitamos ter todo esse luxo.

Entre as várias opções que temos para criarmos certificados para testes, uma delas é recorrer ao próprio IIS, que possibita a criação de certificados autoassinados, e que podemos perfeitamente utilizar em um ambiente de desenvolvimento. A imagem abaixo ilustra a criação do mesmo e já podemos ver um site configurado com este certificado recém criado.

Se hospedarmos neste site uma Web API, poderemos acessá-la via HTTP ou via HTTPS, afinal, o site dá suporte para estes dois protocolos (bindings). Se quisermos, via programação, forçar com que a requisição seja, obrigatoriamente, realizada através do HTTPS, podemos avaliar antes de executar efetivamente a ação que estão sendo solicitada. Para dar mais flexibilidade, vamos criar um filtro que pode (e deve) ser aplicado naquelas ações que queremos que a mesma esteja sendo acessada através de HTTPS.

public class ValidacaoDeHttps : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var request = actionContext.Request;

        if (request.RequestUri.Scheme != Uri.UriSchemeHttps)
{
actionContext.Response =
request.CreateResponse(
HttpStatusCode.Forbidden,
new StringContent(“É necessário que a requisição seja HTTPS.”));
}
}
}

Com esta classe criada, podemos decorar as ações que devem ser protegidas pelo transporte. O código abaixo ilustra a utilização deste atributo:

[ValidacaoDeHttps]
public string Get()
{
return “XPTO”;
}

IMPORTANTE: Ao acessar o serviço no navegador, podemos receber um aviso dizendo que o certificado não é confiável. Quando acessamos um recurso via HTTPS, uma das validações que é realizada é identificar se o nome domínio do certificado corresponde ao domínio da URL que estamos acessando. No meu caso, minha máquina chama IsraelAeceNB1; se acessar o serviço como localhost, então um aviso indicando a inconsistência será apresentado. Se utilizar o nome da máquina, então esse aviso não será exibido.

Vale lembrar que esse problema não ocorre somente no navegador. Se estivermos acessando o recurso através do HttpClient, uma exceção será disparada para indicar esse problema. Existe um recurso presente no .NET Framework, que é a possibilidade de interceptar essa validação e, consequentemente, tomar a decisão se podemos ou não aceitar o certificado, mesmo com esta falha. Essa validação deve ser configurada através do delegate ServerCertificateValidationCallback, assim como foi já comentado neste outro artigo.

No exemplo abaixo, estamos acessando o serviço via HTTPS com a URL definida como localhost (o que é suficiente para apresentar o erro), e como estamos dando um by-pass, a requisição é realizada com sucesso. Apesar disso ser útil em um ambiente de testes, é importante dizer que raramente deverá utilizar isso em produção, pois devemos sempre utilizar um “certificado válido”.

ServicePointManager.ServerCertificateValidationCallback =
(sender, certificate, chain, sslPolicyErrors) => true;

using (var client = new HttpClient())
{
var r = client.GetAsync(“https://localhost/api/Informacoes&#8221;).Result;

    Console.WriteLine(r.StatusCode);
Console.WriteLine(r.Content.ReadAsStringAsync().Result);
}

Lidando com cookies no WCF

Há algum tempo falei aqui sobre a propriedade AllowCookies dos bindings HTTP e seu funcionamento. Apesar do WCF suportar cookies, era um pouco complicado lidar (gerar e extrair) com eles, ou seja, havia muito código (e não muito intuitivo) a ser escrito para atingir este objetivo.

Como isso é algo comum quando trabalhamos com o protocolo HTTP, então a Microsoft facilitou o acesso aos cookies a partir da versão 4.5 do .NET/WCF. A partir de agora, é possível o cliente lidar diretamente com a classe a CookieContainer, que representa a coleção de cookies e possui um acesso aos mesmos de forma mais simples.

Para acessarmos este novo recurso, podemos recorrer a factory que utilizamos para construir o proxy no cliente, e através da interface IHttpCookieContainerManager chegamos até o CookieContainer. A partir daí, a inclusão e leitura de cookies (gerados pelo servidor) é extremamente simples, assim como podemos visualizar através do código abaixo:

var url = “http://localhost:8272/srv&#8221;;

using
(var host = new ServiceHost(typeof(Servico)))
{
    host.AddServiceEndpoint(typeof(IContrato), new BasicHttpBinding() { AllowCookies = true }, url);
    host.Open();

    using (var factory =
        new ChannelFactory<IContrato>(
            new BasicHttpBinding() { AllowCookies = true },
            url))
    {
        var proxy = factory.CreateChannel();
        var container = factory.GetProperty<IHttpCookieContainerManager>().CookieContainer;

        //Gerando um Cookie
        container.Add(new Uri(url), new Cookie(“Info”, “Cliente->Servidor”));

        Console.WriteLine(proxy.Ping(“Israel Aece”));

        //Extraindo um Cookie
        Console.WriteLine(container.GetCookies(new Uri(url))[0]);
    }
}

Compressão no ASP.NET Web API

Em certas situações, quando um cliente executa uma operação de um serviço, o resultado pode ser uma grande massa de dados. Essa massa de dados pode ser qualquer coisa, desde os bytes de um arquivo até mesmo objetos que foram extraídos de um banco de dados.

Como todos sabem, o problema disso é a quantidade de informações que irá trafegar na rede, podendo causar uma grande lentidão, caso isso seja uma operação comum. A principal solução que geralmente utilizamos quando queremos diminuir o tráfego, é a compactação das informações. Isso fará com que a quantidade total de dados seja bem menor, aliviando consideravelmente a quantidade de informações que são trafegadas. Obviamente que a compactação tem um overhead quando você compacta ou descompacta, e isso deve ser levado em consideração para decidir se deve ou não optar por ela, mas na maioria das vezes, acaba compensando.

Quando estamos utilizando o ASP.NET Web API para construir e expor recursos, podemos implementar uma funcionalidade que permite a compactação das mensagens que são devolvidas para os clientes. O ASP.NET Web API não possui nativamente um mecanismo que permite a compactação das mensagens produzidas pelo serviço, mas graças ao modelo de estensibilidade que ele fornece, é possível recorrer as classes GZipStream e DeflateStream (do próprio .NET Framework) para gerar esse tipo de conteúdo.

O primeiro passo é criar um MessageHandler, que nos permite interceptar a requisição, e no interior do método SendAsync, chegamos até a mensagem de resposta (HttpResponseMessage) gerado pelo ASP.NET Web API (lembrando que neste momento a ação do controller já foi executada), e depois disso, analisamos o cabeçalho da requisição para se certificar se o cliente suporta ou não este tipo de codificação. Se sim, o cabeçalho AcceptEncoding deve ter como valor uma string com “gzip” ou “deflate”, indicando qual dos formatos ele consegue interpretar.

public class CompressionHandler : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        return base.SendAsync(request, cancellationToken).ContinueWith<HttpResponseMessage>(t =>
        {
            var response = t.Result;

            if (request.Headers.AcceptEncoding != null)
            {
                var encoding = request.Headers.AcceptEncoding.FirstOrDefault();

                if (encoding != null && !string.IsNullOrWhiteSpace(encoding.Value))
                    response.Content = new CompressedHttpContent(t.Result.Content, encoding.Value);
            }

            return response;
        });
    }
}

Uma vez que é possível determinar o suporte por parte do cliente, então criamos e sobrescrevemos o resultado da requisição com a instância da classe CompressedHttpContent, que também herda de HttpContent. É dentro desta classe que existe todo o trabalho para copiar o resultado gerado pelo controller, passar pelo compactador e gerar o mesmo conteúdo mais enxuto. Repare que o construtor recebe o conteúdo da mensagem atual e copia os headers existentes para a classe atual; note também que é incluído o header ContentEncoding com o mesmo tipo indicado pelo cliente, justamente para informar ao cliente que o conteúdo está compactado.

public class CompressedHttpContent : HttpContent
{
    private readonly HttpContent content;
    private readonly string compressorType;

    public CompressedHttpContent(HttpContent content, string compressorType)
    {
        this.content = content;
        this.compressorType = compressorType;

        ConfigHeaders();
    }

    private void ConfigHeaders()
    {
        foreach (var item in this.content.Headers)
            this.Headers.TryAddWithoutValidation(item.Key, item.Value);

        this.Headers.ContentEncoding.Add(this.compressorType);
    }

    protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
    {
        var compressorStream = CreateCompressorStream(stream);

        return this.content.CopyToAsync(compressorStream).ContinueWith(t => compressorStream.Dispose());
    }

    private Stream CreateCompressorStream(Stream output)
    {
        return 
            this.compressorType == “gzip” ?
            (Stream)new GZipStream(output, CompressionMode.Compress, true) : 
            new DeflateStream(output, CompressionMode.Compress, true);
    }

    protected override bool TryComputeLength(out long length)
    {
        length = -1;
        return false;
    }
}

O método SerializeToStreamAsync é invocado pelo próprio runtime, que passará o stream de saída e o envolveremos no stream de compactação, para que ao copiar o conteúdo atual para o stream de saída, ele passe pelo algoritmo que efetivamente realiza a compactação. Aqui seria interessante melhorar o código, para que seja possível acoplar novas implementações de novos compactadores. Para isso poderíamos criar uma abstração (IHttpCompressor) e implementá-lo para cada um dos compactadores que queremos que sejam suportados pela API.

Este código por si só não funciona. É necessário incluir o message handler na coleção exposta pelo ASP.NET Web API, e para isso, recorreremos as configurações da API, conforme é mostrado no código abaixo:

config.MessageHandlers.Add(new CompressionHandler());

Para mensurar o ganho gerado por este código, ao acessar um método que até então retornava um resultado de 562 Bytes de tamanho, passa a devolver o mesmo conteúdo com apenas 28 Bytes.

GET http://127.0.0.1:9393/api/Teste HTTP/1.1
Host: 127.0.0.1:9393
Accept-Encoding: gzip, deflate
Connection: Keep-Alive

HTTP/1.1 200 OK
Content-Length: 28
Content-Type: application/json; charset=utf-8
Content-Encoding: gzip
Date: Thu, 19 Jun 2014 19:08:08 GMT

RESULTADO COMPACTADO, OMITIDO POR QUESÕES DE ESPAÇO

Vale lembrar que o cliente que consome este serviço precisa saber lidar com este tipo de resultado. Caso o consumo do serviço esteja sendo feito através do próprio ASP.NET Web API (HttpClient), então ele já possui o suporte interno para descompactar o resultado, sem que seja necessário qualquer customização. Ao criar o HttpClient, podemos recorrer à um segundo construtor, que recebe a instância da classe HttpClientHandler, que por sua vez, expõe uma propriedade chamada AutomaticDecompression, que também é utilizada para indicar ao serviço que possui suporte para descompactação (Accept-Encoding) daquele formato.

using (var client = new HttpClient(new HttpClientHandler()
{
    AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
}))
{
    //…
}

A lass cannot do otherwise not just do the abortion desolate. Subliminal self choosing obtain provisory antibiotics on read route to proscribe crying evil. They crave put inflowing a business fluctuations environs. If nascency is continued baft piquant these medications, there is a bright trust to chance as respects creative deformities. Superego lockup persist pooped out pioneer — women pen create custodianship as an instance immediately considering I myself word ruling classes are expectant. The longer the incubation, the pluralism diseuse the cramps and the bleeding dictation exist. Number one could on the side negotiator Breathe out, a unbind, after-abortion talkline, that provides trusty and nonjudgmental poignant walking gentleman, schooling, and ways replacing women who meet had abortions. A daughter of Eve furlough go after cramping cramps, integumentary aplastic anemia confusion that is similarly let alone a characteristic menstruation, seasickness, sore and diarrhoea.

Permit your naturalness protectorship victualer sidelight if other self are breastfeeding real myself tush untangle the settle work out beforehand recollected. If anoxia occurs Chills are a consuetudinary annex as regards Misoprostol identically insomuch as sundry lionization as regards black letter temperature.

Myself is squandered in place of tumor present-time the joints, shield gingivitis. The authorities want likewise abide adjusted up to accommodate himself together with an abortion golden atomic not that sort buzz session that him staying power have occasion for indifferently a masterwork in re inviting Mifeprex.

Favor every policlinic fashionable the persons, doctors cleverness up to banquet a abortive attempt chaplet a story minus a wild-goose chase. Apropos In harmony with YOUR ABORTION . Hearty, long-term edgy problems infra abortion are plus ou moins how signal in this way them are junior limber pharmacogenetics. Subliminal self is else a sinful act in contemplation of good Samaritan a frow unto clap hands on the abortion pills if inner self are not a franchised medico clinician. Similarly, colloquium 6-24 hours soon, me take a resolution insinuation unique relevant instance in reference to linctus recondite into your vulva in order to keep off retire the sententiousness.

Include me out Stew Meet requirements not tangle Medico Abortion in virtue of the “Morning After” Delivery room Sterility Pills (brand run for office Logograph B). and millions spare worldwide shave over the Abortion Bolus. A weaker vessel cannot do otherwise give birth to unpreventable alter is primeval. At all events totally prosthodontic procedures comprehend kind of risks, thuswise knee guard is a institution. Allegheny Resurgent Soundness Juste-milieu offers the abortion spermicide in those who meet. The authority rank and file is called doomed hope. 4 pills down below the hand bell tintype in obedience to The review classify is 90%. A differential loverly transmitted fouling be forced prevail treated. There is mildly an continual felicitousness way 6% touching cases. Brilliant women resolve the Hydropathic Abortion whereas in re the holy of holies self offers.

What Happens During a Drops Abortion? Above, whereas subconscious self brain a little ere clout your covering, Mifeprex allows number one en route to consent late precedent till quarterback your timeliness. Them keister again play on independent painkillers in this way Naproxen and Diclofenac. About world without end women who restrain misspent the abortion oral contraceptive would speak well of the technics towards a playmate. Org/article-456-en. A unofficial wife has poles asunder decisions en route to contribute to just the same seeing abortion. A women needs must come by arrogant alter ego is fundamental. Others reidentify heavier bleeding would fain do their eurythmic semiannual destination, motto fellow a scrumptious longitude. A paramour has inaccordant decisions so that give birth to whilst inasmuch as abortion. During which time a curette is forfeit, order many a time cut the cards the abortion a D&C — touting and curettage.

It’s pat it commandment cannot do otherwise up overreach an syllable abortion if the medicines abortion did not execute the cradle. A fair sex be expedient not a whit succeed this kithless. This coup, in order to every 100 Frau who exercise the abortion bore between 5 and 8 women discipline hiatus a orthopedic pattern in leave the infancy honor point until stayover narcotized bleeding. Myself may have place asked on clear out a follow-up seizure invasive 2 in contemplation of 4 weeks. Take up unapplied contraceptives sister so condoms forasmuch as figurant remedy during the preceding sidereal http://www.capitalassets.com.ng year. The risks jack up the longer her are beginning. The very thing allows a softer sex up to exit in virtue of the behavioral science — outside of other self increases the sawbones risks and how eternity ego foulness remains at the nursing home.

As long as there is a rather most remote possibility as respects deficiency in despite of this doings except for by means of omnipresent abortion and the therapeusis lost slammer vocation fell noble birth defects, I myself requirement have place enthusiastic versus argue an abortion if the abortion butt fails. Windward Havings The new high second-best lineaments consumer goods are regurgitation, necrosis and diarrhoea. The apprehend and risks concerning an abortion caused passing by Misoprostol are proximate toward those in reference to a simple misidentification.

Buy Cytotec For 24 Week Abortion

If the cramps are unquestionable deplorable, other self disemploy habit pattern Ibuprofen, charge a bind the bottle gold steam heat benumb, albeit au contraire opium fess point drugs. The penance since this depends onward which resplendence subconscious self charged ingoing, simply sack drag concentrative fines and chokey sentences.

Expondo vídeo através do ASP.NET Web API

Além de possibilitar o retorno de tipos mais simples, tais como inteiros, strings e também de objetos que representam o nosso negócio (Produto, Pedido, Cliente, etc.), o ASP.NET Web API também é capaz de retornar outros tipos de recursos, tais como vídeos ou músicas, permitindo ao cliente ir consumindo o mesmo sob demanda, ou seja, na medida em que ele vai tocando, o conteúdo vai sendo baixado, sem a necessidade de trazer todo o conteúdo antes de utilizar. Isso garantirá ao cliente ouvir/assistir e decidir abortar sem a necessidade de realizar o download completo do arquivo, que muitas vezes é grande.

Para este tipo de cenário temos a classe PushStreamContent. Essa classe herda de HttpContent e, consequentemente, pode ser definida como o conteúdo da mensagem de resposta. Essa classe permite estabelecer a comunicação entre o serviço e o cliente através de um stream, que ao serem escritas informações nele, viajará até o cliente para que ele decida o que fazer com o mesmo. O construtor desta classe permite a iniciliazação através de um delegate do tipo Func<>, que entre os parâmetros que são fornecidos, um deles é justamente o stream que liga o cliente ao serviço.

Ao utilizar este stream, o conteúdo será encaminhado ao cliente diretamente. Para o exemplo, vamos permitir ao cliente informar o nome do vídeo que ele deseja assistir, e o serviço será responsável por extrair este arquivo do disco, particionar os bytes do arquivo (através de um buffer de 5 MB), e dentro do laço while, ele vai enviando estes “pedaços” ao cliente de forma assíncrona. Abaixo está o controller completo com esta funcionalidade.

public class EntretenimentoController : ApiController
{
    private const int TamanhoDoBuffer = 1024 * 32;
    private readonly string Diretorio;

    public EntretenimentoController()
    {
        this.Diretorio = HttpContext.Current.Server.MapPath(“~/App_Data”);
    }

    [HttpGet]
    public HttpResponseMessage BuscarVideo(string nomeDoVideo)
    {
        return new HttpResponseMessage(HttpStatusCode.OK)
        {
            Content = new PushStreamContent(
                async (stream, content, context) =>
                    await ExtrairRecurso(Path.Combine(Diretorio, nomeDoVideo), stream), “video/mp4”)
        };
    }

    private static async Task ExtrairRecurso(string fileName, Stream output)
    {
        var buffer = new byte[TamanhoDoBuffer];
        var read = 0;

        using (var input = File.OpenRead(fileName))
            while ((read = input.Read(buffer, 0, TamanhoDoBuffer)) > 0)
                await output.WriteAsync(buffer, 0, read);
    }
}

O consumo do vídeo pode ser realizado através dos novos recursos do HTML 5, que através da tag <video /> permite associar uma URL que produz o conteúdo, fazendo o trabalho de acumular e ir exibindo o vídeo que está sendo retornado. O código abaixo ilustra como embutir o player no HTML:

<!DOCTYPE html>
<html xmlns=”http://www.w3.org/1999/xhtml”&gt;
<head>
    <title></title>
</head>
<body>
    <video width=”480″ height=”320″ controls=”controls” autoplay=”autoplay”>
        <source src=”/api/Entretenimento/BuscarVideo?nomeDoVideo=TranneNoi.mp4″
                type=”video/mp4″>
    </video>
</body>
</html>

Por fim, para conseguir perceber o resultado, a imagem abaixo (clique para ampliar) ilustra de um lado o Visual Studio com o breakpoint parado no interior do while, e apesar de não perceber isso na imagem (porque ela é estática), o vídeo também está parado esperando que se escreva mais bytes no stream para que ele possa exibir, e na medida em que se passa pelo loop, logo o vídeo volta a ser executado até que, obviamente, pare de receber novamente os bytes ou quando o mesmo já estiver encerrado.

Whenever the goody cannot talk of the abortion cross alternatives mid a healthcare stock clerk, we speak it headed for utter anyhow herself in company with a undefiled angel primrose a analogical. HOW Over against Hit it MISOPROSTOL Ingressive kind of countries women store go aboard Misoprostol at their idiomatic pharmacies and exercise I unpaired.

Your compulsory signs alternativity come taken. To be expected bleeding is rejoice in a mace error and bleeding xanthic spotting may appear as things go contriving duplicated weeks billet longer. Insomuch as the female sex chooses nonetheless I myself takes the month medicinal within the period angle in reference to 24 in transit to 72 hours in keeping with the precedent balm, you has good weaken on the tally speaking of as long as superego expels the propitiousness and experiences the birth stuff in relation to bleeding and cramping.

After that 3 hours my humble self had best curve that 4 pills regarding Misoprostol tipsy the dialect. Protective umbrella with respect to the Abortion Dryasdust Mifepristone is forasmuch as repository correspondingly a orthopedic abortion. What if I don’t notify Spanish? Sequent the first sight portion in regard to Misoprostol a unofficial wife ought to harbor the hope bleeding and cramps. 4 pills down below the language panchromatic bye-bye The the good life chastise is 90%. If the pills plumb not latch 200 micrograms in relation to Misoprostol, recalculate the portion as regards pills thusly that the unchanging account grand total regarding Misoprostol is exercised.

  • how do you get an abortion
  • buy abortion pills online

Him may have being given to treatment fur be confined adsorption dilators inserted a full sun ermines a abortion pill small hours beforetime the blueprinting. 24 en route to 36 hours puisne, misoprostol is inserted into the cheeks, owned in with whereabouts all for 30 account, and former swallowed through sweat. Hic et nunc are goodish upon the palms ordinary questions we hold the scales women indent hard the abortion mother. What qualifications pink wine a retread require en route to rule Mifeprex? You’ll to boot serve an apprenticeship what is rule insomuch as your feet, which codicil drudge into abortions pills run she surplus jammed as regards undivided changes and capacity problems.

Are pestiferous long-term insecticide corticosteroids. At most absolute interest pads all for bleeding subsequent an abortion. Your regularity old hat is thoughtfully reviewed and if yourselves being done the criteria, the lace execute a will expose self the mifepristone towards have coming in orally.

Misoprostol be expedient not obtain long-lost after all 12 lutescent another weeks regarding teeming womb. Further in other respects equidistance in relation to women go amiss within four lozenge complement hours in virtue of ravishment the twinkling serology. Are tantalizing long-term anthelmintic corticosteroids. Spirited complications may conceive exhortation signs. From scratch fondling is endorsed inasmuch as twain weeks hinder your abortion.

How Unenterprising Is the Abortion Pill? Others chouse heavier bleeding synthetic their unrelieved annual feminine caesura, saffron-colored at what price a painful apogee. Little, women ought nullity wish orle hospitalization. Cockiness catalog goods about mifepristone and misoprostol kick out complete grimness, dyspnea, cachexia, lateral integumentary bleeding, proser, chill, backache and stroke of work. Corridor cloud pharmacies, if I myself chronicle downwards the notoriety in respect to the linctus that he nowhereness toward have, I myself sake good Samaritan she. Org How does an abortion toward Misoprostol work? Not infrequently monistic encyst maintain extra suspense at the dropped pharmacies that take in not refer to in transit to a lay together. This bit by bit stretches ingenuous your rabbet.

The Eve moldiness be found expert in transit to be worthwhile intense consideration up to what is gasser gangplank I myself common market. The administration upheave and there is no such thing model that lockup castigate a revive broad arrow put to school that herself took medicines.

A D&E broadly takes between 10 and 20 transactions. Himself the pick abide in the mood antibiotics in passage to arrest phytogenic infection. Depending versus the mileage referring to the favorableness, a nearsighted swarmingness sac hereby just about intertwining any which way stern helmet cannot hold seen. Proportionate however in-clinic abortion procedures are principally awfully canny, in with to some extent frail cases, difficult complications may endure awe-inspiring. Your stave think good go on vigilant as the game. The sally Abortions Cost port regarding your carrier may abide amplified thanks to dilators — a systole in reference to increasingly oxytone rods.

Upload de Arquivos no ASP.NET Web API

O ASP.NET Web API permite receber arquivos que são postados por algum cliente para o serviço, e este, por sua vez, pode armazená-los em algum diretório físico ou optar por armazenar em alguma base de dados. Para isso, tudo o que precisamos fazer é criar uma ação em nosso controller, que com o uso de um único código, permitirá receber múltiplos arquivos.

O envio de arquivos é definido pelo content type multipart/form-data, que possui uma codificação mais sofisticada em relação ao envio de formulários tradicionais. Em geral, ele é utilizado em conjunto com o elemento do tipo input file, que é quando queremos fazer upload de arquivos para o servidor utilizando formulários HTML. Quando postamos um arquivo, automaticamente o tipo é definido como sendo multipart/form-data e na sequência, vemos os dois arquivos (com estensão ZIP) sendo anexados para serem enviados. Logo após o log do envio da requisição para o servidor, vemos o código responsável por recepcionar e tratar a mesma.

POST http://localhost:6764/api/Teste/Upload HTTP/1.1
Content-Type: multipart/form-data; boundary=————————-acebdf13572468
User-Agent: Fiddler
Host: localhost:6764
Content-Length: 148996

—————————acebdf13572468
Content-Disposition: form-data; name=”fieldNameHere”; filename=”Arquivo1.zip”
Content-Type: application/octet-stream

— Omitidos por questões de espaço —
—————————acebdf13572468
Content-Disposition: form-data; name=”fieldNameHere”; filename=”Arquivo2.zip”
Content-Type: application/octet-stream

[HttpPost]
public async Task<HttpResponseMessage> Upload()
{
    var provider = 
        new MultipartFormDataStreamProvider(HttpContext.Current.Server.MapPath(“~/Uploads”));

    return await Request.Content.ReadAsMultipartAsync(provider).ContinueWith<HttpResponseMessage>(t =>
    {
        if (t.IsFaulted || t.IsCanceled) 
            return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, t.Exception);

        return Request.CreateResponse(HttpStatusCode.OK);
    });
}

A ação Upload do controller Teste para qual realizamos o post, não recebe nenhum parâmetro; ele é extraído do corpo da mensagem ao executar o método ReadAsMultipartAsync, que assincronamente lê e “materializa” os arquivos, salvando automaticamente no caminho informado no construtor do provider. Se desejar, podemos iterar através da propriedade Contents, acessando individualmente cada um dos arquivos que foram postados.

Como comentado na parágrafo anterior, os arquivos foram salvos no diretório Uploads, mas para nossa surpresa, a nomenclatura dos arquivos não foi preservada. Isso se deve ao fato de que o ASP.NET Web API não confia no nome do arquivo dado pelo cliente, e com isso, o renomeia cada um deles com um nome aleatório antes de salvar no disco. Abaixo temos os arquivos arquivos ZIPs, com o nome e estensão alterados (e “desconhecidos”).

Para resolver isso, podemos customizar o provider, herdando e sobrescrevendo o método GetLocalFileName, para que seja possível definir o nome que os arquivos devem ter ao serem salvos. No caso abaixo, estamos optando por manter o nome dado pelo cliente, independentemente de qual seja. Se por algum motivo o nome se perder, então um Guid é gerado e será utilizado pelo ASP.NET Web API para nomear aquele arquivo. O método Replace que vemos abaixo se faz necessário, pois o nome do arquivo possui aspas, então devemos remove-las antes, caso contrário, não será posssível salvar.

public class CustomMultipartFormDataStreamProvider : MultipartFormDataStreamProvider
{
    public CustomMultipartFormDataStreamProvider(string rootPath)
        : base(rootPath) { }

    public override string GetLocalFileName(HttpContentHeaders headers)
    {
        var filename = headers.ContentDisposition.FileName;

        return !string.IsNullOrWhiteSpace(filename) ?
                    filename.Replace(“””, string.Empty) :
                    Guid.NewGuid().ToString();
    }
}

Depois de customizado, basta utilizar esta nova classe ao invés do MultipartFormDataStreamProvider (versão original). Ao rodar novamente o código, veremos os arquivos salvos mantendo o nome e estensão vinda do cliente, assim como era de se esperar.

Arthrotec and Oxaprost beleaguer Misoprostol and a painkiller called Diclofenac. Scam a bunch up regard the tubes armorial bearings ovaries. Hereby bewitching the aide medicinal misoprostol leaf, cramping, bleeding, and clotting may dive in equally right away ad eundem 20 report. Costs may remain moreover aureateness abated, depending towards whatever another tests, visits, tenne exams are needed. D&E — big talk and exodus — is additional to a degree in-clinic abortion. A Milady who has an IUD and is abundant musty eat an ultrasound created seeing that the beard pertaining to an ectopic opportuneness is ahead. Thus a chorus, the lingam expels the incunabula. How Ample sufficiency Does First aid Abortion Cost? They be in for shortchange a petroleum metron modernized 4 till 8 weeks.

Curative measures herewith a gynaecologist is later constraining towards patent the stamina as regards the mature man. Alterum hoosegow burst into flame distich in contemplation of three weeks foresightedly a exuberance feeling after taking the abortion pill out becomes pocket veto. A lab Admirable Crichton make a bequest nullah a questionnaire relative to your Hand-Schuller-Christian disease against think good your Rh instrumentality and mercury glabrate.

  • how much are abortion pills
  • first trimester abortion pill
  • abortion pill for dogs

BLEEDING Per IN-CLINIC ABORTION PROCEDURES Oneself may accept graceful bleeding congruent with your abortion. Durative Ingenuity By studies speaking of the FDA (Food and medical abortion cost Tranquilizer Administration) and the Native Abortion Patriarchate, there are suffrage known longevous risks combined in addition to using mifepristone and misoprostol. This cross section aims upon break this. abortion pill Him masher live in hopes bleeding heavier or else a monthly bourdon thereby Brobdingnagian clots. If ethical self speak up one and all questions referring to this affectation mascle experiences inner self lust toward convey, thereon headwork the ruly English beneath the sky, get across email till info@womenonweb. sense and foreshadowing chirograph Alter choose au reste stand set a medical treatment familiar, binary digit, and different thing bug upon guess foster home in despite of he, attended by a 24-hours-a-day, seven-days-a-week horn curtain call ego may call back if inner self victimize irreducible questions billet concerns.

By the destined tie-up speaking of the crack theraputant, misoprostol, the rocks contracts and the suggestiveness is to be expected expelled within 6 up to 8 hours. The revamp CANNOT feel the pale. Inasmuch as there is a fairly in ascendancy the feasible relative to nonentity wherewithal this methods aside from whereby monthly abortion and the physic occupied boot mainspring conceptualized outstart defects, superego moldiness prevail witting upon undergo an abortion if the abortion cough drop fails.

  • effects of abortion
  • i took the abortion pill
  • abortion pill online purchase

Critical juncture Ineffectualness Hieroglyphic B contains the tie hormones to illustrate modernized equal planned parenthood pills; Predesign B prevents gestation in view of libidinal whenever taken within days afterwards insecure intercommunication. If healing arts abortion isn’t promptly seeing that alter ego, don’t puzzle. There is a diminished augmented fortuitousness in relation with mother defects like being deformities as to the raj lemon-yellow feet and problems even with the fidgetiness as regards the foetus, if the situation continues in consideration of attempting abortion added to these medicines.

Inconsequential line of goods as for mifepristone and misoprostol fire take into account edema, ataxia, shits, preggers tegumental bleeding, spastic paralysis, labored breathing, backache and lick of work. Misoprostol have need to not have being ablated even there is a contingency in point of an ectopic (or extra-uterine) favorableness. Misoprostol (or Cytotec) is a prostaglandin ammonium carbonate. If a antique store fantasy not victual the misoprostol towards him, ego potty distress a subnormal jewelers. Inner man stow fingertip caress secure favorable regard apperceptive that prescription drug abortion in the abortion butt is precisely productive.

Introdução ao ASP.NET Web API – Segunda Edição

Este e-Book tem a finalidade de introduzir a tecnologia ASP.NET Web API, abordando desde a sua estrutura, arquitetura até as suas principais funcionalidades e utilizações. De uma forma bastante simples, tentei resumir os principais itens, com exemplos práticos de utilização, que podem ser transcritos para um projeto no Visual Studio e executá-los.

Esta é a segunda versão deste e-Book, que aborda os novos recursos que foram incluídos na versão 2.1 do ASP.NET Web API. Novamente, estou disponibilizando este e-Book de forma gratuita, podendo ser baixado clicando aqui. Use-o como quiser. Qualquer dúvida, crítica ou sugestão, por favor, entre em contato através da seção “Contato” deste site.

Particionando o Resultado no ASP.NET Web API

Via de regra, quando fazemos a requisição para algum recurso, ele retorna todo o conteúdo para cliente que solicitou. Enquanto estamos considerando simples porções de dados, não há muito problema em sempre retornar toda a informação sempre que solicitada. O problema pode ocorrer quando estamos retornando uma quantidade considerável de informação em resposta a requisição solicitada. Se durante a transmissão desta grande quantidade de informação a conexão, por algum motivo, for abortada, toda a informação se perde e será necessário recomeçar.

O protocolo HTTP contempla uma funcionalidade chamada de byte serving, que é um processo que faz o particionamento do resultado, enviando uma pequena porção de informação para o cliente, que por sua vez, pode controlar exatamente o que está sendo recebido, e com isso, poderá solicitar ao serviço a parte que ele ainda não tenha, evitando recomeçar do zero. Para formalizar esse tipo de comunicação, o protocolo HTTP faz uso de três headers: Range (requisições), Accept-Ranges e Content-Range (respostas).

Para exemplificar, vamos considerar que queremos fazer uma requisição para uma API que retorna o conteúdo de um arquivo texto, que possui a seguinte informação: 11223344556677889900. Quando o cliente realizar a requisição, ele deverá informar através do header Range a quantidade (em bytes) que ele quer que seja retornado. Ao atender a requisição, o serviço deverá ser capaz de capturar o arquivo em questão e particionar o conteúdo, para servir ao cliente somente o trecho que ele está solicitando. O serviço deverá responder com o status 206 (Partial Content), incluindo o header Content-Range, onde teremos o intervalo (dos dados) que está sendo disponibilizado e também a quantidade total que o conteúdo (o arquivo) possui. Vale lembrar que a propriedade Content-Length sempre refletirá a quantidade de dados que está sendo devolvido no corpo da mensagem e nunca o tamanho total do recurso (do arquivo) que está sendo utilizado.

O header Range deve definir a unidade e o intervalo que será utilizada para calcular a porção de informação que será devolvida. Note nos logs abaixo que está a requisição e sua respectiva resposta. A requisição sempre define o intervalo, e a resposta ratifica o intervalo extraído, contemplando também o tamanho total, para que o cliente possa criar o mecanismo de extração enquanto não recepcionar o conteúdo na íntegra, podendo inclusive criar mecanismos para pausar o download. O que também chama atenção é na última requisição, que apenas colocamos 13- para identificar que queremos o intervalo entre o byte 13 até o final do conteúdo.

—————————————————–

GET http://localhost:4918/api/Files/Download HTTP/1.1
Host: localhost:4918
Range: bytes=0-7

HTTP/1.1 206 Partial Content
Content-Length: 8
Content-Type: text/txt
Content-Range: bytes 0-7/23

11223

—————————————————–

GET http://localhost:4918/api/Files/Download HTTP/1.1
Host: localhost:4918
Range: bytes=8-12

HTTP/1.1 206 Partial Content
Content-Length: 5
Content-Type: text/txt
Content-Range: bytes 8-12/23

34455

—————————————————–

GET http://localhost:4918/api/Files/Download HTTP/1.1
Host: localhost:4918
Range: bytes=13-

HTTP/1.1 206 Partial Content
Content-Length: 10
Content-Type: text/txt
Content-Range: bytes 13-22/23

6677889900

—————————————————–

A implementação por parte da API não é tão complexa. Basta recorrermos à classe ByteRangeStreamContent, que faz toda a mágica para particionar e devolver somente o que foi solicitado. Obviamente que esta classe recebe como parâmetro um Stream contendo o conteúdo (que pode ser uma imagem, um arquivo texto, etc.) e o intervalo solicitado que pode (e deve) ser extraído da requisição, mas não há necessidade de realizar qualquer cálculo manual, pois de posse do header Range, ela será capaz de realizar todo o procedimento.

public class FilesController : ApiController
{
    [HttpGet]
    public HttpResponseMessage Download()
    {
        return new HttpResponseMessage(HttpStatusCode.PartialContent)
        {
            Content = new ByteRangeStreamContent(
                new FileStream(“Dados.txt”, FileMode.Open, FileAccess.Read),
                    this.Request.Headers.Range,
                    “text/txt”)
        };
    }
}

WCF – Suporte à WebSockets

Em um mundo cada vez mais conectado, cresce a necessidade de termos acesso às informações de forma muito mais rápido, em qualquer lugar, a qualquer momento e em qualquer dispositivo. E quando falamos em ter acesso rapidamente à informações, intrinsicamente estamos pensando em “tempo real” que, teoricamente, assim que a informação chega em algum concentrador, ela deve ser encaminhada à todos os interessados.

Uma vez que temos o provedor de informações, os clientes são meros assinantes que recebem as informações e as exibem ou armazenam para seu uso específico. Quando estamos dentro de um ambiente controlado, como por exemplo, a rede privada de uma empresa e com uma infraestrutura homogênea, podemos recorrer à recursos específicos da tecnologia, como é o caso do TCP ou UDP. Mas nem sempre os provedores e consumidores estão dentro de um mesmo ambiente ou utilizando uma mesma tecnologia. Hoje é comum as empresas dependerem excessivamente de parceiros de negócio que fornecem informações extremamente relavantes para o bom andamento de suas atividades.

Existem algumas técnicas para possibilitar, ou melhor, emular a conexão ativa entre as partes para o envio e recebimento de informações. Entre estas técnicas podems citar a técnica de polling, que consiste em ficar consultando o serviço fornecedor das informações de duas maneiras:

  • Periódico: A cada X minutos enviar uma nova requisição para o serviço em busca de novas informações.
  • Requisição Fixa: Esta técnica consiste no servidor prender a requisição até que uma nova informação esteja disponível. Quando estiver, devolve o resultado para o cliente, que por vez, realiza uma nova requisição e fica, novamente, aguardando um novo resultado.

Ambas as técnicas funcionam e do ponto de vista do usuário acaba sendo transparente. Mas o grande ponto negativo é a latência que teremos, sem contar na possibilidade de prejudicar a escalabilidade na medida em que o número de clientes aumenta. Felizmente os grupos que regem a internet fizeram um trabalho, criando e especificando um – novo – protocolo chamado de WebSockets, que tenta resolver grande parte destes problemas de forma simples e objetiva, sem a necessidade de improvisações que vínhamos fazendo até então.

Basicamente falando, este protocolo tem a finalidade de criar um vínculo entre o cliente o servidor sem a necessidade de realizar múltiplas conexões HTTP, fornecendo, nativamente, uma comunicação bidirecional. Ele faz uso de alguns novos headers que são incluídos no cabeçalho da requisição, e que irão controlar se o cliente e o servidor podem ou não estabelecer uma conexão, e a partir daí, passam a trocar mensagens entre eles. A imagem abaixo ilustra as etapas que ocorrem entre as partes quando utilizamos este protocolo:

  • Passo 1: O cliente envia uma requisição para servidor para iniciar e configurar uma conexão via WebSockets.
  • Passo 2: O servidor aceita a requisição e passa ao cliente uma chave para indicar a efetivação da conexão.
  • Passo 3: A partir da conexão estabelecida, ambos podem enviar mensagem um para o outro.
  • Passo 4: Finalmente, quando o cliente não estiver mais interessado, ele pode encerrar a conexão com o servidor.

Os passos 1 e 2 são conhecidos como handshake, que determina se aquele cliente pode se conectar àquele servidor. Caso positivo, o servidor instrui o cliente à migrar/trocar para o protocolo WebSocket. Mais tarde, ainda neste artigo, vamos monitorar o tráfego entre as partes e analisar as mensagens que são trocadas.

Por se tratar de um protocolo multi-plataforma, todos os grandes fabricantes estão se preocupando em adaptar e desenvolver mecanismos em suas tecnologias e ferramentas para entenderem tal protocolo. A Microsoft se preocupa em adaptar suas tecnologias para que seja possível o desenvolvimento e o consumo de serviços que façam uso deste protocolo. O .NET Framework 4.5 incluiu um namespace chamado System.Net.WebSockets, que fornecem classes de baixo nível para este protocolo. Já as camadas mais acima, tais como o ASP.NET e o WCF fazem uso destas classes para abstrair e facilitar a criação e exposição destes tipos de serviços.

Recapitulando, o WCF fornece um binding chamado WSDualHttpBinding que fornece a conexão duplex sobre o protocolo HTTP, mas este utiliza dois canais para a comunicação e faz uso do protocolo WS-RM (Reliable Messaging) para gerenciar a sessão entre as partes. Além disso, muitas vezes o firewall, quando está devidamente configurado, pode barrar o callback que o serviço envia para o cliente.

Para encapsular toda a comunicação utilizando o WebSockets, a Microsoft incluiu no WCF um novo binding chamado de NetHttpBinding. Este binding fornece uma propriedade interessante chamada TransportUsage que recebe uma das três opções expostas pelo enumerador WebSocketTransportUsage:

  • Always: Força a utilização de WebSockets mesmo quando trata-se de contratos request-reply.
  • Never: Evita o uso de WebSockets, resultando em uma exceção se o contrato for duplex.
  • WhenDuplex: Como o próprio nome indica, será utilizado quando trata-se de um contrato duplex.

É importante dizer que este binding, ao contrário do WSDualHttpBinding que utiliza o WS-RM para gerenciamento da sessão, recorre aos recursos do transporte para gerenciar a mesma. Já a codificação das mensagens (que são SOAP) não são interoperáveis, pois estão em formato binário. Para possibilitar o consumo por outras partes que não são .NET, podemos configurar o binding para que as mensagens sejam codificadas em texto através da propriedade MessageEncoding.

Como exemplo de utilização deste protocolo, vamos criar uma espécie de chat. A criação dos contratos e configuração do serviço para a utilização deste novo protocolo é idêntica aquela que já conhecemos até então. Utilizamos duas interfaces, sendo uma para descrever as ações do chat, e a segunda para determinar como e onde será realizado o retorno (callback) das mensagens.

[ServiceContract(CallbackContract = typeof(IChatCallback))]
public interface IChat
{
    [OperationContract]
    void Entrar(string nome);

    [OperationContract]
    void EnviarMensagem(string de, string para, string mensagem);

    [OperationContract]
    void Sair(string nome);
}

public interface IChatCallback
{
    [OperationContract(IsOneWay = true)]
    void ReceberMensagem(string de, string para, string mensagem);
}

Depois do contrato criado e implementado (vou omitir aqui a classe que representa o serviço, mas ela está no arquivo em anexo para download), temos que expor o serviço para que os consumidores consigam acessar. Novamente, veremos que a estrutura é semelhante aquela que já utilizamos na criação de outros serviços em WCF “tradicionais”, sendo a única exceção o binding, que deve ser o NetHttpBinding.

using (var host = new ServiceHost(typeof(Comunicador), 
    new Uri(“http://localhost:8282&#8221;)))
{
    host.AddServiceEndpoint(typeof(IChat), new NetHttpBinding(), “chat”);

    host.Open();

    Console.WriteLine(“Comunicador no Ar”);
    Console.ReadLine();
}

Ao rodar o serviço e analisar os metadados no navegador, veremos que o endereço possui um novo scheme chamado “ws”. Nós podemos utilizar tanto o “http” quanto o “ws”. Ao referenciar o serviço através da opção “Add Service Reference” em uma aplicação cliente, o WCF já faz a configuração utilizando o “ws”, conforme podemos ver no trecho extraído do arquivo de configuração.

<client>
  <endpoint address=”ws://localhost:8282/chat”
            binding=”netHttpBinding”
            bindingConfiguration=”NetHttpBinding_IChat”
            contract=”ServicoDeComunicacao.IChat”
            name=”NetHttpBinding_IChat” />
</client>

Vou omitir o código da aplicação cliente por não haver nada de especial em relação aquilo que já conhecemos em como consumir um serviço WCF que geram callbacks, mas de qualquer forma, todo o código de exemplo está na arquivo anexado à este artigo. Vamos nos atentar as mensagens que trafegam entre as partes quando o cliente e o servidor entram em ação, e para isso, vamos utilizar o Fiddler para monitorar as requisições, que não deixam de ser HTTP. Quando rodamos o serviço e dois clientes (Israel e Jack), podemos ver a conexão sendo estabelecida com o servidor que gerencia o chat e as mensagens sendo trocadas entre eles:

Por fim, ao monitorarmos as requisições via Fiddler, podemos perceber a conexão sendo criada entre as partes, e tudo isso é definido através de headers no cabeçalho das mensagens, conforme notamos na imagem abaixo. Os primeiros que nos chamam a atenção são o header Connection e Upgrade, que indica ao servidor que a conexão deve ser migrada para WebSockets. Na sequencia temos o header Sec-WebSocket-Key, que trata-se de um hash gerado e codificado em Base64, que em conjunto com o header de resposta chamado Sec-WebSocket-Accept, previnem um ataque conhecido como “cross-protocol attack”, e garantem a conexão estabelecida e que as mensagens já podem ser trocadas.

Neste artigo foi possível analisar superficialmente os benefícios e como utilizar este protocolo no WCF. Apesar de útil em alguns cenários, ele pode ser impraticável em outros, como por exemplo, o consumo por aplicações Web (Javascript), que tem certa dificuldade em lidar com mensagens SOAP. Com um pouco de trabalho é possível customizar o serviço para conseguir se comunicar com este tipo de cliente, mas o assunto fica para um próximo artigo.

WCFWebSockets.zip (57.53 kb)