Autenticação com WCF e jQuery

Recentemente escrevi sobre o consumo de serviços WCF a partir do jQuery. Naquele artigo foi comentado como construir serviços WCF para ser acessados através do ambiente REST, e além disso, vimos também como proceder para o consumo deste serviço utilizando o jQuery como cliente.

Mas um detalhe que não foi abordado no artigo foi a questão da segurança, ou melhor, do processo de autenticação do cliente que consome o serviço. Por exemplo, imagine que temos um serviço que exige que o usuário se identifique, para que assim possamos determinar se ele terá ou não acesso ao serviço. Apesar do WCF fornecer várias alternativas para isso, quando estamos em um ambiente REST, alguns cuidados especiais são necessários, quais serão abordados no decorrer deste artigo.

O primeiro detalhe para nos atentarmos é como vamos configurar o serviço para que o mesmo possa exigir as credenciais. Para expor um serviço para ser consumido através do ambiente REST, utilizamos um binding exclusivo chamado de WebHttpBinding. Em sua configuração padrão, não há nenhum tipo de autenticação configurada, mas como qualquer binding, podemos recorrer à opção security para isso.

Temos apenas três opções relacionadas à segurança para este binding: None, Transport e TransportCredentialOnly. A primeira opção desabilita qualquer tipo de proteção e autenticação no respectivo serviço. Já a segunda opção, Transport, determina que será o protocolo que deverá garantir a segurança da mensagem (HTTPS) e, finalmente, o TransportCredentialOnly, que não fornecerá integridade e confidencialidade na mensagem que está sendo trafegada, e utilizará apenas o protocolo HTTP exclusivamente para autenticação do usuário.

Depois desta configuração que determina como a comunicação deverá ser protegida, temos uma espécie de “sub-configuração” dela que precisamos nos atentar. Esta sub-configuração determina como as credenciais serão passadas para o serviço. Entre as várias formas, temos o HTTP Basic, que faz com que as credenciais viagem do cliente para o serviço sem qualquer espécie de criptografia. Esse modelo, em sua configuração padrão, tem uma forte afinidade com o Windows/Active Directory, ou seja, para utilizar esse recurso, as credenciais informadas do lado do cliente deverão refletir uma conta válida no Windows/Active Directory, algo que não vamos nos preocupar neste momento. A configuração do serviço WCF deverá ficar da seguinte forma:

<system.serviceModel>
  <services>
    <service
      name=”RESTComBasicAuthentication.Services.ServicoDeUsuarios”
      behaviorConfiguration=”config”>
      <endpoint
        address=””
        binding=”webHttpBinding”
        contract=”RESTComBasicAuthentication.Services.IUsuarios”
        behaviorConfiguration=”edpConfig”
        bindingConfiguration=”bc” />
    </service>
  </services>
  <bindings>
    <webHttpBinding>
      <binding name=”bc”>
        <security mode=”TransportCredentialOnly”>
          <transport clientCredentialType=”Basic” />
        </security>
      </binding>
    </webHttpBinding>
  </bindings>
  <!– Outras Configurações –>
</system.serviceModel>

Quando utilizamos o modelo Basic, ao tentar acessar um recurso protegido, o próprio browser é capaz de identificar e abrir uma janela com os campos para informarmos o username e password, só que não podemos nos esquecer de que esse serviço será consumido por algum cliente, e que o foco aqui é o uso do jQuery, e com isso, de alguma forma precisamos enviar o username e password do cliente para o serviço. Como já sabemos, o jQuery oferece uma função chamada $.ajax, que nos permite configurar e efetuar a chamada para um determinado serviço ou algum outro método. Internamente, este método recorre a um objeto popularmente conhecido, que é o XMLHttpRequest. Este objeto é o responsável por gerenciar toda a comunicação entre o cliente e o serviço.

De acordo com a especificação deste objeto, há um método chamado Open, que entre os parâmetros convencionais, como endereço até o serviço, o tipo da requisição (Json ou Xml), há também como informar mais duas informações relacionadas ao processo de autenticação: username e password. Através dos parâmetros username e password, definimos duas strings que representam cada uma dessas informações. Como o jQuery abstrai o acesso a este objeto, a função $.ajax também nos permite informar o usuário e senha, como já mencionado acima. Sabendo da existência destes parâmetros, podemos configurar a chamada para o serviço através do jQuery da seguinte forma:

function RecuperarUsuario() {
    $.ajax(
    {
        type: “POST”,
        username: “UsuarioQueExisteNoWindows”,
        password: “123456”,
        url: “http://localhost/Services/ServicoDeUsuarios.svc/RecuperarUsuario&#8221;,
        contentType: “application/json”,
        data: ‘{ “nome”: “Israel Aece”, “email”: “ia@israelaece.com” }’,
        processData: true,
        success:
            function (resultado) {
                alert(resultado.RecuperarUsuarioResult.Nome);
                alert(resultado.RecuperarUsuarioResult.Email);
            },
    });
}

Se você monitorar a requisição para este serviço com alguma ferramenta, como é o caso do Fiddler, você verá que o username e password não serão enviados até que realmente seja necessário. O modelo de autenticação Basic é baseado no processo conhecido como “Desafio HTTP 401”, que funciona da seguinte forma:

  • O cliente solicita um recurso (página, serviço, etc.) que está protegido.
  • Ao detectar que o cliente não está autenticado, o servidor exige que ele se autentique e informe as credenciais a partir do modelo Basic. Isso é informado a partir de um header chamado WWW-Authenticate: Basic.
  • Neste momento, o servidor retorna uma resposta com o código 401 (Access Denied), que instrui o cliente (browser) a solicitar as credenciais de acesso.
  • Uma vez informado, o browser recria a mesma requisição, mas agora envia nos headers da mesma o usernamepassword codificados em Base64, sem qualquer espécie de criptografia. Na resposta, o header enviado é o Authorization: Basic [Username+Password Codificado].
  • Quando este header acima estiver presente, o servidor (IIS) é capaz de validá-lo no Windows/Active Directory, e se for um usuário válido, permitirá o acesso, caso contrário retornará a mesma resposta com código 401, até que ele digite uma credencial válida.

Apesar das credenciais estarem em hard-code no exemplo acima, nada impede de criarmos uma tela onde o cliente pode digitar um usuário e senha, mas lembrando que este usuário deverá exisitir no Windows/Active Directory.

Customização

O principal ponto negativo da solução acima é a necessidade de termos os usuários cadastrados no Windows, algo que pode ser inviável em um ambiente que não é controlado, como é o caso da internet. Algo muito comum em aplicações deste tipo, é a validação do usuário em uma base de dados, ou até mesmo, utilizando a estrutura do Membership do ASP.NET. Para atingirmos esse objetivo, precisamos entender um pouco mais sobre o processo de autenticação e também alguns pontos de estensibilidade.

Quando configuramos o modelo Basic, o IIS é o responsável por coordenar todo o processo de acesso ao recurso, e se o usuário não estiver autenticado, o próprio IIS devolve a mensagem com o código 401 e o header específico para o mesmo (1), para que o browser proceda com a solicitação das credenciais (2), e depois de informadas, refaz a requisição embutindo o header com as credencias codificadas (3). A imagem abaixo ilustra esse processo:

No exemplo que vimos acima, o único recurso protegido pelo modelo Basic é apenas o arquivo ServicoDeUsuarios.svc. Agora, se desejamos customizar, temos que trazer todo o controle do processo de autenticação para a aplicação, ou seja, não iremos mais querer que o IIS coordene o processo, que como sabemos, ele recorre ao Windows para validar os usuários. Sendo assim, precisamos permitir o acesso anônimo ao arquivo *.svc.

Há algum tempo eu comentei sobre a possibilidade de efetuar a customização da autenticação do WCF através de usuário e senha, utilizando a classe UserNamePasswordValidator para essa validação. O problema é que o binding WebHttpBinding não suporta a customização deste validador, o que nos obrigaria à descer o nível até o pipeline do ASP.NET para implementar algo específico para o WCF.

Ao invés disso, podemos recorrer aos interceptadores (Interceptors). Os interceptadores não estão nativamente dentro do WCF, mas estão disponíveis ao instalar o WCF-REST Starter Kit. Este kit nada mais é que um conjunto de funcionalidades que podemos incorporar aos nossos projetos WCF baseados em REST, tornando algumas tarefas comuns em algo mais simples de se resolver/implementar, como vai ser o caso aqui.

Ao instalar este kit, teremos à nossa disposição alguns novos assemblies, e entre eles um chamado Microsoft.ServiceModel.Web.dll. Uma das classes fornecidas por ele é a classe abstrata RequestInterceptor. Essa classe fornece um método abstrato chamado ProcessRequest, que permite interceptar a requisição, antes mesmo dela começar a ser executada, fornecendo um parâmetro do tipo RequestContext, que representa o contexto da requisição atual, qual será utilizado para a interação com o cliente que está tentando acessar o recurso.

Com esta possibilidade, podemos criar um interceptador que extrai o header da requisição HTTP que representa a credencial informada pelo usuário (WWW-Authenticate), e a valida em algum repositório de sua escolha, como uma base de dados. A partir daqui é necessário conhecermos como funciona o processo do modelo HTTP Basic, para conseguirmos dialogar com o cliente, para que assim ele consiga coordenar o processo de autenticação do usuário.

Como havia dito acima, o username e password não são enviados até que sejam efetivamente exigidos. Nesta customização, ao identificarmos que o header não está presente na requisição, precisamos configurar a resposta para o cliente com o código 401, que representa acesso não autorizado, e informar na resposta o mesmo header, para continuar obrigando o usuário a informar o username e password.

Para saber se o cliente informou as credenciais, precisamos detectar a presença do header chamado Authorization. Se existir, então precisamos decodificá-lo, utilizando o método FromBase64String da classe Convert, que dado uma string, retorna um array de bytes representando as credenciais separadas por um “:”. Depois disso, tudo o que precisamos fazer é separá-los, para que assim podermos efetuar a validação em algum repositório. O código abaixo ilustra esse processo:

string credentials = mp.Headers[“Authorization”];

if (!string.IsNullOrWhiteSpace(credentials))
{
    string decodedCredentials =
        Encoding.Default.GetString(Convert.FromBase64String(credentials.Substring(6)));

    int separator = decodedCredentials.IndexOf(‘:’);
    username = decodedCredentials.Substring(0, separator);
    password = decodedCredentials.Substring(separator + 1);
}

Caso o header não exista ou o usuário não existir na base de dados, então podemos criar o header para que o cliente seja – novamente – obrigado a informar as credenciais. Para isso, utilizamos as propriedades da mensagem, e configuramos a mensagem de retorno. A mensagem é representada no WCF pela classe Message. O código abaixo ilustra a criação, configuração e resposta ao cliente com esta mensagem recém criada:

private void GenerateAccessDeniedMessage(ref RequestContext requestContext)
{
    Message reply = Message.CreateMessage(MessageVersion.None, null, null
        new DataContractJsonSerializer(typeof(object)));

    HttpResponseMessageProperty hrp = new HttpResponseMessageProperty();
    hrp.StatusCode = HttpStatusCode.Unauthorized;
    hrp.Headers.Add(“WWW-Authenticate”, string.Format(“Basic realm=”{0}””, this.Realm));
    reply.Properties[HttpResponseMessageProperty.Name] = hrp;

    requestContext.Reply(reply);
    requestContext = null;
}

Se o usuário for válido, então é necessário inicializar o contexto de segurança do WCF, que é representado pela classe ServiceSecurityContext, que utiliza uma instância da classe GenericPrincipal para identificar o usuário logado.

Finalmente, tudo isso não funciona por si só. Ainda precisamos acoplar a instância desta classe à execução. Para isso, devemos recorrer a customização da classe que cria o host, que é responsável por gerenciar a execução da classe que representa o serviço. A classe ServiceHostFactory fornece um método chamado CreateServiceHost, que como o próprio nome diz, permite retornar qualquer classe que herde direta ou indiretamente da classe ServiceHost. Dentro do assembly do WCF-Rest Starter Kit, temos uma versão específica de host, chamada de WebServiceHost2. A grande diferença deste host, é que ele expõe uma propriedade chamada Interceptors, que permite adicionarmos qualquer interceptador, desde que ele herde da classe RequestInterceptor, como já vimos acima. Depois que a factory customizada foi criada, devemos alterar o arquivo *.svc para que ela seja utilizada:

<%@ ServiceHost
    Language=”C#”
    Debug=”true”
    Factory=”RESTComBasicAuthentication.CustomRestHostFactory”
    Service=”RESTComBasicAuthentication.Services.ServicoDeUsuarios”
    CodeBehind=”ServicoDeUsuarios.svc.cs” %>

Uma vez que acoplamos este interceptador, ele é quem gerenciará o processo de autenticação, ou seja, o cliente irá dialogar com este interceptador, mas para que isso funcione corretamente, é necessário que a autenticação Basic esteja desabilitada no IIS. Através da imagem abaixo, podemos reparar este novo comportamento:

Conclusão: Apesar de não temos nativamente no WCF uma forma de customizar a autenticação em serviços REST, podemos recorrer ao WCF-REST Starter Kit para conseguir efetuar essa customização, utilizando a infraestrutura oferecida pelo modelo HTTP Basic para enviar as credenciais. Apesar de tudo funcionar como deveria, é importante dizer que os dados continuam sendo trafegados sem qualquer proteção, e para evitar que alguém visualize o conteúdo, é importante que toda a comunicação seja protegida pelo HTTPS.

RESTComBasicAuthentication.zip (328.00 kb)

QCon – Como unificamos nossa camada de autenticação?

O principal evento de arquitetos e desenvolvedores chega a América Latina. O QCon SP traz, dias 11 e 12 de Setembro, ícones internacionais e nacionais de diversas áreas, com apresentações de alto nível técnico. Com sistemas cada vez mais complexos, o QCon aborda não apenas uma única tecnologia ou aspecto: passa de Java, .NET e Rails até Arquitetura, Design, Cloud, Escalabilidade, Replicação, Cache e casos de sucesso.

Neste evento, eu fui convidado para compor juntamente com alguns ícones do mundo .NET (tais como Thiago Cruz Soares e Fabio Galuppo), o grupo de palestrantes focados em tecnologias Microsoft/.NET. A minha palestra tem como finalidade abordar o WIF – Windows Identity Foundation, que já falei bastante por aqui. Abaixo temos a descrição completa da palestra:

Título: Como unificamos nossa camada de autenticação?
Palestrante: Israel Aece
Descritivo: Autenticação e autorização são dois conceitos importantes que existem no desenvolvimento de software. A autenticação é a necessidade de saber quem o usuário é, enquanto a autorização é saber que direitos ele tem no software. Há uma grande complexidade em torno destes temas, pois cada aplicação precisa se preocupar em vários detalhes para garantir a segurança, tais como: um local seguro para armazenar as credenciais de acesso, definição de políticas para a criação e reutilização de senhas, etc. E como se isso não fosse o bastante, corremos um grande risco de termos a mesma infraestrutura repetida entre várias aplicações, dificultando a manutenção, segurança e a experiência de navegação dos usuários que as acessam. Essa palestra mostrará cenários típicos do nosso dia-à-dia, como SSO (Single Sign-On) e federação dentro da plataforma .NET.

Codificando.NET 2010 – Palestra sobre WCF

No próximo dia 19 de junho (sábado), acontecerá em São Paulo um evento chamado Codificando 2010, organizado pela comunidade Codificando.NET. Esse evento terá várias sessões focadas exclusivamente em desenvolvimento de aplicações utilizando a plataforma .NET, com especialistas de mercado. Para maiores detalhes sobre o evento em geral, consulte o site neste endereço.

Eu fui convidado pelo Alexandre Tarifa para falar sobre WCF – Windows Communication Foundation, que é a alternativa no ambiente Microsoft/.NET para construção de aplicações distribuídas e conectadas. É importante dizer que a palestra será de nível 100, abordando superficialmente algumas das principais funcionalidades e mudanças que aconteceram nesta nova versão da tecnologia, permitindo desmistificar os principais elementos que compõem a estrutura do WCF. Abaixo temos a descrição da palestra:

Título: Distribuindo Componentes com WCF
Palestrante: Israel Aece
Descritivo: O WCF é o pilar de comunicação da plataforma .NET, e que está presente desde a versão 3.0. Através dele podemos construir serviços que podem ser consumidos pela própria empresa ou por parceiros de negócios, para que seja possível criar aplicações inteligentes e conectadas. A finalidade desta palestra é mostrar um overview sobre o WCF, abordando superficialmente as funcionalidades incluídas na versão 4.0, com exemplos práticos de sua utilização.

Evento de Tecnologia em Hortolândia

No próximo dia 01 de junho (terça-feira) acontecerá um evento na UNASP Hortolândia (Centro Universitário Adventista de São Paulo), na cidade de Hortolândia. Para quem é de Campinas e região, este evento acontecerá na sede da universidade, localizada na Rua Pr. Hugo Gegembauer, 265, Parque Hortolândia, à partir das 19:45. Eu palestrarei sobre o Visual Studio 2010 e o .NET Framework 4.0. É importante dizer que a palestra será de nível 100, que além de abordar superficialmente algumas das principais funcionalidades desta nova versão, falaremos um pouco também sobre algumas tecnologias que já existem e estão à disposição desde as versões anteriores. Abaixo temos a descrição da palestra:

Título: Visual Studio 2010 e .NET Framework 4.0
Palestrante: Israel Aece
Descritivo: Esta palestra tem a finalidade de exibir um “tour” sobre a plataforma .NET, e a principal ferramenta que utilizamos para desenvolver aplicações para ela, que é o Visual Studio. A ideia é demonstrar rapidamente a história e a evolução do .NET Framework até a versão 4.0, incluindo assuntos como as linguagens de programação (C# e VB.NET), acesso à dados e aplicações para internet (WebForms, MVC e Silverlight). Logo após, vamos analisar de forma superficial as novidades que estão sendo incluídas na IDE do Visual Studio 2010 e que dão suporte ao desenvolvimento de qualquer tipo de aplicação sobre a plataforma .NET.

Tratando erros com jQuery e WCF

Neste artigo eu mostrei como construir serviços WCF para serem consumidos através do jQuery. Nele falamos sobre os cuidados que devemos ter para criar e expor serviços WCF, mas não chegamos a falar sobre alguns detalhes, não menos importante, como é o caso do tratamento de erros, que é algo tão comum em qualquer tipo de aplicação.

Ao executar alguma operação, uma exceção pode ser disparada por algum motivo. Como já falamos, ao utilizar a biblioteca do jQuery para invocar algum serviço, podemos através de um callback, especificarmos um código para ser disparado quando algum problema ocorrer do lado do serviço. Para configurar isso, podemos utilizar o parâmetro error da função $.ajax. O código abaixo ilustra como podemos configurar o parâmetro error, exibindo uma mensagem informando ao usuário que algum problema ocorreu:

function RecuperarUsuario() {
    $.ajax(
    {
        type: “POST”,
        url: “http://localhost/Services/ServicoDeUsuarios.svc/RecuperarUsuario&#8221;,
        contentType: “application/json”,
        data: ‘{ “nome”: “”, “email”: “ia@israelaece.com” }’, //Nome vazio causa o erro
        processData: false,
        success:
            function (resultado) {
                alert(resultado.RecuperarUsuarioResult.Nome);
                alert(resultado.RecuperarUsuarioResult.Email);
            },
        error:
            function (xhr, textStatus, errorThrown) {
                alert(‘Algum Problema Ocorreu!’);
            }
        });
    }

Esse tipo de código funciona normalmente, até que você precise capturar a mensagem exata do erro que ocorreu. Quando executamos uma operação que está disparando alguma exceção, o WCF acaba retornando a seguinte mensagem: “Request server encountered an error processing the request. See server logs for more details”. O problema é que o erro não será retornado em um formato que é facilmente entendido/preferido pelo jQuery, que é o JSON.

Ao configurar o contrato para expor via AJAX, podemos definir através do atributo WebInvokeAttribute, que a requisição (RequestFormat) e a resposta (ResponseFormat) sejam formatadas em JSON, mas isso não inclui eventuais exceções que sejam disparadas pelas respectivas operações, mesmo que esse problema esteja definido como um contrato de fault (FaultContractAttribute).

Para tentar resolver isso, podemos recorrer a alguns pontos de estensibilidade do WCF, para conseguirmos interceptar o erro que ocorreu. Ao interceptar, deveremos transformar a mensagem em algum objeto que deverá ser entendido pelo jQuery, entregando para o cliente todas as informações necessárias para que o mesmo consiga tratar o erro ocorrido.

Para descrever o problema, vamos criar uma classe que possui características que detalham o erro ocorrido. Essa classe será chamada de GenericErrorDescription, que possuirá apenas uma única propriedade (para manter a simplicidade), chamada de Message, do tipo string. Como a finalidade será transformar a exceção em formato JSON para facilitar o consumo pelo jQuery, criaremos uma classe chamada de JsonErrorHandler, e nela implementaremos a interface IErrorHandler, que é uma espécie de interceptador (mais detalhes neste artigo). O principal método fornecido por esta interface, é chamado de ProvideFault, que passa como parâmetro a instância da exceção que ocorreu e uma instância da classe Message, que corresponde a mensagem que será devolvida para o cliente.

Na implementação deste método, utilizaremos o método estático CreateMessage da classe Message, que criará a mensagem de retorno, utilizando o serializador JSON para que a mesma será formatada neste padrão, e além disso, esse serializador deverá serializar a instância da classe que representa o erro, que no nosso exemplo é a GenericErrorDescription. Na sequência configuramos a instância da classe HttpResponseMessageProperty, para customizarmos a mensagem, informando que o tipo a ser retornado será application/json, para que o jQuery consiga, facilmente, entender e interpretar esse conteúdo. Note também que mantemos o StatusCode do HTTP como 500, ou seja, um erro interno, e como sua descrição, definimos a mesma mensagem gerada pela exceção disparada pela operação.

A classe JsonErrorHandler ainda implementa a interface IEndpointBehavior, que nos permite acoplar a instância desta classe em um endpoint específico, do lado do serviço (dispatcher), na coleção de tratadores de erros. O código abaixo ilustra a classe JsonErrorHandler já devidamente implementada:

public class JsonErrorHandler : IEndpointBehavior, IErrorHandler
{
    public bool HandleError(Exception error)
    {
        return true;
    }

    public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
    {
        GenericErrorDescription desc = 
            new GenericErrorDescription() { Message = error.Message };

        fault = Message.CreateMessage(version, “”, desc, 
            new DataContractJsonSerializer(typeof(GenericErrorDescription)));
        fault.Properties.Add(WebBodyFormatMessageProperty.Name, 
            new WebBodyFormatMessageProperty(WebContentFormat.Json));

        var msgp = new HttpResponseMessageProperty();
        msgp.Headers[HttpResponseHeader.ContentType] = “application/json”;
        msgp.StatusCode = HttpStatusCode.InternalServerError;
        msgp.StatusDescription = desc.Message;

        fault.Properties.Add(HttpResponseMessageProperty.Name, msgp);
    }

    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bp) { }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime cr) { }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher ed)
    {
        ed.ChannelDispatcher.ErrorHandlers.Add(this);
    }

    public void Validate(ServiceEndpoint endpoint) { }
}

Só que essa classe por si só não funciona. Precisamos efetivamente acoplar ao pipeline do WCF, e para isso, podemos criar um extension element, que nos dará a oportunidade de efetuar essa configuração de modo declarativo, ou seja, através do arquivo Web.config. Basicamente, essa classe será responsável por criar instâncias da classe que criamos acima, ou seja, do tratador de erros:

public class JsonErrorElement : BehaviorExtensionElement
{
    public override Type BehaviorType
    {
        get
        {
            return typeof(JsonErrorHandler);
        }
    }

    protected override object CreateBehavior()
    {
        return new JsonErrorHandler();
    }
}

Depois das classes devidamente criadas, tudo o que precisamos fazer agora é configurarmos o arquivo Web.config do serviço, acoplando o extension element ao endpoint de acesso ao serviço. A configuração final do Web.config deve ficar da seguinte forma:

<system.serviceModel>
  <services>
    <service name=”ServicoDeUsuarios” behaviorConfiguration=”config“>
      <endpoint
        binding=”webHttpBinding”
        contract=”IUsuarios”
        behaviorConfiguration=”edpConfig” />
    </service>
  </services>
  <behaviors>
    <serviceBehaviors>
      <behavior name=”config“>
        <serviceDebug includeExceptionDetailInFaults=”false” />
      </behavior>
    </serviceBehaviors>
    <endpointBehaviors>
      <behavior name=”edpConfig“>
        <jsonErrorHandler />
      </behavior>
    </endpointBehaviors>
  </behaviors>
  <extensions>
    <behaviorExtensions>
      <add
        name=”jsonErrorHandler
        type=”JsonErrorElement, WCFExtensions, Version=1.0.0.0, …” />
    </behaviorExtensions>
  </extensions>
</system.serviceModel>

Já do lado do cliente, as mudanças são bastante ligeiras. Tudo o que precisamos fazer é uma pequena mudança no código que é disparado quando o erro ocorre. Uma vez que o interceptador de erros está acoplado do WCF, a mensagem com o erro de retorno será formatada em JSON, e se analisarmos o retorno, veremos o seguinte resultado:

{“Message”: “Informe o nome do usuariou000du000aParameter name: nome”}

Como a mensagem de retorno está em formato JSON, utilizaremos o método parse da classe JSON, exposta pelo JSON2. Esse método é responsável por transformar o conteúdo JSON em um objeto, respeitando as mesmas propriedades serializadas pela classe GenericErrorDescription. Com isso, o nosso código de consumo ao serviço será alterado para:

function RecuperarUsuario() {
    $.ajax(
    {
        type: “POST”,
        url: “http://localhost/Services/ServicoDeUsuarios.svc/RecuperarUsuario&#8221;,
        contentType: “application/json”,
        data: ‘{ “nome”: “”, “email”: “ia@israelaece.com” }’, //Nome vazio causa o erro
        processData: false,
        success:
            function (resultado) {
                alert(resultado.RecuperarUsuarioResult.Nome);
                alert(resultado.RecuperarUsuarioResult.Email);
            },
        error:
            function (xhr, textStatus, errorThrown) {
                var erro = JSON.parse(xhr.responseText);
                alert(erro.Message);
            }
        });
    }

Se quiser levar mais detalhes do erro, você ainda tem algumas outras alternativas, mas não tão interessantes como essa. Você poderia optar por definir o atributo includeExceptionDetailInFaults do elemento serviceDebug para True, mas isso iria expor mais informações do que realmente deveria, como por exemplo a Stack Trace, algo que não deveria ultrapassar o serviço. Além dela, ainda poderia envolver toda a operação em um bloco try/catch, e caso algum problema ocorra, utilizamos a classe WebOperationContext para customizar o StatusCode e o ContentType através dela, mas isso torna a classe que representa o serviço dependente do protocolo HTTP, o que não é uma boa opção.

Conclusão: Graças a grande flexibilidade fornecida pelo WCF, podemos contornar alguma de suas “limitações” de uma forma bastante elegante, sem precisar misturar em minhas operações, códigos que estão relacionados puramente à infraestrutura.

A importância do StrongName

Imagine que você precise criar um conjunto de componentes que gerenciam a área de recursos humanos de uma determinada empresa. Entre esses componentes, vamos ter um chamado Salario, que dado o nome do funcionário, valor base do salário e a quantidade de horas extras que o funcionário realizou no mês, retorná o valor líquido que a empresa deverá pagar a ele.

Para ilustrar isso, temos um projeto do tipo Class Library, chamado de RegrasDeNegocio. Dentro deste projeto, criamos uma classe chamada Salario, que possuirá apenas o método chamado de Calcular, que receberá os parâmetros mencionados acima. Traduzindo tudo isso em código, teremos algo como:

public class Salario
{
    public decimal Calcular(string nomeDoFuncionario, decimal valorBase, decimal horasExtras)
    {
        return valorBase + horasExtras;
    }
}

Note que não há nenhuma complexidade envolvida para não desviarmos o foco. Como sabemos, este projeto dará origem à uma DLL, que poderá ser utilizada por várias aplicações que rodam dentro da empresa. Como já era de se esperar, vamos referenciá-la em um projeto chamado AplicacaoDeRH, que utilizará esse componente recém criado para calcular os salários de seus respectivos funcionários. Com isso, o código de consumo na aplicação final é algo parecido com isso:

Console.WriteLine(new Salario().Calcular(“Israel Aece”, 1000.00M, 250.00M));

Dá mesma forma que antes, vamos manter a simplicidade aqui. Depois deste software (EXE + DLL) instalado na máquina do responsável pelo RH da empresa, eu chego até o diretório físico onde ele está instalado. Copio esses dois arquivos para minha máquina para começar a analisar como esse componente e aplicação foram desenvolvidos. Como sabemos, dentro de qualquer assembly .NET, temos apenas código IL, que é um código ainda decompilável. Podemos utilizar o Reflector para isso e, consequentemente, visualizar tudo o que eles possuem (classes, métodos, parâmetros, etc.).

A partir de agora, vamos explorar a vulnerabilidade. Como eu conheço toda a estrutura que o componente (DLL) tem, nada impede de eu criar um projeto no Visual Studio .NET, com o mesmo nome, com os mesmos tipos e os mesmos parâmetros. Com isso, eu vou manipular o corpo do método Calcular, verificando se o funcionário que está sendo calculado o salário sou eu, e se for, multiplico a quantidade de horas extras por 2, para que eu possa ganhar um valor maior do que realmente deveria.

public class Salario
{
    public decimal Calcular(string nomeDoFuncionario, decimal valorBase, decimal horasExtras)
    {
        if (nomeDoFuncionario == “Israel Aece”)
            horasExtras *= 2;

        return valorBase + horasExtras;
    }
}

Depois de compilado, isso dará origem à uma – nova – DLL com o mesmo nome. De alguma forma, eu chego até o computador do responsável pelo RH da empresa, e substituo fisicamente a DLL anterior por essa DLL que acabamos de desenvolver, e que viola a regra de negócio, pois manipula o resultado para beneficiar um funcionário específico. Com isso, quando o responsável pelo RH for calcular o meu salário, ele me pagará duas vezes o valor das minhas horas extras. Se ele confia cegamente no software que dá o resultado, estou sendo beneficiado, a empresa prejudicada e dificilmente alguém encontrará o problema.

A importância do StrongName

Todo e qualquer assembly possui algumas características que ajudam ao runtime determinar a sua identidade. A identidade de qualquer assembly .NET é composta por quatro informações, a saber: nome, versão, cultura e uma chave pública. O nome nada mais é que o nome do assembly, desconsiderando a sua extensão. A versão é o número em que o projeto se encontra, e que por padrão é 1.0. Já a cultura determina se o assembly é sensitivo à alguma cultura e, finalmente, a chave pública, qual falaremos mais adiante.

Podemos utilizar várias ferramentas para conseguir visualizar essas informações. No nosso caso, se abrirmos dentro do Reflector o componente que criamos inicialmente, aquele que possui o código legal, poderemos comprovar essas características que ajudam a identificar o assembly:

RegrasDeNegocio, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

Quando criamos a assembly ilegal, com o código que multiplica a quantidade de horas extras por dois, poderemos notar que o resultado será idêntico, ou seja, não há nada que diferencie a identidade dos dois assemblies. Sendo assim, a substituição física é o suficiente para comprometer a regra de cálculo de salário, já que para a aplicação que a consome, acaba sendo o mesmo componente. Se repararmos melhor, entre as quatro informações que compõem a identidade do assembly, uma delas é chamada de PublicKeyToken, e que está nula (não definida). É justamente nela que está a solução para o nosso problema.

Dentro do .NET Framework existem dois tipos de assemblies: os que são fracamente nomeados e os que são fortemente nomeados. Aqueles que são fracamente nomeados (que é o padrão para todos os projetos .NET), são estruturalmente idênticos, possuindo o mesmo formato e os mesmos tipos definidos, mas como está, dá margem para esse tipo de problema.

Isso acontece porque quando efetuamos a referência do componente RegrasDeNegocio.dll na aplicação AplicacaoDeRH.exe, o .NET injeta no manifesto da AplicacaoDeRH, informações pertinentes ao assembly de regras de negócio. Se analisarmos o manifesto do EXE, veremos a seguinte informação:

Na imagem acima, podemos verificar que dentro da AplicacaoDeRH há uma referência para o componente RegrasDeNegocio, que inclui o nome e a versão dele. Como até então o componente ilegal possui a mesma identidade, a aplicação consome ele sem maiores problemas, não sabendo que se trata de um componente malicioso.

Para resolver o nosso problema, vamos recorrer aos assemblies fortemente nomeados (strong names). A única e principal diferença em relações aos assemblies fracamente nomeados, é a atribuição de uma chave única, que não se repetirá em nenhum lugar do mundo. A Microsoft criou esse recurso, desde a primeira versão do .NET Framework, que utiliza um par de chaves (pública e privada) para garantir a unicidade do assembly. Antes de ver como elas funcionam, vamos primeiramente entender como gerá-la. O .NET Framework fornece uma ferramenta chamada SN.exe, que é responsável por gerar e manipular essas chaves. Para gerar a nossa chave, podemos executar o seguinte comando (através do prompt do Visual Studio .NET):

SN -k MinhasChaves.snk

O arquivo gerado possui as duas chaves, a pública e a privada e você pode nomear o arquivo da forma que quiser. Com o par de chaves gerado, podemos criar um segundo arquivo para acomodar somente a chave pública, mas em um primeiro momento, isso é desnecessário. A ideia aqui é somente visualizarmos o que temos como chave pública:

SN -p MinhasChaves.snk MinhaChavePublica.snk

Para visualizarmos a chave pública, podemos utilizar o seguinte comando:

SN -tp MinhaChavePublica.snk

Public key is
0024000004800000940000000602000000240000525341310004000001000100f1589e575d9c20
cc36a0fb7245d74c8d69ddc26a0c92ebee5e65dba7c94a6583701176cc5a8fd795e11d7e366c49
a19f3ae28509fa8961e6eca103353fe98168a402dc35001b98d9d5325f6121bde11bc698f268a3
e7e338b950b565be26e371c2550dfaee54f9ef8993dc476f60b2ab5ad69d5ae832ddd7e35e43ad
6daafae2

Public key token is 0b8510fcd7fd739a

Só que o arquivo snk por si só não funciona. Você precisa vinculá-lo ao assembly qual deseja assinar. Para isso, você pode abrir o arquivo AssemblyInfo.cs, e adicionar o atributo AssemblyKeyFileAttribute, que recebe o caminho físico até o arquivo que contém o par de chaves, e que no nosso exemplo é MinhasChaves.snk.

[assembly: AssemblyKeyFile(@”C:MinhasChaves.snk”)]

Ao compilar o assembly com a chave vinculada, veremos que a identidade do assembly já mudará. Ao vincular a chave criada acima no nosso componente RegrasDeNegocio, a identidade irá aparecer da seguinte forma:

RegrasDeNegocio, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0b8510fcd7fd739a

A única e essencial diferença é que agora a propriedade PublicKeyToken reflete exatamente a nossa chave pública, que está contida no arquivo MinhasChaves.snk vinculado ao componente. A partir de agora, as aplicações que referenciarem o componente RegrasDeNegocio, guardarão além do nome e versão do mesmo, a chave pública que o identifica. Depois dessas alterações, se visualizarmos o manifesto da aplicação AplicacaoDeRH, teremos o seguinte resultado:

Com isso, qualquer pessoa maliciosa que tente refazer o assembly, por mais que ela se atente a criar toda a estrutura de tipos e métodos, definir o mesmo nome de assembly, e ainda, assinar com um outro strong name, ela jamais conseguirá reproduzir a mesma identidade e, consequentemente, não conseguirá mais alterar o componente que está instalado no cliente. É importante dizer que fisicamente, a substituição ainda poderá ocorrer, mas quando a aplicacação AplicacaoDeRH tentar acessar algum recurso do assembly RegrasDeNegocio, uma exceção será disparada, informando que o assembly solicitado não corresponde aquele que foi inicialmente referenciado.

Observação: Toda essa segurança pode continuar vulnerável se você deixar o arquivo com a chave privada em mãos erradas. Se a pessoa maliciosa conseguir ter acesso a esse arquivo, ela irá gerar o assembly idêntico como ela já fazia, mas ao invés de criar um novo par de chaves para assinar o assembly, ela utilizará o mesmo que você utilizou para assinar o seu, que é o verdadeiro, e com isso todo o problema volta a acontecer.

Para finalizar, vamos entender como todo esse mecanismo funciona e como o runtime do .NET Framework assegura isso. Quando geramos a chave a partir do utilitário SN.exe, um par de chaves é adicionado no arquivo MinhasChaves.snk. Quando compilamos o projeto com esse arquivo vinculado a ele, o .NET gera um hash do componente utilizando o algoritmo SHA1 e assina esse hash com a chave privada. O resultado deste processo é adicionado no próprio assembly, incluindo também a sua chave pública, que está matematicamente relacionada à chave privada. A imagem abaixo ilustra esse processo:

Como vimos acima, quando o componente é referenciado na aplicação que o utiliza, a chave pública também é adicionada à aplicação. Durante a execução, o .NET Framework irá aplicar o mesmo algoritmo de hash no conteúdo do componente (DLL) e dará origem à um novo hash e a chave pública embutida na aplicação que consome aquele componente, será utilizada para extrair o conteúdo (já “hasheado”) que está embutido na DLL do componente. Para determinar se a DLL é a mesma ou não, o resultado do hash deve ser igual, do contrário, a DLL foi substituída e, felizmente, uma exceção será disparada, evitando assim de consumir um componente ilegal. A imagem abaixo ilustra esse processo:

Conclusão: Ao assinar uma aplicação/componente com um strong name, podemos tirar proveito de várias funcionalidades, como por exemplo, o refinamento de segurança, a instalação no GAC, que por sua vez possibilita a centralização, execução lado a lado de múltiplas versões de um mesmo componente, etc. Mas um dos principais benefícios fornecidos por ele, é a unicidade do componente, evitando que alguém consiga reproduzí-lo e, consequentemente, colocar em risco a execução e a confiabilidade das aplicações que a consomem.

AppFabric para desenvolvedores WCF

Temos dentro do sistema operacional uma ferramenta administrativa conhecida como Component Services. É através desta ferramenta que controlamos os componentes que utilizam a tecnologia COM+, permitindo visualizar aqueles componentes que estão hospedados em um determinado servidor, configurar suas características, entre várias outras funcionalidades.

Em muitas situações, o Component Services é encarado como sendo o servidor de aplicações, pois é nele que estarão todos os componentes que são utilizados pela companhia. Utilizamos o Component Services para centralizar tais componentes, fazendo uso de suas funcionalidades, tais como: suporte à transações, pool de objetos, sincronização, etc. As aplicações clientes, sejam elas Windows ou Web, recorrem a estes componentes hospedados neste servidor para executar as tarefas.

Com o surgimento do WCF, o COM+ está perdendo espaço, e a partir de agora, quando falamos em sistemas distribuídos, utilizamos o WCF como tecnologia para suportar isso. Uma das principais características do WCF, é a independência de hosting, ou seja, podemos utilizar qualquer tipo de aplicação para hospedar um serviço WCF.

No ambiente do WCF, um dos hosts que mais se popularizou foi o IIS, que até então, possibilitava apenas a publicação do serviço em cima do protocolo HTTP/HTTPS. A partir da versão 7.0 do IIS, ele já traz suporte à todos os protocolos, incluindo o TCP (WAS). Ao incorporar essa funcionalidade, isso o tornou muito mais do que um simples servidor para sites da web, dando a ele características de um servidor de aplicação, onde podemos hospedar componentes, que através do WCF, vamos publicar para os consumidores, estejam eles dentro do fora dos limites da empresa.

O IIS ganhou todas essas capacidades, mas as ferramentas que ajudam a monitorar esses serviços não evoluíram na mesma proporção. Por mais que eu consiga hospedar meus componentes no IIS, fazendo uso dos diversos protocolos, não há como, por exemplo, saber quais são os serviços WCF que eu tenho hospedado naquele servidor; quais são os endpoints publicados para um determinado serviço, entre várias outras informações úteis tanto para os desenvolvedores quanto para aqueles que administram o servidor.

Pensando nisso, a Microsoft criou uma ferramenta chamada de Windows Server AppFabric. Quando instalada, essa ferramenta adiciona ao sistema operacional, mais precisamente dentro do IIS, um conjunto de funcionalidades que permitem diagnosticar e gerenciar os serviços que rodam dentro de um determinado servidor. Além disso, o AppFabric ainda fornece recursos adicionais, como uma estrutura para caching distribuído, que pode ser utilizado para qualquer tipo de aplicação.

Entre os vários recursos oferecidos pelo AppFabric, temos a possibilidade de gerenciar e monitorar serviços WCF. Entre as funcionalidades exclusivas ao WCF, temos a capacidade de visualizar quais são os serviços que rodam naquele servidor, quais são os endpoints que cada serviço publica (incluindo aqueles de metadados). As imagens abaixo ilustram essas funcionalidades:

Ainda há uma opção chamada de Dashboard, que exibe uma visão sintética de quantas chamadas para serviços WCF ocorreram, quantas falharam, as exceções que foram disparadas, etc. Como trata-se de uma visão agrupada, essa tela possui vários links, que ao clicar, levará para uma segunda tela, com os filtros relacionados àquela opção clicada, fornecendo a visão analítica, com informações mais completas a respeito daquele serviço. A imagem abaixo ilustra este dashboard:

Ao instalar o AppFabric, um assistente é inicializado para configurá-lo. Basicamente, ele solicitará um local para armazenar as informações geradas por ele, para que mais tarde, possamos visualizá-las. Essas configurações exigem que você defina, através de uma espécie de provider, um banco de de dados SQL Server. É importante que você crie um banco exclusivo para isso, já que este assistente adicionará vários objetos dentro dele (tabelas, views, jobs, etc.), que são de uso exclusivo, e misturar com a base de dados da aplicação não é uma boa prática.

Além dessas informações macros, ainda temos um detalhamento delas. Quando utilizamos o tracing, uma série de informações são geradas, catalogando todos os estágios por onde a requisição está passando. No AppFabric temos uma seção chamada de Tracked Events, que nos permite visualizar justamente esse tipo de informação. Se analisarmos a imagem abaixo, podemos perceber os diversos eventos (estágios) do processamento, que ocorreram do lado do servidor, e também é possível visualizar a operação que foi efetivamente disparada.

Algumas poucas configurações do serviço estão disponíveis a partir do AppFabric, como é o caso de algumas cotas e throttling, mas como sabemos, as configurações do WCF são extensas e complexas, e neste caso, o uso da ferramenta WCF Service Configuration Editor performa melhor.

Para finalizar, um outro recurso bastante interessante, que também é fornecido com o AppFabric, é a possibilidade de exportar todas as configurações de um servidor, incluindo os serviços que nele rodam. Esse recurso utiliza em seus bastidores, uma ferramenta conhecida como Web Deployment Tool, e que permite configurar um outro servidor com as mesmas características deste servidor de origem, sem a necessidade de lembrar cada uma das configurações que você já realizou anteriormente.

Conclusão: O AppFabric não visa apenas serviços WCF. Como o Windows Workflow (WF) tem uma forte integração com o WCF, é possível gerenciarmos esses serviços a partir do AppFabric, com recursos para interagir com workflows de longa duração. Além disso, ainda há recursos extras que vão além do escopo definido para este artigo, mas que não são menos importantes. Depois de ter criado toda a infraestrutura necessária para suportar serviços WCF dentro do IIS, a Microsoft tem destinado grande parte de seus esforços no desenvolvimento desse tipo de ferramenta, que ajudam a monitorar e diagnosticar problemas, algo que muitas vezes são realizadas por outras pessoas, e que não são necessariamente desenvolvedores.

Utilizando jQuery para invocar Actions

Com jQuery podemos acessar serviços WCF para tornar a experiência do usuário muito melhor, evitando a atualização completa da página. Neste artigo vimos como proceder para preparar um serviço WCF para ser exposto e ser consumido via AJAX, e além disso, exploramos a API do jQuery para efetuar a comunicação com esse serviço.

Só que muitas vezes, para ter a riqueza necessário do lado do cliente, tudo o que precisamos fazer é consumir métodos que estão no código C#/VB.NET, dentro da própria aplicação. Se a aplicação está baseada no ASP.NET MVC, talvez tenhamos a necessidade de invocar uma ação (action) de um determinado controller. Felizmente o jQuery não está limitado à executar apenas métodos expostos por serviços WCF, mas também podemos acessar os métodos criados nos controllers, utilizando a mesma API. A finalidade deste artigo é mostrar como proceder para atingir esse objetivo.

Como todos sabemos, todas as actions de um controller sempre devem retornar a instância de uma das classes derivadas de ActionResult, e como o próprio nome diz, é responsável por receber, armazenar e devolver o resultado da respectiva ação. Uma das classes derivadas dela é a JsonResult, que representa o resultado em formato JSON, que é o formato mais conveniente para o jQuery trabalhar.

Sendo assim, para aquelas actions que desejamos consumir através do jQuery, precisamos retornar uma instância da classe JsonResult, abastecendo a propriedade Data com algum objeto que desejamos visualizar do lado do cliente. Essa propriedade recebe um System.Object, o que nos permite definirmos qualquer objeto, incluindo tipos anônimos. A partir da versão 2.0 do ASP.NET MVC, a Microsoft adicionou nesta classe uma nova propriedade chamada de JsonRequestBehavior, que recebe uma das duas opções fornecidas pelo enumerador com o mesmo nome. Basicamente, a ideia desta propriedade é controlar se o acesso via GET é permitido ou não. Por questões de segurança, essa propriedade é definida com a opção DenyGet, o que nega a possibilidade de conseguir invocar através de GET. Você pode trocar para a opção AllowGet, mas é importante que você conheça os eventuais problemas que podem acontecer se isso estiver habilitado. Com esse conhecimento da classe JsonResult, podemos ter a seguinte action:

public class UsuariosController : Controller
{
    public ActionResult RecuperarUsuario()
    {
        return new JsonResult()
        {
            Data = new Usuario() { Codigo = 123, Nome = “Israel” }
        };
    }
}

Depois do controller e da action criados, vamos recorrer ao jQuery para consumir este método. O jQuery fornece alguns atalhos, que evita a configuração total da função $.ajax. Um desses atalhos é a função $.getJSON, que dado uma URL e um callback, podemos referenciar o método criado anteriormente, e com a função de callback processar o resultado. O problema é que a função $.getJSON efetua a solicitação via GET, e como vimos acima, não estamos permitindo isso (JsonRequestBehavior). Sendo assim, vamos recorrer a função de baixo nível $.ajax, configurando apenas o que é necessário para executar o método:

function RecuperarUsuario() {
    $.ajax(
    {
        type: “POST”,
        url: “/Usuarios/RecuperarUsuario”,
        contentType: “application/json”,
        success:
            function (resultado) {
                alert(resultado.Codigo);
                alert(resultado.Nome);
            },
    }

Como percebemos no código acima, ele está invocando o método RecuperarUsuario no controller Usuarios, através de POST, e quando o resultado é devolvido, exibimos a mensagem na tela. Note que há uma barra (/) antes do nome do controller. Isso é necessário porque a view corrente, que possui o código jQuery, não faz parte deste controller, o que nos obriga a mencionar a partir no nível raiz. Se quisermos acessar uma action que está no controller da view, então tudo o que é necessário é informar o nome da mesma, sem mencionar o controller.

Já quando a action exigir parâmetros, é necessário informá-los durante a chamada. Se modificarmos a action para ela passar a receber dois parâmetros, sendo o código e o nome do usuário, precisamos informar isso na chamada para o método, ficando da seguinte forma:

function RecuperarUsuario() {
    $.ajax(
    {
        type: “POST”,
        url: “/Usuarios/RecuperarUsuario”,
        data: { “codigo”: 123, “nome”: “Israel Aece” },
        processData: true,
        success:
            function (resultado) {
                alert(resultado.Codigo);
                alert(resultado.Nome);
            },
    }

Como a opção processData está definida como True, ele converterá o JSON que informamos no parâmetro data em uma espécie de coleção de chave/valor, e como estamos efetuando a requisição através de POST, as parâmetros serão colocados no corpo da mensagem, separando cada par de chave com o caracter &. Note que na chamada acima, não definimos a propriedade contentType para application/json, já que o conteúdo a ser enviado trata-se de parâmetros em suas formas tradicionais.

O problema maior é quando a action recebe um parâmetro complexo, como por exemplo, a instância da classe Usuario. Neste caso, temos que recorrer à biblioteca JSON2, que fornecerá recursos para serializar a instância de um objeto em formato JSON, para que assim possa trafegar até a action correspondente. Com isso, o código para a chamada à ela será da seguinte forma:

function Adicionar() {
    var usuario = { “Codigo”: 123, “Nome”: “Israel” };

    $.ajax(
    {
        type: “POST”,
        url: “/User/Adicionar”,
        contentType: “application/json”,
        data: JSON.stringify(usuario),
        processData: false,
        success:
            function (resultado) {
                alert(resultado);
            },
    });
}

Do lado do servidor, teremos um método chamado Adicionar, que recebe a instância da classe Usuario. O código abaixo ilustra como devemos configurar a action com este parâmetro, e note que a propriedade Data retorna uma mensagem, informando que o usuário foi cadastrado com sucesso.

public class UsuariosController : Controller
{
    public ActionResult Adicionar(Usuario usuario)
    {
        return new JsonResult()
        {
            Data = “Usuario cadastrado com sucesso.”
        };
    }
}

Só que do lado da action também será necessário efetuar um código adicional. Como estamos mandando o conteúdo em formato JSON, o ASP.NET MVC não conseguirá extrair o objeto diretamente dele, o que nos obriga a criar um binder exclusivo para isso, onde podemos utilizar algum serializador JSON que faça esse trabalho.

Para atingir esse objetivo, podemos utilizar um ponto de estensibilidade do ASP.NET MVC, que nos permite criar um atributo herdando da classe CustomModelBinderAttribute, onde podemos definir como vamos efetuar a “tradução” do(s) parâmetro(s) que estão no corpo da requisição, em um objeto conhecido pela aplicação, e que no nosso exemplo será a classe Usuario. Esta classe possui um método chamado GetBinder, que retorna a instância de uma classe que implementa a interface IModelBinder, qual utilizaremos o serializador DataContractJsonSerializer, que é o mesmo serializador utilizado pelo WCF. O código abaixo ilustra como ele deve ficar:

public class JsonBinderAttribute : CustomModelBinderAttribute
{
    public override IModelBinder GetBinder()
    {
        return new JsonModelBinder();
    }

    public class JsonModelBinder : IModelBinder
    {
        public object BindModel(ControllerContext cc, ModelBindingContext bc)
        {
            return new DataContractJsonSerializer(bc.ModelType)
                .ReadObject(cc.HttpContext.Request.InputStream);
        }
    }
}

Agora, tudo o que precisamos fazer é decorar o parâmetro da action com o atributo que criamos acima. Isso dirá ao runtime do ASP.NET MVC que deverá utilizar este binder para preencher o conteúdo do parâmetro usuario. Abaixo temos a mesma action Adicionar, mas com a alteração necessária para que funcione devidamente, utilizando o binder recém criado:

public ActionResult Adicionar([JsonBinder]Usuario usuario)
{
    //…
}

Conclusão: Este artigo mostrou mais uma das possibilidades que temos ao utilizar o jQuery, onde conseguimos acessar métodos escritos em C#/VB.NET, sem a necessidade de uma atualização geral da página. Como já sabemos, a experiência do usuário aumenta, e nós como desenvolvedores, podemos fazer uso de uma API consistente, independente se estamos consumindo métodos locais ou remotos.

multipleSiteBindingsEnabled

Há algum tempo eu comentei aqui sobre uma dificuldade que existe quando hospedamos serviços WCF no IIS. Neste mesmo post, eu mostrei a solução que foi incorporada na versão 3.5 do WCF.

Para facilitar isso, a partir da versão 4.0 do WCF temos uma opção chamada multipleSiteBindingsEnabled, disponível através do elemento serviceHostingEnvironment, que quando definido como True, permite que o serviço fique disponível a partir dos múltiplos endereços de acesso configurados no IIS. Abaixo temos o arquivo de configuração com esta opção habilitada:

<system.serviceModel>
    <serviceHostingEnvironment multipleSiteBindingsEnabled=”true”/>
</system.serviceModel>

Consumindo serviços WCF com jQuery

O jQuery é uma biblioteca com várias funcionalidades que tornam o desenvolvimento de código JavaScript muito mais simples. Tarefas que demandavam várias linhas de código para chegar a um determinado resultado, atualmente com o jQuery o código necessário para atingir esse mesmo objetivo é muito menos complexo. Inclusive a Microsoft reconheceu a facilidade e a larga adoção pelos desenvolvedores, e decidiu incorporá-lo às templates de projeto do ASP.NET.

Entre as mais variadas funcionalidades que o jQuery oferece, uma delas é o suporte ao AJAX, que nos permite invocar métodos que estão do lado do servidor. Mas além disso, uma das possibilidades que temos é a requisição para serviços, incluindo serviços construídos com WCF. A finalidade deste artigo é mostrar como proceder para criar serviços WCF que possam ser consumidos pelo AJAX, e depois disso, vamos analisar o que o jQuery oferece para o consumo do mesmo.

Primeiramente vamos nos atentar a construção de um serviço para que possamos consumí-lo através do AJAX/jQuery. O que precisamos nos atentar é que para expor esse serviço para clientes AJAX, é necessário decorarmos as operações não somente com o atributo OperationContractAttribute, mas também com os atributos WebGetAttribute ou WebInvokeAttribute, que são disponibilizados a partir da versão 3.5 do .NET Framework, e que estão contidos debaixo do namespace System.ServiceModel.Web (assembly System.ServiceModel.Web.dll).

Como exemplo, o contrato irá manipular instância da classe Usuario, que nada mais é do que um objeto simples, que possui três propriedades autoexplicativas: Codigo, Nome e Email. O contrato fornecerá três operações: RecuperarUsuario, que retorna a instância da classe Usuario devidamente configurada com os parâmetros de entrada, uma outra operação chamada RecuperarUsuarios que retorna uma coleção de usuários e, finalmente, a operação Adicionar, que dado a instância do usuário, irá adicioná-lo em algum repositório. Abaixo podemos visualizar a interface que servirá como o contrato para o serviço:

[ServiceContract]
public interface IUsuarios
{
    [OperationContract]
    [WebInvoke(
        BodyStyle = WebMessageBodyStyle.Wrapped,
        RequestFormat = WebMessageFormat.Json,
        ResponseFormat = WebMessageFormat.Json)]
    Usuario RecuperarUsuario(string nome, string email);

    [OperationContract]
    [WebGet(
        BodyStyle = WebMessageBodyStyle.Bare,
        RequestFormat = WebMessageFormat.Json,
        ResponseFormat = WebMessageFormat.Json)]
    Usuario[] RecuperarUsuarios();

    [OperationContract]
    [WebInvoke(
        BodyStyle = WebMessageBodyStyle.Bare,
        RequestFormat = WebMessageFormat.Json,
        ResponseFormat = WebMessageFormat.Json)]
    void Adicionar(Usuario usuario);
}

Note que as operações que serão expostas também determinam algumas configurações específicas para quando forem consumidas a partir do AJAX. É importante perceber também que em todas elas, estamos optando por trabalhar com JSON ao invés do XML para formular a mensagem de requisição e de resposta, já que o JSON é mais simples de se trabalhar com Javascript. A propriedade BodyStyle controla como o corpo da requisição/resposta deve ser formatado, determinando se os parâmetros ou o resultado dos métodos devem ou não estar dentro de elementos adicionais. Para maiores detalhes sobre esses parâmetros, consulte este artigo.

Ao interceptar a requisição/resposta que é feita para a primeira operação, então teremos as informações em JSON sendo trafegadas, e as duas pontas (WCF e o jQuery) se encarregam de fazer toda a tradução necessária, aliviando assim nosso trabalho. Antes de analisarmos o código necessário para consumir serviços WCF no jQuery, vamos analisar o conteúdo que está sendo trafegado para as mensagens (requisição e resposta respectivamente) do contrato que criamos acima:

[ Operação RecuperarUsuario ]

POST http://localhost/Services/ServicoDeUsuarios.svc/RecuperarUsuario HTTP/1.1
Content-Type: application/json
— OUTROS PARAMETROS OMITIDOS —

{ “nome”: “Israel Aece”, “email”: “ia@israelaece.com” }

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
— OUTROS PARAMETROS OMITIDOS —

{“RecuperarUsuarioResult”:{“Codigo”:123,”Email”:”ia@israelaece.com”,”Nome”:”Israel Aece”}}

[ Operação RecuperarUsuarios ]

GET http://localhost/Services/ServicoDeUsuarios.svc/RecuperarUsuarios HTTP/1.1
— OUTROS PARAMETROS OMITIDOS —

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
— OUTROS PARAMETROS OMITIDOS —

[{“Codigo”:1,”Email”:”usuario1@servidor.com.br”,”Nome”:”Nome do Usuario 1″},{“Codigo”:2,”Email”:”usuario2@servidor.com.br”,”Nome”:”Nome do Usuario 2″},{“Codigo”:3,”Email”:”usuario3@servidor.com.br”,”Nome”:”Nome do Usuario 3″},{“Codigo”:4,”Email”:”usuario4@servidor.com.br”,”Nome”:”Nome do Usuario 4″}]

[ Operação Adicionar ]

POST http://localhost/Services/ServicoDeUsuarios.svc/Adicionar HTTP/1.1
Content-Type: application/json
— OUTROS PARAMETROS OMITIDOS —

{“Codigo”:123,”Nome”:”Israel”,”Email”:”ia@israelaece.com”}

Note que a URL de requisição também contempla o método a ser disparado do lado do serviço. Os parâmetros de entrada são serializados em JSON, e o resultado idem. Na operação RecuperarUsuario, configuramos ela para que o resultado seja Wrapped, e com isso, o corpo da mensagem de retorno veio envolvida em um objeto com o nome de RecuperarUsuarioResult, ao contrário daquelas definidas como Bare, onde a requisição/resposta não estão envolvidas neste elemento adicional.

Além dos detalhes que são necessários em nível de contrato, precisamos nos atentar em como hospedar esse serviço. Você precisa configurar o endpoint do WCF para utilizar um binding exclusivo para este cenário, que é o WebHttpBinding. Se você estiver hospedando no IIS (como é o caso do exemplo acima), então provavelmente haverá um arquivo com extensão *.svc que representa o serviço. É dentro deste arquivo que precisamos trocar o “fábrica” de hosts, que deve apontar para o WebServiceHostFactory, assim como já mostrei neste artigo.

Depois de todo o serviço WCF já devidamente criado e rodando, precisamos entender a API do jQuery para consumir esse serviço de exemplo. Nos dois tipos de projetos ASP.NET (WebForms e MVC), ambos já trazem o JQuery referenciado, o que nos permite acessar o que ele fornece para consumir serviços, escritos em qualquer tecnologia. Sendo assim, o primeiro passo importante para acessar qualquer um dos recursos fornecidos pelo jQuery, devemos adicionar uma referência para o arquivo *.js correspondente ao mesmo, e para isso, podemos utilizar o seguinte elemento:

http://Scripts/jquery-1.4.1.js

Depois deste arquivo referenciado, então já podemos utilizar a API do jQuery para consumir serviços WCF. Vamos utilizar neste exemplo a função $.ajax, que é uma função de baixo nível do jQuery, e que nos permite customizar, através de uma série de parâmetros, as configurações para controlar como a mensagem será enviada e como a resposta será processada.

Entre os vários parâmetros, temos o type, que determina com a requisição será enviada ao serviço, podendo ser através de GET ou POST. A propriedade url determina o endereço até o serviço, incluindo o nome da operação a ser invocada. contentType é onde definimos como o corpo da mensagem está formatada, e apesar do jQuery utilizar um tipo genérico, que pode ser aplicado em grande parte dos casos, é sempre melhor deixar isso explícito com o tipo que você está operando. A propriedade data determina o que vai ser enviado para a operação. Essa propriedade trabalha em conjunto com uma outra propriedade chamada processData. Quando você define os dados a serem enviados para o serviço através do método GET, então os dados serão convertidos em query strings, e a propriedade processData previne esse comportamento.

Além dessas propriedades, temos algumas opções para a configuração de callbacks para alguns cenários. beforeSend permite efetuar algum processamento momentos antes da requisição ser enviada ao serviço. A opção success permite especificarmos um callback apontando para um método que deverá ser disparado quando o resultado voltar com sucesso. Já error também permite especificarmos um método a ser disparado quando algum problema acontecer no serviço. É importante dizer aqui que o tratamento de erro não será tão simples, pois o WCF não traduz automaticamente a exceção em um erro no formato JSON, o que dificulta para mostrar a mensagem de erro. Finalmente, temos um callback chamado de complete, que como o próprio nome diz, é disparado quando a requisição é finalizada, independemtente se ocorreu ou não alguma exceção durante o seu processamento.

Abaixo temos como podemos configurar a função $.ajax para executarmos a primeira operação fornecida pelo serviço WCF que criamos anteriormente, que é a RecuperarUsuario. Como o acesso deve ser feito através do método POST, então os parâmetros serão enviados no corpo da mensagem, em formato JSON. Do lado do serviço, o WCF consegue interpretar o objeto JSON que foi enviado, extrair cada propriedade e preencher cada um dos parâmetros exigidos pela operação.

function RecuperarUsuario() {
    $.ajax(
    {
        type: “POST”,
        url: “http://localhost/Services/ServicoDeUsuarios.svc/RecuperarUsuario&#8221;,
        contentType: “application/json”,
        data: ‘{ “nome”: “Israel”, “email”: “ia@israelaece.com” }’,
        processData: false,
        success:
            function (resultado) {
                alert(resultado.RecuperarUsuarioResult.Nome);
                alert(resultado.RecuperarUsuarioResult.Email);
            },
        error:
            function (xhr, textStatus, errorThrown) {
                alert(‘Algum Problema Ocorreu!’);
            }
        });
    }

É importante perceber que configuramos (no contrato) o corpo da mensagem para o método RecuperarUsuario como Wrapped, e que isso nos obrigará a acessar o resultado através do objeto que envolve as propriedades do usuário, e que é criada automaticamente pelo JSON, que neste caso é chamada de RecuperarUsuarioResult.

Já a segunda operação exposta pelo serviço WCF, que retorna uma coleção de usuários, vamos acessá-la através do método GET, e ao receber o resultado, vamos iterar pela coleção, acessando elemento a elemento mostrando as propriedades Nome e Email de cada usuário retornado pelo serviço. É importante perceber aqui que estamos acessando diretamente as propriedades, sem passar por aquele elemento que é gerado pelo JSON. Isso se deve ao fato de termos configurado a respectiva operação como Bare, que evita envolver o resultado neste membro extra.

function RecuperarUsuarios() {
    $.ajax(
    {
        type: “GET”,
        url: “http://localhost/Services/ServicoDeUsuarios.svc/RecuperarUsuarios&#8221;,
        success:
            function (usuarios) {
                $.each(usuarios, function (indice, usuario) {
                    alert(usuario.Nome + “: ” + usuario.Email);
                })
            }
        });
    }

Finalmente temos o método AdicionarUsuario, que recebe como parâmetro a instância da classe Usuario e o adiciona em algum repositório. O usuário é criado utilizando a sintaxe JSON, onde configuramos cada propriedade e seu respectivo valor através de uma espécie de dicionário. Só que o jQuery não traz nativamente funções para representar o objeto em formato de string, algo que é necessário para enviá-lo até o serviço. Ao invés de fazer todo o trabalho árduo para essa transformação, podemos recorrer à uma biblioteca fornecida através do site oficial do JSON, chamada de JSON2.js. Essa biblioteca fornece dois métodos para a manipulação do JSON, sendo eles: parse e stringify. O método parse retorna o objeto devidamente reconstruído a partir de uma estrutura JSON, enquanto o método stringify retorna uma string contendo representação JSON de um determinado objeto. É justamente o resultado deste segundo método que estamos enviando ao serviço:

function AdicionarUsuario() {
    var usuario = { “Codigo”: 123, “Nome”: “Israel”, “Email”: “ia@israelaece.com” };

    $.ajax(
    {
        type: “POST”,
        url: “http://localhost/Services/ServicoDeUsuarios.svc/Adicionar&#8221;,
        contentType: “application/json”,
        data: JSON.stringify(usuario),
        processData: false,
        success:
            function (resultado) {
                alert(‘Usuário adicionado com sucesso.’);
            }
        });
    }

Apenas atente-se que para este código funcionar, precisamos fazer o download do arquivo json2.js e referenciá-lo na página, como vemos abaixo:

http://Scripts/json2.js

Conclusão: Consumir serviços a partir de AJAX pode tornar a experiência do usuário muito melhor, já que evita a necessidade de ter efetuar a atualização completa da página. Isso já era uma necessidade, mas o jQuery torna isso muito mais simples, onde mesmo utilizando funções de baixo nível como vimos aqui, a tarefa acaba sendo muito mais simples de se realizar.