WCF Web API agora é ASP.NET Web API

Por algum tempo eu venho falando sobre um novo projeto da Microsoft chamado de WCF Web API, que trata-se de um espécie de estensão do WCF que facilita a construção e o consumo de serviços que são puramente Web (REST), ou seja, estão fortemente amarrados ao protocolo HTTP e o assumem como uma camada de aplicação. Abaixo temos alguns dos artigos que escrevi e que abordam essa tecnologia:

Apesar de possuir uma forma de hospedar esse tipo de serviço através de uma aplicação do tipo Windows (Windows Service, Console, etc.), a sua forma mais natural é utilizar o IIS, ou melhor, utilizar qualquer template de aplicação ASP.NET e lá criar a classe que representará o serviço, e apenas com uma linha de código, é o suficiente para mapear uma URI base para o serviço e tudo magicamente funciona, sem a necessidade de uma configuração extra no arquivo Web.config.

Foi a partir deste momento que nos perguntarmos porque não utilizar o próprio ASP.NET MVC? Com o ASP.NET você tem acesso a todo conjunto de recursos do HTTP, já que projetos Web tem afinidade com este protocolo. Além disso, a necessidade que os scripts tem em invocar um método C#, fez com que a Microsoft criasse um tipo de resultado chamado de JsonResult, qual retorna um valor “facilmente legível” para o Javascript.

Haviam certos overlaps entre o WCF Web API e o ASP.NET MVC, onde cada um deles determina uma forma específica de utilizar o mesmo protocolo, que é o HTTP. Então, para remover essa confusão, a Microsoft decidiu juntar essas duas tecnologias, e daí surgiu o ASP.NET Web API.

Com essa mesclagem alguns dos elementos que compunham o WCF Web API não existirão mais, justamente porque o ASP.NET MVC trata de outra forma. No ASP.NET Web API, agora vamos lidar com controllers e actions ao invés de uma classe decorada com o atributo ServiceContractAttribute e de métodos decorados com WebGetAttribute/WebInvokeAttribute. O roteamento do ASP.NET será utilizado para direcionar as requisições aos serviços. O model binding será o responsável por materializar o corpo da requisição em objetos complexos que, eventualmente, receberemos em nossos métodos. As actions filters serão utilizados ao invés de operation handlers, e ainda em tempo, se quisermos manipular complementamente a mensagem de requisição/resposta, continuamos tendo acesso às classes HttpRequestMessage e HttpResponseMessage.

Particularmente, eu gosto mais da ideia de ter um único framework que aborda os mais diferentes tipos de comunicação ao invés de atrelar isso especificamente a um tipo de projeto, mas também sou capaz de compreender a necessidade que a Microsoft tem de apartar isso, afinal, o WCF foi construído quando todos pensavam que o protocolo SOAP seria a solução para todo e qualquer tipo de comunicação existente, e o protocolo HTTP só seria mais um meio de transporte. Mas como percebemos ao longo do tempo, em certas ocasiões, ele é extremamente overkill. Mas é importante dizer que há funcionalidades que o SOAP possui que são bem interessantes, e se utilizadas da forma correta, podem trazer vários benefícios, mesmo em ambientes homogêneos. De qualquer forma, em posts futuros mostrarei como procedemos para construir serviços através desta nova tecnologia, que é o ASP.NET Web API.

O impacto do limitador de conexões HTTP

Internamente o .NET Framework possui uma classe chamada ServicePoint que controla as conexões HTTP que são realizadas. A sua criação é feita e gerenciada por uma outra classe, chamada de ServicePointManager, e ambas estão debaixo do namespace System.Net. A criação não se dá de forma desordenada, ou seja, ela é criada para atender um determinado recurso (página, serviço, imagem, etc.), e ao invés de desprezá-la, ela é armazenada e compartilhada para quando precisarmos, novamente, acessar aquele mesmo servidor.

Para falarmos de classes de mais alto nível, um exemplo é a classe HttpWebRequest que utilizamos para realizar requisições HTTP, que recorre internamente à classe ServicePointManager, e que por sua vez, faz todas verificações necessárias, e devolve um objeto ServicePoint pronto para ser utilizado. Como há uma única instância desta classe com aquele servidor, podemos ter a necessidade de realizar conexões simultâneas para ele. Por questões de performance, a especificação do protocolo HTTP determina que um cliente não deve manter mais do que duas conexões com um mesmo servidor.

Apesar desta sugestão, podemos ter a necessidade de aumentar esse valor para que possamos executar mais requisições concorrentes a um mesmo servidor. Pensando nisso, a Microsoft disponibiliza um configuração global, qual nos permite determinar a quantidade de conexões concorrentes que podemos realizar à um mesmo servidor. Para isso, há várias propriedades estáticas, que estão expostas a partir da classe ServicePointManager, e a propriedade que controla a quantidade de conexões é a DefaultConnectionLimit, onde o padrão é apenas 2 conexões, assim como sugere o HTTP/1.1.

Quando consumimos serviços WCF ou até mesmo serviços do tipo ASMX, não lidamos – diretamente – com as classes que vimos aqui, mas se analisarmos os bastidores das classes do WCF (ClientBase<TChannel>) e do ASMX (SoapHttpClientProtocol), veremos que eles, em algum momento, vai recorrer à classe HttpWebRequest e, consequentemente, estaremos sendo limitados caso haja a necessidade de realizar mais do que duas conexões concorrentes ao mesmo servidor.

Supondo que temos um serviço WCF e queremos consumí-lo em uma aplicação cliente, e para efeito dos testes, vamos criar 100 requisições concorrentes para o mesmo. Um pequeno detalhe, é que já definimos a quantidade mínima de threads para que o ThreadPool já as crie, nos antecipando e dizendo a ele quantas threads serão necessárias para executarmos o trabalho.

const int QtdeDeRequisicoes = 100;

ServicePointManager.DefaultConnectionLimit = 2;
ThreadPool.SetMinThreads(QtdeDeRequisicoes, QtdeDeRequisicoes);

var tasks = new Task[QtdeDeRequisicoes];
var sw = Stopwatch.StartNew();

for (int i = 0; i < QtdeDeRequisicoes; i++)
{
    tasks[i] =
        Task.Factory.StartNew<string>(o =>
        {
            Console.WriteLine(“Inicio:t” + o);

            using (var proxy = new ServiceReference1.ServiceClient())
                return proxy.GetData((int)o);
        }, i)
        .ContinueWith(t => Console.WriteLine(“Fim:t” + t.Result));
}

Task.WaitAll(tasks);
Console.WriteLine(sw.Elapsed);

Note que no código acima estamos explicitamente definindo que a aplicação cliente pode somente estabelecer duas conexões concorrentes com um mesmo servidor. Para o serviço de teste, ele levará, na minha máquina, cerca de 48 segundos. O gráfico abaixo ilustra a execução destas requisições. Enquanto a linha vermelha mostra a quantidade de requisições que chegaram até o serviço, a linha verde exibe a quantidade de requisições que estão sendo executadas por ele. Tudo isso sendo extraído do servidor onde o mesmo está hospedado.

Se mudarmos ligeiramente o código acima, definindo para 15 a propriedade DefaultConnectionLimit, o tempo para executar as mesmas 100 requisições cai para 20 segundos, ou seja, temos um ganho considerável. Novamente, através do gráfico abaixo temos as mesmas requisições em um tempo bem mais reduzido:

Observação: Apesar de facilitar a vida do cliente, esta configuração poderá comprometer o desempenho do serviço/servidor, pois estamos atendendo várias requisições que partem de um mesmo cliente, exacerbando o serviço com requisições que poderiam estar distribuídas entre outros interessados em consumir este mesmo serviço.

É importante mencionar que o cliente criado para consumir o serviço WCF de exemplo, é uma aplicação Windows (Console). Quando a aplicação cliente é uma aplicação Web (ASP.NET), também podemos ser influenciado por esta configuração, mas neste caso, ele está dimensionado de uma forma diferente, ou seja, em sua configuração padrão, no interior da classe HttpRuntime, ele define a propriedade DefaultConnectionLimit como 12 * quantidade de CPUs da máquina atual. Sendo assim, qualquer conexão HTTP que você realize através desta aplicação Web, você estará “limitado” à esta quantidade de conexões.

Finalmente, para efeito de testes, você não pode ter o cliente e o serviço na mesma máquina, pois a classe ServicePointManager avalia se o serviço está hospedado localmente, e se estiver, retorna a constante Int32.MaxValue (2147483647) como quantidade de conexões simultâneas, sendo um valor que dificilmente será atingido.

WCF Web API – Suporte à JSONP

Uma das grandes necessidades no consumo de serviços por parte das aplicações Web, é consumir serviços criados e que estão além da própria aplicação cliente, que provavelmente estará debaixo de um outro domínio, e por questões de segurança, isso não será permitido diretamente, já que se utilizado de forma maliciosa e sem o consentimento do usuário, pode por em risco as informações e a navegação dos usuários.

Para contornar essa “limitação”, então precisamos de alguma técnica para possibilitar que essa tarefa seja realizada. Uma opção seria a criação de um serviço nesta aplicação cliente, que serviria como um wrapper, e este por sua vez, consumiria diretamente o serviço, sem as imposições de chamada entre domínios que o navegador impõe. Com isso, o código JavaScript irá consumir este serviço local, que por sua vez, encaminharia a requisição para o serviço remoto, em outro domínio.

Apesar desta técnica funcionar, ela acaba sendo uma solução ruim, já que teremos que envolver outros elementos para realizar uma tarefa relativamente simples. Felizmente o jQuery fornece nativamente o suporte a uma técnica conhecida como JSONP (JSON with Padding).

O seu funcionamento não é muito complicado. Como disse acima, requisições entre domínios não são permitidas, mas há uma única exceção: a tag , ou seja, podemos definir no elemento src (source) a URL para um recurso que está além do nosso domínio, que o navegador não irá proibir o acesso. O que o JSONP faz é justamente o uso dela, criando dinamicamente esta tag, e definindo no atributo src a URL do serviço que estamos tentando acessar.

Na verdade isso não funciona sozinho, ou seja, precisa de uma certa colaboração por parte do serviço, para que o cliente possa processar o resultado da forma correta. Além dos parâmetros que são exigidos pelo método do serviço, o jQuery inclui um parâmetro chamado callback, que é o nome de uma função criada temporariamente no cliente. Aqui entra em cena a infraestrutura do serviço, que deve ser capaz de retornar o resultado (dados) envolvido nesta função, e quando o mesmo chegar ao cliente, ele invocará para capturar o resultado e encaminhá-lo para o nosso código, e assim iremos manipular da forma que acharmos mais conveniente. Falaremos da implementação por parte do serviço mais tarde.

Para fazer tudo isso funcionar, precisamos nos atentar à alguns detalhes do lado do cliente e do lado do serviço. Do lado do cliente, tudo o que precisamos fazer é indicar para a API de AJAX do jQuery que ela deve utilizar JSONP. Para isso, devemos recorrer ao atributo dataType, que indica o tipo de dado/formato que você está esperando que o servidor te retorne. No nosso caso, vamos apontar jsonp, assim como é mostrado no código abaixo:

    $(document).ready(function () {
        $.ajax(
        {
            type: ‘GET’,
            url: ‘http://ipv4.fiddler:1191/cotacoes&#8217;,
            dataType: ‘jsonp’,
            success: function (cotacoes) {
                var itens = [];

                $.each(cotacoes, function (indice, cotacao) {
                    itens.push(‘

  • ‘ + cotacao.Moeda + ‘: ‘ + cotacao.ValorEmReal + ‘
  • ‘);
                    });

                    $(‘

      ‘, { html: itens.join(”) }).appendTo($(‘#Cotacoes’));
              }
          });
      });

      </head>
      <body>
         

         

      </body>
      </html>

      Por parte do cliente, o jQuery fornece parâmetros para realizarmos a configuração via JSONP. Como podemos perceber no código acima, em negrito temos do tipo da requisição sendo definido como JSONP, o que faz com que a requisição seja formatada da seguinte forma (repare o que temos em negrito):

      GET http://127.0.0.1:1191/cotacoes?callback=jQuery15109440240194135102_1328569080908&_=1328569080915 HTTP/1.1
      Accept: application/javascript, */*;q=0.8
      Referer: http://ipv4.fiddler:1185/Index.htm
      Accept-Language: en-US,pt-BR;q=0.5
      User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
      Accept-Encoding: gzip, deflate
      Host: 127.0.0.1:1191
      Connection: Keep-Alive

      Como disse acima, é necessário que o serviço também de suporte à esta funcionalidade. A versão atual do WCF Web API, que está na 0.6, já traz esse recurso nativamente, e com poucas (talvez nenhuma) configurações, podemos construir e expor o serviço para que ele seja consumido através de um cliente que esteja hospedado em um outro domínio. Para o exemplo, temos um serviço “dummy” de cotação de câmbio, que possui os dados estáticos. Apenas como observação, não é mais necessário que o serviço seja decorado com o atributo ServiceContractAttribute.

      public class ServicoDeCotacoes
      {
          [WebGet]
          public IEnumerable<Cotacao> RecuperarCotacoes()
          {
              return new[]
              { 
                  new Cotacao() { Moeda = “Dólar Americano”, ValorEmReal = 1.7263M },
                  new Cotacao() { Moeda = “Euro”, ValorEmReal = 2.2653M },
                  new Cotacao() { Moeda = “Libra”, ValorEmReal = 2.7308M }
              };
          }
      }

      Finalmente, tudo o que precisamos fazer com o serviço é configurá-lo através da classe WebApiConfiguration, algo como já era realizado nas versões anteriores desta API. Abaixo temos um código simples, que ilustra como procedemos para realizar tal configuração:

      public class MvcApplication : System.Web.HttpApplication
      {
          protected void Application_Start()
          {
              ConfigurarServico();
          }

          private static void ConfigurarServico()
          {
              RouteTable.Routes.MapServiceRoute<ServicoDeCotacoes>(
                  “cotacoes”,
                  new WebApiConfiguration()
                  {
                      CreateInstance = (t, ic, msg) => new ServicoDeCotacoes()
                  });
          }
      }

      Ao executar a requisição para o serviço e interceptando-a, teremos na resposta da mesma, a função criada dinamicamente no cliente que será executada automaticamente pelo próprio jQuery. Mais uma vez, repare o que temos negritado abaixo. Note que o nome da função que foi criado pelo jQuery e repassado para o serviço, é devolvido para o mesmo.

      HTTP/1.1 200 OK
      Server: ASP.NET Development Server/10.0.0.0
      Date: Mon, 06 Feb 2012 22:58:00 GMT
      X-AspNet-Version: 4.0.30319
      jsonp-callback: jQuery15109440240194135102_1328569080908
      Content-Length: 170
      Cache-Control: private
      Content-Type: application/javascript; charset=utf-8
      Connection: Close

      jQuery15109440240194135102_1328569080908([{“Moeda”:”Dólar Americano”,”ValorEmReal”:1.7263},{“Moeda”:”Euro”,”ValorEmReal”:2.2653},{“Moeda”:”Libra”,”ValorEmReal”:2.7308}])

      Nenhuma configuração extra foi realizada por parte do serviço, porque a Microsoft entende que isso seja uma necessidade comum, o que faz com que já venha devidamente configurado. Internamente temos um operation response handler chamado JsonpHttpResponseHandler, que é responsável por avaliar se a requisição é ou não uma requisição do tipo JSONP, e para isso, verifica se há uma querystring chamada callback. Caso queira alterar o nome desta querystring, pode-se recorrer à propriedade CallbackQueryParameter deste próprio handler.

      Além disso, ainda temos um media type customizado, chamado de JsonpMediaTypeFormatter, que envolve o resultado gerado pelo serviço, pela função (callback) criada pelo jQuery, que entenderá isso como o resultado que será repassado para a função de sucesso, configurada na chamada do método $.ajax.

    WCF Web API Test Client

    Uma das ferramentas que a Microsoft criou para facilitar o teste de serviços WCF baseados em SOAP foi o WCF Test Client. Este utilitário permite consumir serviços simples através de alguns protocolos, sem a necessidade de ter que escrever uma aplicação cliente para apenas testá-lo.

    Já para testar serviços baseandos em REST, esse utilitário não ajuda. Podemos recorrer ao navegador. Mas ele também não vai ajudar. Não é possível testar métodos POST diretamente, ele não consegue interpretar o formato JSON, não é possível customizar headers, etc. Por conta de todas essas “limitações”, precisamos de uma ferramenta extra para nos auxiliar nos testes destes tipos de serviços. Isso nos leva a instalar uma aplicação de terceiros, como por exemplo, o Fiddler.

    Apesar do Fiddler ajudar imensamente, ainda é um pouco complicado, pois precisamos descobrir quais são as URIs e seus respectivos métodos HTTP que foram disponibilizados pelo serviço. Para facilitar os testes, a Microsoft incorporou na WCF Web API uma ferramenta, escrita em jQuery, para que possamos testar os serviços tão logo quando eles forem criados, já listando os endereços disponíveis e com uma interface acessível no navegador que conduz facilmente os testes. Esta ferramenta é chamada de WCF Web API Test Client.

    Por padrão, esse recurso está desabilitado. Para habilitá-lo precisamos customizar as configurações do serviço, utilizando a classe HttpConfiguration. Essa classe expõe uma propriedade boleana chamada EnableTestClient. O código abaixo ilustra como efetuar a configuração no arquivo Global.asax:

    RouteTable.Routes.MapServiceRoute<ServicoDeUsuarios>
        (“usuarios”, new HttpConfiguration() { EnableTestClient = true });

    Ao definir esta propriedade como True, podemos acrescentar o sufixo “/test” na endereço do serviço, e a interface qual foi mencionada acima é exibida no navegador, e dali em diante, podemos utilizá-la para efetuar os testes. As imagens abaixo exibem alguns dos testes que foram capturados em um exemplo simples, que posta informações e também captura os dados que foram inseridos.

     

     

    Recursos da Palestra do TechEd Brasil 2011

    Ontem eu fiz uma palestra no TechEd Brasil 2011, e o principal assunto abordado lá foi a nova API que a Microsoft está criando para facilitar a construção, hospedagem e consumo de serviços WCF baseados em REST.

    O exemplo principal foi concetrado um projeto que nomeie de Techitter, que é composto por algumas aplicações simulando – de muito longe – o Twitter. A solução é composta por 4 projetos, onde um é o serviço, e onde concentra-se grande parte das novidades, um site em ASP.NET MVC que via jQuery posta e carrega as mensagens; outro projeto que consome a mesma API como um widget e, finalmente, uma aplicação WPF que também faz uso do serviço, consumindo o mesmo serviço via HttpClient, que também compõe a nova API. Para incrementar, existe o consumo de um serviço criado em outra tecnologia (NodeJs.exe), que foi consumido pelo serviço.

    Gostaria de agradecer a todos os presentes, e também ao Rogerio Cordeiro pela oportunidade. Para aqueles interessados, o download do projeto pode ser baixado clicando aqui.

    Caching em Serviços REST

    Uma das principais técnicas que são utilizadas na Web em busca de performance, é a utilização de técnicas de caching. Com elas, podemos armazenar em algum local uma cópia da página (HTML), arquivo, imagem, etc., que estamos acessando, para quando precisarmos novamente daquele recurso (URL) mais tarde, sermos atendidos de uma forma muito mais rápida.

    A redução da latência e a diminuição do tráfego na rede são dois detalhes que alguma estratégia de caching pode ajudar a melhorar. O controle do caching pode estar definido do lado do servidor ou diretamente no cliente que consome o recurso. Sendo assim, ao acessar um recurso que já foi acessado recentemente, o usuário será servido quase que instantaneamente com o – mesmo – resultado.

    As estratégias de caching são parte da especificação do protocolo HTTP, que como sabemos, foi desenhado para ser utilizado para acessar informações de sistemas distribuídos. A ideia principal do caching do HTTP, é tentar eliminar, quando possível, a necessidade de fazer novas requisições para um mesmo recurso, ou quando a requisição é necessária, tentar diminuir a quantidade de dados devolvidos.

    Na verdade, dois detalhes importantes são definidos na especificação do protocolo, onde a estratégia de caching deve/pode controlar, a saber: expiração e validação. A expiração consiste em verificar se o recurso que está sendo solicitado já está em cache e continua sendo válido (ainda não expirado). Já a validação verifica se o recurso que está sendo re-solicitado ao servidor, sofreu ou não mudanças desde a última requisição, e caso não tenha, nada será retornado, afinal já temos a versão mais atualizada, e isso reduz a quantidade de informações – desnecessárias – sendo trafegadas.

    Serviços REST, por estarem fortemente ligados ao protocolo HTTP, podem também fazer uso do caching oferecido pelo protocolo. A ideia deste artigo é demonstrar as opções que temos para configurar e, consequentemente, fazer uso de todos os benefícios oferecidos pelo caching. Para o exemplo, teremos um serviço que gerencia produtos, e haverá um único método que dado um identificador, retorna a instância do produto correspondente. Abaixo temos o código do serviço que utilizaremos pelos exemplos:

    [ServiceContract]
    [
        AspNetCompatibilityRequirements
        (
            RequirementsMode = AspNetCompatibilityRequirementsMode.Required
        )
    ]
    public class Servico
    {
        [WebGet(UriTemplate = “produtos/{produtoId}”)]
        public Produto RecuperarProduto(string produtoId)
        {
            var produto =
                (
                    from p in produtos
                    where p.Id == Convert.ToInt32(produtoId)
                    select p
                ).SingleOrDefault();

            return produto;
        }
    }

    Vou omitir a configuração do serviço aqui, mas neste primeiro momento estaremos utilizando a infraestrutura fornecida pelo WCF para a construção de serviços baseado em REST, que está disponível desde a versão 3.5 do .NET Framework (WCF Web Http). Ao subir este serviço, ele estará acessível e toda e qualquer requisição realizada pelo navegador chegará até o ele.

    Todo o controle do caching do HTTP é realizado através de headers que foram criados e são assegurados pelo navegador e pelo servidor, para controlar o caching criado. Os serviços WCF fornecem alguns recursos que nos permitem acessar de forma mais simples estes headers, manipulando-os de acordo com a nossa necessidade. Os headers são divididos em cartegorias para manipular a expiração e a validação, e inicialmente vamos analisar aqueles que são utilizados para determinar a expiração de um recurso.

    Expiração

    O HTTP 1.1 introduziu um novo header, que é responsável por controlar a expiração. Este header é o Cache-Control, que pode receber vários valores que combinados, instruem o cliente a como efetuar e controlar o caching do recurso que está sendo devolvido. Um dos valores que podemos definir no Cache-Control é private, que determina que aquele conteúdo é exclusivo à um usuário (navegador), e pode eventualmente ser cacheado por ele. Podemos combiná-lo com outro valor que é o max-age, que define um número inteiro, que determina quantos segundos depois da requisição o conteúdo deverá ser mantido no cache.

    Sendo assim, podemos recorrer ao contexto da requisição atual (WebOperationContext) dentro do método que está sendo disparado, e lá incluir o header que mencionamos acima. Temos que acessar a coleção de headers a partir da propriedade OutgoingResponse, que permite acessar as informações pertinentes à resposta.

    WebOperationContext.Current.OutgoingResponse.Headers.Add(“Cache-Control”, “private, max-age=30”);

    Já quando não quiser que o cliente efetue o cache do recurso, podemos recorrer ao mesmo código acima para explicitamente determinar isso, determinando o valor do header Cache-Control como no-cache. O código abaixo exibe esta configuração:

    WebOperationContext.Current.OutgoingResponse.Headers.Add(“Cache-Control”, “no-cache”);

    Note que para configurarmos o header Cache-Control, utilizamos uma classe pertinente ao WCF, que independe do host que estamos utilizando para hospedar o serviço. Quando utilizamos o IIS e, consequentemente, a infraestrutura do ASP.NET, podemos fazer uso de um recurso que já existe há algum tempo, que é o OutputCache.

    A configuração do caching é através de cache profiles, que é um recurso onde você define todas as características do caching no arquivo de configuração (Web.config), e vincula essa configuração através do atributo AspNetCacheProfileAttribute. Abaixo temos o arquivo de configuração do serviço, e podemos notar a configuração do caching. A primeira configuração importante é habilitar o modelo de compatibilidade com o ASP.NET, e fazemos isso através do atributo aspNetCompatibilityEnabled do elemento serviceHostingEnvironment, definindo-o como True.

    Em seguida, habilitamos o OutputCache definindo o atributo enableOutputCache como True. Logo após, temos um profile criado, que agrupa o conjunto de configurações de cache e o nomeia. Repare que estamos definindo o local do cache como “Server”, o que determina que uma vez atendida a requisição para um determinado recurso, o cache será armazenado no servidor, e qualquer requisição subsequente, partindo ou não do mesmo cliente, será devolvida do cache criado, respeitando a duração de 60 segundos, ali também configurada. Isso fará com que qualquer complexidade que temos na execução daquele recurso, o preço será pago apenas uma única vez.

    <configuration>
      <system.web>
        <caching>
          <outputCache enableOutputCache=”true” />
          <outputCacheSettings>
            <outputCacheProfiles>
              <add name=”CachingNoServidor”
                   location=”Server”
                   duration=”60″
                   varyByParam=”none”/>
            </outputCacheProfiles>
          </outputCacheSettings>
        </caching>
      </system.web>
      <system.serviceModel>
        <serviceHostingEnvironment aspNetCompatibilityEnabled=”true”/>
        <services>
          <service name=”ViaWcfWebHttp.Servico”>
            <endpoint address=””
                      binding=”webHttpBinding”
                      contract=”ViaWcfWebHttp.Servico”/>
          </service>
        </services>
      </system.serviceModel>
    </configuration>

    Como disse anteriormente, a amarração da configuração com o método do serviço é realizada através do atributo AspNetCacheProfileAttribute, que recebe em seu construtor uma string que representa o nome do profile que você quer aplicar para ele. Abaixo temos o serviço que foi ligeiramente modificado, decorado com o respectivo atributo:

    [AspNetCacheProfile(“CachingNoServidor”)]
    [WebGet(UriTemplate = “produtos/{produtoId}”)]
    public Produto RecuperarProduto(string produtoId) { }

    Como esse caching refere-se ao servidor, os clientes nada sabem sobre ele. Inclusive na resposta ao cliente, por padrão, ele define o header Cache-Control como no-cache. Como já era de se esperar, podemos criar um novo profile, e lá definirmos o local do cache no cliente. Isso fará com que ao acessar o serviço, o cliente receberá o header Cache-Control definido como private e o atributo max-age definido como 60 (segundos), fazendo com que o navegador faça o caching do recurso. Abaixo temos o trecho do arquivo de configuração que exibe a adição deste profile de caching para o cliente:

    <outputCacheSettings>
       <outputCacheProfiles>
          <add name=”CachingNoCliente”
               location=”Client”
               duration=”60″
               varyByParam=”none”/>
       </outputCacheProfiles>
    </outputCacheSettings>

    Validação

    Acima vimos as opções que temos para controlarmos a expiração. Notamos que a expiração controla o período em que o recurso ficará disponível no caching do cliente (ou do servidor). Isso faz com que alguns recursos não sejam requisitados a todo momento, diminuindo a quantidade de informações que trafegam entre as partes. Só que dependendo do conteúdo que está sendo armazenado no cache, nem sempre podemos confiar cegamente no conteúdo que está salvo do lado do cliente.

    Em certos cenários, o custo do round-trip é ignorado, em busca dos dados mais recentes possíveis, onde o prejuízo de visualizar uma informação defasada é muito maior. Só que as vezes, vamos até o servidor em busca dessa nova informação, e ela ainda não foi alterada, retornando para o cliente o mesmo conteúdo, atualizando a informação que temos localmente com exatamente, a mesma informação, ou seja, trafegamos uma informação que já tínhamos do lado do cliente. Para otimizar isso, temos uma técnica que chamamos de “GET condicional”.

    Essa técnica faz uso de entity tags (ETags), que consiste na adição de um header que é adicionado na resposta à uma requisição, que caracteriza a “versão” do conteúdo que foi devolvido ao cliente. Ao receber esse conteúdo e encaminhar esta tag nas requisições subsequentes, o serviço deverá ser capaz de identificar se houve ou não mudanças no objeto; caso exista, o serviço irá retornar a versão mais recente, do contrário, retornará o status 304 do HTTP, que indica que o recurso não teve mudanças, sem qualquer conteúdo na resposta, poupando assim que informações desnecessárias sejam enviadas ao cliente, que por sua vez, já possue a versão mais atual.

    A implementação consiste em duas partes, sendo a primeira onde devemos nos preocupar em passar ao cliente as informações que caracterizam a “versão” do conteúdo, e a segunda parte, onde devemos criar dentro do serviço, a lógica para determinar se a versão que o cliente possui já é ou não a mais recente.

    Para nosso exemplo, vamos incrementar a classe Produto com uma propriedade do tipo Guid chamada Versao, que define a versão do mesmo. Qualquer alteração que ocorra em qualquer uma das propriedades do produto, deverá atualizar o GUID. Já que essa propriedade irá caracterizar o versionamento, devemos apontar na resposta para o cliente o seu valor para que ele possa encaminhar ao mesmo através do header ETag. E para isso, vamos novamente recorrer a classe WebOperationContext, acessando a resposta que será enviada ao cliente e, finalmente, teremos o método SetETag, que como o próprio nome diz, permite definirmos a tag:

    [WebGet(UriTemplate = “produtos/{produtoId}”)]
    public Produto RecuperarProduto(string produtoId)
    {
        var produto =
            (
                from p in produtos
                where p.Id == Convert.ToInt32(produtoId)
                select p
            ).SingleOrDefault();

        WebOperationContext.Current.OutgoingResponse.SetETag(produto.Versao);
        return produto;
    }

    Ao utilizar uma ferramenta para monitorar o tráfego HTTP, podemos visualizar o resultado da requisição para o serviço acima. Note a presença do header ETag definido com o GUID gerado para nosso objeto:

    HTTP/1.1 200 OK
    Server: ASP.NET Development Server/10.0.0.0
    Date: Sun, 28 Aug 2011 20:26:53 GMT
    X-AspNet-Version: 4.0.30319
    Content-Length: 202
    ETag: “8e548670-8b75-4187-aedc-8182f46c3216”
    Cache-Control: private
    Content-Type: application/xml; charset=utf-8
    Connection: Close

    <Produto xmlns=”http://schemas.datacontract.org/2004/07/ViaWcfWebHttp&#8221; xmlns:i=”http://www.w3.org/2001/XMLSchema-instance”><Descricao>Mouse Microsoft</Descricao><Id>1</Id><Valor>120.00</Valor></Produto>

    Uma vez que o cliente recepciona essa requisição, as requisições subsequentes repassam o valor do header ETag para o serviço através de um outro header, chamado de If-None-Match, onde o serviço deverá averiguar se o produto foi alterado nesta janela de tempo, para determinar se o conteúdo do cliente deve ou não ser atualizado. Abaixo temos a requisição sendo realizada ao serviço depois de receber a ETag:

    GET http://localhost:3911/Servico.svc/produtos/1 HTTP/1.1
    Accept: text/html, application/xhtml+xml, */*
    Accept-Language: en-US,pt-BR;q=0.5
    User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
    Accept-Encoding: gzip, deflate
    Host: localhost:3911
    If-None-Match: “8e548670-8b75-4187-aedc-8182f46c3216”
    Connection: Keep-Alive

    Para efetuar essa validação do lado do serviço, há um método chamado CheckConditionalRetrieve, que está disponível a partir da propriedade IncomingRequest da classe WebOperationContext. Esse método recebe como parâmetro a ETag do produto. Se o produto não foi modificado, então a tag da requisição será a mesma, o que faz com que o método, internamente, aborte a requisição, devolvendo ao cliente o resultado 304 do HTTP, que caracteriza que nada foi mudado (NotModified). O código a seguir exibe a utilização deste método, e logo na sequência, temos a imagem que ilustra esse procedimento:

    [WebGet(UriTemplate = “produtos/{produtoId}”)]
    public Produto RecuperarProduto(string produtoId)
    {
        var produto =
            (
                from p int produtos
                where p.Id == Convert.ToInt32(produtoId)
                select p
            ).SingleOrDefault();

        WebOperationContext.Current.IncomingRequest.CheckConditionalRetrieve(produto.Versao);
        WebOperationContext.Current.OutgoingResponse.SetETag(produto.Versao);

        return produto;
    }

    WCF Web API

    Como já comentei aqui, a Microsoft trabalha em um novo projeto chamado WCF Web API, que torna o desenvolvimento e consumo de serviços REST mais simples. Estes tipos de serviços também podem tirar proveito dos recursos de caching fornecidos pelo HTTP que vimos neste artigo.

    Ao utilizar os objetos que representam as mensagens de requisição e resposta diretamente, você encontrá propriedades que configuram o caching no cliente. Você também pode optar por utilizar um message handler, para separar o que corresponde ao negócio do que compete a parte de infraestrutura.

    Coletando e analisando arquivos de Dump

    Ao instalar uma aplicação em seu local de funcionamento, começa uma nova etapa, que é o monitoramento da mesma, que permite diagnosticar eventuais falhas e tentar trabalhar sempre de uma forma preventiva. Só que muitas vezes, estes problemas podem acontecer durante a execução, problemas estes que podem ser por falta de testes que atendiam aquelas condições, ou ainda, referente à algum problema de infraestrutura.

    Se você toma o devido cuidado de catalogar as exceções que estão sendo disparadas, você pode recorrer aos arquivos onde elas estão armazenadas e inspecionar o que aconteceu e, consequentemente, encontrar a região do código responsável por aquele problema, e resolvê-lo, para em seguida, distribuir a correção para ele. Só que para detectar o problema, geralmente precisamos muito mais do que simplesmente o tipo da exceção que foi disparada, mas também quais foram os parâmetros informados, os valores que as variáveis estavam definidas naquele momento, e assim por diante.

    Quando estamos em ambiente de desenvolvimento, podemos recorrer ao debugger do Visual Studio para executar a aplicação passo à passo, parando nos pontos que são importantes e naqueles que podem estar ocasionando o problema, e atenciosamente analisar e detectar o problema. Só que se essa aplicação já estiver em funcionamento, isso não é possível, pelo menos não de uma forma simples. Neste caso podemos recorrer a criação de um arquivo de dump da aplicação em questão. Ao gerar este arquivo, ele “fotografa” o estado atual do processo e gera várias informações para que possamos depurá-la mais tarde, algo mais ou menos parecido com o reporte de bugs do Windows.

    Esse recurso é algo que podemos utilizar tanto em aplicações cliente como aquelas que rodam em um servidor, como é o caso de aplicações ASP.NET ou de serviços WCF. No caso de aplicações cliente, você pode recorrer ao Doctor Watson do Windows ou indo diretamente através da Task Manager. Como eu quero demonstrar a coleta do dump de um serviço WCF, vamos recorrer à segunda opção. Como sabemos, ao hospedar um serviço WCF no IIS, quem será responsável por executá-lo é um processo, chamado de w3wp.exe, que pode ser configurado através da opção Application Pools. Abaixo temos a imagem que ilustra como extrair o dump do processo do IIS:

    Basicamente, este serviço recebe uma requisição e gera uma massa de informações para o respectivo cliente. Depois do arquivo de dump criado (extensão *.dmp), você receberá uma notificação informando onde ele foi salvo. Tudo o que precisamos fazer agora, é abrir o arquivo no Visual Studio 2010. A partir desta versão, o Visual Studio é capaz de interpretar esses arquivos. Ao abrí-lo, você irá se deparar com uma página, que detalha as informações sobre o processo. Podemos visualizar o nome do processo de onde o dump foi extraído, versão do sistema operacional, da CLR, etc. Outro ponto importante são os módulos que foram carregados à este processo, que aqui, por questões de espaço, não estão sendo exibidos todos eles. A imagem abaixo ilustra este resumo:

    Como este arquivo contém o estado da aplicação naquele momento, o Visual Studio nos permite analisar o estado das informações (variáveis, parâmetros, etc.) que tínhamos, de uma forma tão simples quanto depurar a aplicação. Só que para isso funcionar, é necessário definirmos os símbolos, que são responsáveis por armazenarem informações para guiar o debugger até o código fonte. A opção “Set symbol paths” nos permite definir o endereço até o arquivo *.pdb, gerado durante o desenvolvimento do serviço.

    Depois disso definido, podemos clicar na opção “Debug with Mixed”, e o debugger do Visual Studio entra em ação. Ele lerá as informações contidas no arquivo de dump e irá exibí-las através das ferramentas de depuração que o próprio Visual Studio já nos fornece. A imagem que veremos a seguir já é uma dessas ferramentas: a janela Parallel Stacks. Essa janela é útil para depurarmos aplicações multi-thread, como é o caso de serviços WCF. Como podemos visualizar, temos a stack da execução e dentro dela, a chamada para o método Executar, que faz parte do serviço criado para o teste.

    Ao clicar com o botão direito em um dos itens, podemos alternar entre as threads que estavam em execução naquele momento, acessando a operação Executar. Note que entre parênteses há o valor do parâmetro que está sendo passado para a operação. Abaixo temos a imagem que ilustra as três threads que temos em execução:

    Finalmente, ao selecionar uma das opções listadas na imagem acima, somos encaminhados para o código correspondente, conseguindo visualizar o estado das informações, simplesmente passando o mouse por cima das mesmas. Além disso, você ainda pode recorrer as janelas de depuração que já existem há algum tempo no Visual Studio, como é caso das janelas de Threads, Modules e Locals, que trazem informações pertinentes aquele código que está sendo depurado no momento. A imagem abaixo exibe o estado das variáveis e parâmetros da operação Executar no momento em que o arquivo de dump foi gerado:

    Utilizando o utilitário netstat

    Quando hospedamos mais que um serviço em uma mesma máquina, pode ser difícil gerenciar, e de uma forma simples, visualizar o que está ativo e aceitando requisições. Se não temos o luxo de utilizar algum sistema de gerenciamento mais eficiente, como é o caso do AppFabric, podemos recorrer à um utilitário de linha de comando que existe no sistema operacional chamado netstat.

    Este popular utilitário exibe uma lista com as conexões de rede estabelecidas no computador onde o mesmo está sendo executado. Se tivermos serviços WCF hospedados em uma determinada máquina, é possível visualizá-las através deste utilitário, e no mínimo, enxergar em qual porta eles encontram, se ela (porta) está aberta ou não e seu status. Abaixo temos um código de teste, que cria e abre vários hosts dentro de uma aplicação Console.

    static void Main(string[] args)
    {
        ServiceHost[] hosts = new ServiceHost[10];

        for (int i = 0; i < 10; i++)
        {
            var host = 
                new ServiceHost(typeof(Servico), 
                    new Uri(string.Format(“http://localhost:987{0}”, i)));

            host.AddServiceEndpoint(typeof(IContrato), new BasicHttpBinding(), “srv”);
            host.Open();
            hosts[i] = host;
        }

        Console.ReadLine();
    }

    Ao rodar esta aplicação, dez hosts são criados e abertos. Ao executar o utilitário netstat, essas conexões já são listadas, assim como podemos perceber na imagem abaixo:

    Expondo Tipos POCO através do WCF

    Ao construir serviços WCF, podemos expor tipos que vão além dos tipos tradicionais (tais como strings, inteiros, etc.), ou seja, podemos recorrer a construção de tipos customizados, onde construimos classes com suas propriedades que determinam os dados que serão carregados entre o cliente e o serviço.

    Algumas vezes essas classes são construídas com o intuito de atender a requisição e/ou resposta das operações de um determinado serviço, mas que internamente, são consultas que fazemos no banco de dados e estamos retornando ao cliente, ou ainda, são comandos que devemos executar, também no banco de dados, para persitir alguma informação.

    Se optarmos pelo uso do Entity Framework, podemos utilizar o modelo de geração POCO, onde as classes geradas são consideradas “puras”, ou seja, não dependem de nenhuma classe do framework de persistência. Isso tornam as classes simples, apenas com as propriedades que são, em princípio, mapeadas para colunas da base de dados. Sendo assim, muitos podem optar pela exposição direta destas classes no contrato de um serviço WCF, evitando assim a criação de outras classes (DTOs) para efetuar o transporte das informações.

    Mas expor diretamente essas classes podem acarretar alguns problemas. A questão é que entidades que foram geradas utilizando o modelo POCO, possuem um comportamento durante a execução diferente das entidades que são geradas pelo modelo padrão do Entity Framework. Quando utilizamos o modelo padrão, as entidades herdam diretamente da classe EntityObject, que fornece toda a infraestrutura necessária para efetuar o rastreamento das mudanças e dá também o suporte ao lazy-loading. Quando utilizamos classes POCO, esses recursos continuam sendo oferecidos, mas são implementados de forma diferente.

    Neste caso, o Entity Framework gera proxies dinâmicos para interceptar os acessos às propriedades das entidades que estão sendo manipuladas, e com isso, todos os recursos acima, continuam ainda sendo suportados. Abaixo temos o objeto Type da classe que foi gerada dinamicamente.

    {System.Data.Entity.DynamicProxies.Cliente_B38C1C71074F1A0CDCF11548021F55AF4BAC2116057847A45ACD8E600D02BB90}

    Só que ao expor esse tipo de objeto diretamente através do WCF, vamos nos deparar com uma exceção durante a execução. Isso se deve ao fato de que o WCF não é capaz serializar/deseralizar tipos que não são conhecidos pelo mesmo. Ao construir o contrato para um serviço WCF, você pode mencionar os tipos das classes geradas efetivamente pelo EDMX, mas durante a execução, o tipo acima será criado e, consequentemente, será entregue para a infraestrutura do WCF, ele irá se certificar de que o tipo é conhecido no contrato, e como não é, a exceção será disparada.

    Há algumas alternativas para evitar esse problema. A primeira delas é desabilitar a criação do proxy dinâmico através da propriedade boleana ProxyCreationEnabled, que está acessível através do contexto do Entity Framework, assim como é exibido no código abaixo. O problema é que ao fazer isso, entidades criadas no padrão POCO não serão capazes de fornecer as funcionalidades de rastreamento de mudanças e lazy-loading.

    public class Servico : IContrato
    {
        public Cliente Recuperar(int id)
        {
            using (DBTestesEntities1 ctx = new DBTestesEntities1())
            {
                ctx.ContextOptions.ProxyCreationEnabled = false;

                return (from c in ctx.Cliente where c.ClienteId == id select c).Single();
            }
        }
    }

    A outra opção é a criação de um behavior que pode ser aplicado em nível de operação, alterando o serializador padrão do WCF, que é o DataContractSerializer, para o serializador ProxyDataContractResolver. Este serializador, que está debaixo do namespace System.Data.Objects, ajuda na resolução dos tipos que são criados dinamicamente pelo Entity Framework em “tipos concretos”, recorrendo ao método estático GetObjectType, exposto através da classe ObjectContext, que dado o Type do proxy dinâmico, ele retorna o tipo correspondente POCO, informando ao WCF que Type correto para que ele possa ser capaz de serializá-lo. Abaixo temos um exemplo da implementação e aplicação deste behavior:

    public class ProxyDataResolverAttribute : Attribute, IOperationBehavior
    {
        public void ApplyDispatchBehavior(OperationDescription opDescription, DispatchOperation dop)
        {
            opDescription
                .Behaviors
                .Find<DataContractSerializerOperationBehavior>()
                .DataContractResolver = new ProxyDataContractResolver();
        }

        //outros métodos
    }

    [ServiceContract]
    public interface IContrato
    {
        [OperationContract]
        [ProxyDataResolver]
        Cliente Recuperar(int id);
    }

    E, finalmente, uma terceira opção, seria a utilização de DTOs (Data Transfer Objects), onde você pode definir os objetos que quer trafegar entre as partes, sem a necessidade de se preocupar com detalhes de uma tecnologia específica que esteja utilizando nos bastidores e, principalmente, de ter a possibilidade de desacoplar complementamente o que representa os seus dados/domínio daquilo que quer expor para os clientes/parceiros.

    WCF Web API – API Key Verification

    Quando criamos algum tipo de serviço, em princípio nos concentramos nas funcionalidades e informações que ele irá expor aos consumidores. Depois disso, nos preocuparemos em analisar o contexto de segurança, verificando o tipo de autenticação e nível de autorização que são necessários para o serviço funcionar de forma segura.

    O detalhe é que muitas vezes não queremos envolver qualquer mecanismo de autenticação e autorização no serviço, já que ele poderá ser acessado de forma pública, sem qualquer necessidade do consumidor efetivamente se cadastrar, gerar um login e senha e, finalmente, acessar o respectivo serviço, apresentando à ele essas informações. Mas apesar do cliente não se identificar com um login e senha, não quer dizer que nosso serviço não precise ser “protegido” de alguma outra forma.

    A questão é que permitindo o acesso irrestrito total, permite com que bons usuários o acessem da forma legal, e também permite com que outros usuários, estes mal intencionados, disparem uma infinidade de requisições contra o serviço, e se este, por sua vez, pode estar consumindo recursos caros, com por exemplo, acessando uma base de dados, em pouco tempo nosso servidor estará esgotado, não conseguindo atender nem mesmo aqueles que usam o serviço da forma correta.

    Uma técnica chamada API Key Verification foi criada com o intuito de evitar esse tipo de problema. Com uma implementação simples, criamos e mantemos uma lista de chaves (podendo ser strings, inteiros, Guids, etc.) que estão habilitadas à acessarem o serviço. Os consumidores podem receber esta chave de alguma forma (out-of-band ou não), como por exemplo, fazendo um cadastro no site da empresa demonstrando o interesse; mais tarde, ele receberá um e-mail contendo a chave que foi criada exclusivamente para o mesmo, e que deverá ser utilizada quando efetuar uma requisição para o serviço, embutindo-a na coleção de headers ou querystrings, de acordo com o que você determinar. Ao chegar a requisição no serviço, você detecta a presença desta informação, e se a chave não fizer parte da requisição ou for uma chave inválida, deveremos rejeitar a mesma.

    A ideia deste artigo é mostrar como podemos implementar esta validação utilizando a nova API do WCF, chamada WCF Web API. Para isso, vamos recorrer à um recurso exposto por ela, chamado de Message Handlers. Esses handlers são acoplados ao runtime, e são executados durante os primeiros estágios da requisição, antes mesmo do serviço ser efetivamente executado. Para maiores detalhes sobre os Message Handlers, consulte este artigo. Abaixo temos a implementação deste handler que validará a chave que o consumidor está nos encaminhando:

    public class ApiKeyVerificationMessageHandler : DelegatingChannel
    {
        private readonly IRepositorioDeChaves repositorioDeChaves;
        private const string API_KEY = “apiKey”;

        public ApiKeyVerificationMessageHandler(HttpMessageChannel inner, IRepositorioDeChaves repositorio)
            : base(inner)
        {
            this.repositorioDeChaves = repositorio;
        }

        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellation)
        {
            var queryStrings = HttpUtility.ParseQueryString(request.RequestUri.Query);
            var chave = Guid.Empty;

            if (Guid.TryParse(queryStrings[API_KEY], out chave) && repositorioDeChaves.VerificarSeExiste(chave))
                return base.SendAsync(request, cancellation);

            return Task.Factory.StartNew(() => new HttpResponseMessage(HttpStatusCode.Unauthorized, “A chave fornecida é inválida.”));
        }
    }

    Analisando a classe acima, podemos perceber que no construtor recebemos a instância de alguma classe que implemente a interface IRepositorioDeChaves. Utilizamos a interface aqui, justamente para tornar o nosso handler independente do local onde desejamos armazenar as chaves. Para efeito de testes, optei por criar uma implementação em memória e que ocultarei aqui por questões de espaço, mas você poderá recorrer a qualquer outro meio, como XML, SQL, etc. Em seguida, sobrescrevemos o método SendAsync (exposto pela classe DelegatingChannel), onde detectamos se existe ou não uma query string chamada apiKey, e se houver, fazemos o parser da mesma através do Guid, que é o tipo de dado que estamos utilizando para determinar o tipo das chaves que dão acesso ao serviço. Não existindo a chave na query string ou ela sendo inválida, retornamos uma mensagem informando o status como 401, que indica que a requisição não foi autorizada à acessar o serviço.

    Depois disso, precisamos acoplar esse handler à execução, e para isso, utilizamos o evento ApplicationStart do arquivo Global.asax, onde vamos criar a factory responsável pela criação do handler. Essa factory será responsável por instanciar a classe ApiKeyVerificationMessageHandler que criamos acima, passando o repositório de chaves em memória que também criamos e configuramos dentro deste evento. Note que estou utilizando uma sobrecarga do método SetMessageHandlerFactory, que me permite passar um delegate contendo o código de construção do objeto, mas se quiser algo mais rebuscado, poderia construir uma factory herdando da classe HttpMessageHandlerFactory.

    protected void Application_Start(object sender, EventArgs e)
    {
        RepositorioDeGuidsEmMemoria repositorio = new RepositorioDeGuidsEmMemoria();
        repositorio.Adicionar(new Guid(“d4907f3c-52c7-457e-9c18-e5abf9be77fe”));
        repositorio.Adicionar(new Guid(“adc5c096-fdc3-4c57-a887-ba4a368f299f”));

        var config =
            HttpHostConfiguration
                .Create()
                .SetMessageHandlerFactory(inner => new ApiKeyVerificationMessageHandler(inner, repositorio));

        RouteTable.Routes.MapServiceRoute<ServicoDeTeste>(“teste”, config);
    }

    Depois dessas customizações, podemos utilizar o Fiddler para efetuar e capturar as requisições para o serviço. Para exemplificar, a primeira requisição informa um elemento chamado apiKey na coleção de query strings. Isso fará com que o serviço entregue a resposta da forma correta. Já na segunda requisição, omitimos a chave, fazendo com que o a resposta seja definida como 401, como também podemos perceber abaixo:

    — Primeira Requisição
    GET http://localhost:1830/teste/ping?apiKey=d4907f3c-52c7-457e-9c18-e5abf9be77fe&value=sss HTTP/1.1
    User-Agent: Fiddler
    Host: localhost:1830

    — Resposta
    HTTP/1.1 200 OK
    Content-Length: 63
    Content-Type: application/xml; charset=utf-8

    <?xml version=”1.0″ encoding=”utf-8″?><string>sss ping</string>

    — Segunda Requisição
    GET http://localhost:1830/teste/ping?value=sss HTTP/1.1
    User-Agent: Fiddler
    Host: localhost:1830

    — Resposta
    HTTP/1.1 401 Unauthorized
    Content-Length: 0
    Connection: Close

    Além do que foi apresentado aqui, você ainda poderia criar políticas para renovação e revogação de chaves, e além disso, permitir com que o consumidor mande a chave na coleção de query strings ou de headers, podendo o handler ser inteligente o bastante para ser capaz de detectar em ambos os locais, e caso não encontrado, rejeitaria do mesmo jeito.