É inegável a importância que os Web Services adquiriram dentro da área de tecnologia, sobretudo se consideradas situações que envolvam a transferência de informações em tempo real. Independentemente do tipo integração a que se prestem, estas construções podem trafegar quantidades consideráveis de dados por uma rede.

Levando em conta estes fatos, é fácil chegar à conclusão de que questões envolvendo performance podem adquirir uma importância vital em muitos ramos de negócio. Empresas de e-commerce e instituições bancárias constituem bons exemplos disto. Diante destas preocupações, a utilização de técnicas de compressão pode se revelar como uma excelente opção nestes cenários, uma vez que contribuirá para reduzir o volume dos dados que se movem de um ponto a outro.

A meta deste artigo é apresentar, de uma maneira rápida e direta, uma alternativa para a implementação da compressão em serviços Web API. A fim de cumprir tal objetivo será utilizado um package do NuGet que simplifica esta tarefa, partindo para isto de um exemplo envolvendo um Web Service para consulta a um catálogo de produtos.

Implementando o serviço Web API para testes

Para implementar o projeto detalhado neste artigo foram utilizados os seguintes recursos:

  • O Microsoft Visual Studio Professional 2013 Update 4 como IDE de desenvolvimento;
  • O .NET Framework 4.5.1;
  • O Microsoft ASP.NET Web API 2.2;
  • O package Microsoft.Owin, que contém recursos básicos para utilização dos componentes OWIN;
  • O package Microsoft.Owin.Host.HttpListener, o qual permite a utilização de um servidor OWIN a partir de uma aplicação .NET;
  • O package Microsoft.Owin.Hosting, que contempla a infraestrutura básica para hospedagem e execução de aplicações OWIN;
  • O package Microsoft.AspNet.WebApi.Owin, que disponibiliza recursos para execução de um serviço Web API em um servidor OWIN;
  • O package Microsoft.AspNet.WebApi.MessageHandlers.Compression, o qual contém um módulo que simplifica o processo de compactação de mensagens geradas por uma aplicação Web API. Diferentemente dos demais pacotes, este último item não é disponibilizado pela Microsoft (na verdade, trata-se do resultado de um projeto open source publicado no repositório do NuGet).

Um projeto do tipo “Console Application” chamado “ExemploFinancas” deverá ser criado, como indicado na Imagem 1.

webapi-compressao-01
Imagem 1: Criando uma Console Application no Visual Studio 2013

OBSERVAÇÕES:

  • OWIN (sigla do inglês “Open Web Interface for .NET”) é um projeto open source criado com o objetivo de desacoplar aplicações Web criadas em .NET de servidores de aplicação convencionais (notadamente o IIS), a partir de um conjunto de funcionalidades que procura fornecer um ambiente modular e mais leve em termos de alocação de recursos. Esta solução torna possível que serviços Web API sejam hospedados em Console Applications, Windows Services ou, até mesmo, Worker Roles criadas na plataforma Azure;
  • Embora o exemplo abordado neste post faça uso de uma Console Application, em um cenário real as outras alternativas citadas (Windows Service, Worker Role) seriam mais adequadas para a hospedagem “self-host” de um serviço utilizando OWIN.

Para a instalação dos packages requeridos para o projeto TesteCompressaoWebAPI acessar o menu “TOOLS” e, em seguida, “NuGet Package Manager” > “Package Manager Console” (Imagem 2).

webapi-compressao-02
Imagem 2: Acessando o NuGet Package Manager

Aparecerá neste momento a janela “Package Manager Console” (Imagem 3), na qual deverão ser digitadas as seguintes linhas de comando:

Install-Package Microsoft.Owin
Install-Package Microsoft.Owin.Host.HttpListener
Install-Package Microsoft.Owin.Hosting
Install-Package Microsoft.AspNet.WebApi.Owin
Install-Package Microsoft.AspNet.WebApi.MessageHandlers.Compression

webapi-compressao-03
Imagem 3: O prompt de comandos do NuGet Package Manager

O próximo passo agora será a criação de uma nova classe que terá por nome “Produto” (Listagem 1), representando itens comercializados por uma empresa fictícia. Constarão neste tipo propriedades indicando o código de um produto, o nome/descrição do mesmo, além de seu preço de venda.

namespace TesteCompressaoWebAPI
{
    public class Produto
    {
        public string CodProduto;
        public string NomeProduto;
        public double Preco;
    }
}

Listagem 1: Classe Produto

Na Listagem 2 está a definição do tipo ProdutosController. Este Controller retornará um catálogo de produtos comercializáveis, sendo possível observar no mesmo:

  • A classe ProdutosController herda do tipo básico ApiController (System.Web.Http), o qual contém os recursos necessários para a implementação de Controllers dentro da tecnologia Web API;
  • A presença da Action GetProdutos, responsável por devolver uma coleção de instâncias do tipo Produto (criadas com valores “fake”, para efeitos de teste). Este método será utilizado no tratamento de requisições HTTP do tipo GET, toda vez que uma solicitação neste padrão for direcionada ao serviço representado por ProdutosController.
using System.Collections.Generic;
using System.Web.Http;

namespace TesteCompressaoWebAPI
{
    public class ProdutosController : ApiController
    {
        public IEnumerable<Produto> GetProdutos()
        {
            List<Produto> produtos = new List<Produto>();

            Produto prod;
            for (int i = 1; i <= 100; i++)
            {
                prod = new Produto();
                prod.CodProduto = i.ToString("0000");
                prod.NomeProduto = string.Format("PRODUTO {0:0000}", i);
                prod.Preco = i / 10.0;

                produtos.Add(prod);
            }

            return produtos;
        }
    }
}

Listagem 2: Classe ProdutosController

As configurações para a execução do serviço Web API de consulta a produtos estão declaradas na classe Startup, cujo código-fonte encontra-se na Listagem 3:

  • O método Configuration recebe como parâmetro uma referência do tipo IAppBuilder (namespace Owin), na qual constarão as configurações a serem utilizadas pelo OWIN na hospedagem da solução de exemplo;
  • Uma nova instância da classe HttpConfiguration (namespace System.Web.Http) será gerada. A partir da propriedade Routes deste objeto será especificado o comportamento das rotas possíveis para uma aplicação, por meio de uma chamada ao método MapHttpRoute;
  • A produção de mensagens de retorno utilizando XML será desativada, através de uma chamada ao método Remove do objeto associado à propriedade Formatters;
  • O objeto do tipo HttpConfiguration será então informado como parâmetro ao se invocar a operação UseWebApi de IAppBuilder (usando para isto a referência recebida pelo método Configuration). Será este ajuste que habilitará a hospedagem do serviço Web API, empregando para isto os mecanismos disponibilizados pelo projeto OWIN.
using Owin;
using System.Web.Http;

namespace TesteCompressaoWebAPI
{
    public class Startup
    {
        public void Configuration(IAppBuilder appBuilder)
        {
            HttpConfiguration config = new HttpConfiguration();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "testes/{controller}"
            );

            config.Formatters.Remove(
                config.Formatters.XmlFormatter);

            appBuilder.UseWebApi(config);
        }
    }
}

Listagem 3: Classe Startup

Por fim, será necessário ajustar a classe Program para que se inicie a execução do serviço Web API de testes. Na Listagem 4 estão as instruções que ativarão a hospedagem via OWIN, através de uma chamada ao método Start do tipo WebApp (namespace Microsoft.Owin.Hosting): para esta operação foram informados como parâmetro a classe Startup (já descrita anteriormente), além de uma URL base para o acesso à aplicação em questão (o valor “55042” corresponde a uma porta disponível no momento da implementação do projeto TesteCompressaoWebAPI).

using System;
using Microsoft.Owin.Hosting;

namespace TesteCompressaoWebAPI
{
    class Program
    {
        static void Main(string[] args)
        {
            using (WebApp.Start<Startup>("http://localhost:55042/"))
            {
                Console.WriteLine(
                    "Serviço de consulta de produtos em execução...");
                Console.WriteLine(
                    "Pressione qualquer tecla para encerrar este processo...");

                Console.ReadKey();
            }
        }
    }
}

Listagem 4: Classe Program

Concluída esta primeira fase de implementação, será necessário agora executar a aplicação de exemplo. Ao se fazer isto aparecerá como resultado a tela indicada na Imagem 4.

webapi-compressao-04
Imagem 4: O projeto TesteCompressaoWebAPI em execução

Para testar o serviço descrito neste post será utilizada a seguinte URL:

http://localhost:55042/testes/produtos

O utilitário Fiddler também será empregado nesta demonstração, a fim de determinar se as respostas devolvidas pelo Web Service estão ou não utilizando o recurso de compressão. Conforme é possível observar na Imagem 5, o endereço para testes foi indicado no filtro de requisições da seção “Filters” deste aplicativo.

webapi-compressao-05
Imagem 5: Configurando o Fiddler para monitorar o serviço de testes

Uma requisição será então encaminhada ao serviço de consulta ao catálogo de produtos através do Google Chrome (Imagem 6). O resultado será um texto no formato JSON, no qual constarão informações de um conjunto de 100 produtos.

webapi-compressao-06
Imagem 6: Efetuando um teste através via Google Chrome

O retorno gerado pelo Web Service também poderá ser observado pelo utilitário Fiddler. Na Imagem 7 encontram-se destacados em vermelho o tamanho (6.302 bytes) da resposta produzida pelo serviço, além do conteúdo deste retorno (um header com informações gerais, além de uma string JSON com dados do catálogo de produtos).

 

webapi-compressao-07
Imagem 7: Resposta capturada via utilitário Fiddler

Ativando o mecanismo de compressão

Para ativar o uso da compressão será necessário modificar o método Configure da classe Startup (Listagem 5), adicionando uma instância do tipo ServerCompressionHandler (namespace Microsoft.AspNet.WebApi.MessageHandlers.Compression) à propriedade MessageHandlers do objeto associado à variável “config”. Esta nova referência de ServerCompressionHandler recebe como parâmetros instâncias dos tipos GZipCompressor e DeflateCompressor (ambas declaradas no namespace Microsoft.AspNet.WebApi.MessageHandlers.Compression.Compressors), as quais serão empregadas no processo de compactação dos dados.

using Owin;
using System.Web.Http;
using Microsoft.AspNet.WebApi.MessageHandlers.Compression;
using Microsoft.AspNet.WebApi.MessageHandlers.Compression.Compressors;

namespace TesteCompressaoWebAPI
{
    public class Startup
    {
        public void Configuration(IAppBuilder appBuilder)
        {
            HttpConfiguration config = new HttpConfiguration();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "testes/{controller}"
            );

            config.Formatters.Remove(
                config.Formatters.XmlFormatter);

            config.MessageHandlers.Insert(0,
                new ServerCompressionHandler(
                    new GZipCompressor(),
                    new DeflateCompressor())); 

            appBuilder.UseWebApi(config);
        }
    }
}

Listagem 5: Classe Startup após ajustes

Um novo teste no Google Chrome após a atualização do projeto TesteCompressaoWebAPI mostrará, via utilitário Fiddler (Imagem 8), que a resposta produzida pelo serviço de consulta de produtos já se encontra compactada:

  • O tamanho da resposta foi reduzido para 741 bytes;
  • O atributo “Content-Encoding” do header está com o valor “gzip”, o qual corresponde ao padrão de compressão empregado pelo Web Service.

webapi-compressao-08
Imagem 8: Resposta após o uso do recurso de compressão

Conclusão

A solução apresentada neste artigo é apenas uma das alternativas disponíveis para o uso de técnicas de compressão em serviços Web API. A compactação da resposta produzida por uma estrutura deste tipo pode ser de grande valia, principalmente se levados em conta cenários que envolvam um grande número de acessos e/ou um volume considerável de dados trafegados. Outro caminho possível passaria pela implementação de um Action Filter, o qual seria vinculado a cada método de um Web Service que necessitasse deste comportamento específico.

Espero que este conteúdo possa ter sido útil.

Até uma próxima oportunidade!

Referências

ASP.NET Web API
http://www.asp.net/web-api

Fiddler – free web debugging proxy
http://www.telerik.com/fiddler

Fontes da solução descrita neste artigo
https://github.com/renatogroffe/TesteCompressaoWebAPI

Microsoft ASP.NET Web API Compression
https://www.nuget.org/packages/Microsoft.AspNet.WebApi.MessageHandlers.Compression/

OWIN – Open Web Interface for .NET
http://owin.org/

Utilitário Fiddler: Monitoramento de Web Services
http://www.devmedia.com.br/utilitario-fiddler-monitoramento-de-web-services/31274

Renato Groffe

Atua como consultor em atividades voltadas ao desenvolvimento de softwares há mais de 13 anos. Bacharel em Sistemas de Informação, com especialização em Engenharia de Software. Microsoft Certified Technology Specialist (Web, WCF, Distributed Applications, ADO.NET, Windows Forms), Microsoft Specialist (HTML5 with JavaScript and CSS3, Developing ASP.NET MVC 4 Web Applications), Oracle Certified Associate (PL/SQL), Sun Certified (SCJP, SCWCD), ITIL Foundation V2, Cobit 4.1 Foundation.

Facebook Google+ 

Comentários

comentarios