WCF Tooling

by Israel Aece 27. August 2010 07:59

A criação de serviços WCF envolve a construção de um contrato (interface), e depois a classe que o representará. Em seguida, para podermos expor ele para que os clientes possam consumir, precisamos utilizar algum host. Isso exige a configuração dos endpoints, behaviors, bindings, etc., e isso pode ser feito de forma imperativa ou declarativa.

Se tivermos toda a implementação pronta (a interface do contrato e a classe do serviço), podemos recorrer à algumas ferramentas que o WCF fornece, evitando assim escrever código para hospedar e/ou consumir o serviço. Utilizando essas ferramentas nos permite avaliar o comportamento, talvez analisar a performance, e tudo isso, sem a necessidade de gastar tempo configurando o servidor (o IIS por exemplo) ou criar um código para consumir o serviço. Para nos auxiliar, temos três ferramentas, que estão descritas abaixo:

  • Service Configuration Editor: Este editor fornece uma interface gráfica para efetuarmos a configuração do serviço WCF, e que resultará na criação ou edição de um arquivo de configuração (App.config ou Web.config). Ele exigirá que você informe em qual assembly está o serviço, identificará o(s) contrato(s) que ele implementa, e depois disso, você configura os endpoints, bindings, behaviors, etc., tudo de acordo com a sua necessidade.
  • WCF Service Host: Este utilitário recebe como parâmetro o assembly que contém o serviço e seu contrato. Além disso, um segundo parâmetro (que também é obrigatório), é o arquivo com extensão *.config onde está contida todas as configurações daquele serviço.
  • WCF Test Client: Este utilitário tem a finalidade de simular um cliente, para que você consiga efetuar o consumo do serviço sem a necessidade de criar uma aplicação para isso. Ele recebe como parâmetro o endereço do documento WSDL, e com isso, irá extrair todas as informações e criará um formulário para que possamos informar os eventuais parâmetros para as operações, e depois exibirá o resultado.

Essas ferramentas já são conhecidas. Quando você cria um projeto utilizando a template WCF Service Library, ao rodá-la, verá que ambos utilitários serão inicializados para testar o serviço. Através das imagens abaixo, podemos visualizar o serviço sendo configurado pelo Service Configuration Editor. Em seguida, ele sendo hospedado no WCF Service Host e, finalmente, o WCF Test Client que irá consumi-lo.

O editor nós podemos acessá-lo diretamente através do Visual Studio, clicando em cima do arquivo de configuração correspondente, e em seguida, na opção Edit WCF Configuration. Se quiser acessar diretamente, você pode recorrer ao menu Tools e depois WCF Service Configuration Editor. Já os outros utilitários estão disponíveis através do prompt de comando do próprio Visual Studio. Abaixo temos a utilização de cada um deles:

C:\>WcfSvcHost /service:C:\Temp\MeuServico.dll /config:C:\Temp\MeuServico.dll.config
C:\>WcfTestClient http://localhost:8383/?wsdl

É importante dizer que esses utilitários não funcionam em alguns cenários, como por exemplo, quando utilizamos callbacks. Neste caso, a única saída será recorrer a criação de um projeto para o consumo deste serviço.

Tags:

WCF

Comunicação Local no Silverlight

by Israel Aece 23. August 2010 13:29

Como sabemos, podemos consumir serviços WCF em aplicações Silverlight. Isso nos permite colocar alguma tarefa em um serviço na aplicação que faz a hospedagem do serviço ou até mesmo em outros locais, fora do domínio qual ela se encontra. A ideia aqui é permitir a comunicação entre a aplicação Silverlight (que roda dentro do navegador) e serviços que estão hospedados além dessa máquina.

Mas e se precisarmos de algo mais simples, como por exemplo, a comunicação entre duas aplicações Silverlight que rodam dentro do navegador em uma mesma máquina? Utilizar o WCF aqui pode ser extremamente complicado, pois exigirá desenvolvermos uma série de funcionalidades para permitir esse interação, e ainda podemos ter um grande overhead, já que a comunicação não será local e dependerá de que a conexão esteja disponível com o servidor/serviço com qual queremos dialogar.

Para esse tipo de cenário o Silverlight fornece algo bem mais simples de se trabalhar, que é uma funcionalidade conhecida como "comunicação local". A ideia aqui é criar aplicações que geram informações, e aquelas que estiverem interessadas, podem capturá-las e tratar da forma que achar mais conveniente. Esse tipo de comunicação pode ser utilizada por plugins que rodam dentro da mesma página, em páginas diferentes, estando ou não dentro do mesmo domínio.

Através das imagens abaixo podemos analisar os cenários mais comuns. Na primeira imagem (1) temos uma única página ASPX hospedando duas aplicações Silverlight, e se precisarmos efetuar a comunicação entre elas, podemos utilizar o recurso que veremos aqui. Já na segunda imagem (2), temos duas página distintas dentro de um mesmo domínio, mas cada página hospeda uma aplicação Silverlight diferente, e da mesma forma, a comunicação também será possível. Na terceira (3) e última imagem, temos duas aplicações, mas cada uma delas está hospedada em um domínio diferente, mas isso também pode ser permitido, mas falaremos mais disso abaixo.

A implementação é relativamente simples. Para utilizarmos a comunicação local entre aplicações Silverlight, vamos recorrer aos tipos que estão disponível a partir do namespace System.Windows.Messaging. As principais classes que teremos aqui são: LocalMessageSender e LocalMenssageReceiver. Como podemos perceber, a primeira classe é responsável por enviar mensagens, enquanto a segunda se encarrega de receber tais mensagens.

Aqui é importante comentarmos sobre algumas "limitações": tudo o que podemos mandar de um lado à outro deve ser, obrigatoriamente, uma string. Qualquer coisa diferente disso, exigirá um trabalho extra, como serializar o objeto em algum formato Xml ou Json. Dependendo da quantidade de informação que você levar de um lado para outro, considere o uso do Json ao invés do Xml, que é bem menos verboso, e isso pode evitar você atingir o limite máximo do tamanho da string, que deve ser menor ou igual a 40KB. Uma outra alternativa aqui é serializar as informações em formato binário e utilizar Base64 para codificá-la.

Se vamos gerar uma aplicação que gera informações, então temos que recorrer ao uso da classe LocalMessageSender. Em seu construtor ela recebe uma string que corresponde ao nome do destinatário das mensagens geradas por ela. Já o segundo parâmetro do construtor desta classe, recebe uma string contendo o domínio que receberá as mensagens. Você pode utilizar o membro estático chamado Global desta mesma classe, que corresponde à um "*", e instrui o Silverlight que qualquer domínio poderá receber as mensagens. Finalmente, essa mesma classe fornece o método chamado SendAsync, que permite o envio de uma string para aqueles que desejarem capturá-la.

Chega o momento de efetuar a configuração do destinatário. Agora entra em cena a classe LocalMessageReceiver, que recebe em seu construtor três parâmetros: uma string com o nome do destinatário, uma das opções do enumerador ReceiverNameScope e, finalmente, uma coleção de strings, que representa os domínios de quais a aplicação poderá receber mensagens. Essa classe fornece um evento chamado MessageReceived, que é disparado quando uma nova mensagem chega para a aplicação, e para capturá-la, tudo o que precisamos fazer é nos vincularmos a este evento e acessar a mensagem através da propriedade Message do argumento MessageReceivedEventArgs. Para finalizar, o método Listen é responsável por começar a monitorar as mensagens que chegam e entregá-las para o evento acima.

Depois de conhecer essas classes, podemos já fazer o uso delas nas nossas aplicações. Para exemplificar, teremos duas aplicações Silverlight, hospedadas em locais diferentes. A ideia será permitir a comunicação entre elas, e para manter a simplicidade do exemplo, tudo o que a aplicação fará ao receber a mensagem, será colocá-la em um TextBox. Abaixo temos a configuração de uma das aplicações, utilizando tudo o que vimos acima:

public partial class MainPage : UserControl
{
    private LocalMessageSender sender;
    private LocalMessageReceiver receiver;

    public MainPage(string aplicacaoLocal, string aplicacaoRemota)
    {
        InitializeComponent();

        this.sender = new LocalMessageSender(aplicacaoRemota, LocalMessageSender.Global);
        this.receiver = new LocalMessageReceiver(
            aplicacaoLocal, ReceiverNameScope.Global, LocalMessageReceiver.AnyDomain);

        this.receiver.MessageReceived += 
            new EventHandler<MessageReceivedEventArgs>(receiver_MessageReceived);
        this.receiver.Listen();
    }

    private void receiver_MessageReceived(object sender, MessageReceivedEventArgs e)
    {
        this.Mensagens.Text += string.Format("{0}{1}", e.Message, Environment.NewLine);
    }

    private void EnviaMensagem_Click(object sender, RoutedEventArgs e)
    {
        this.sender.SendAsync(this.Mensagem.Text);
    }
}

O código da outra aplicação será exatamente igual. O único detalhe ali é o construtor da classe MainPage, que recebe como parâmetros o nome local e o nome remoto. O nome remoto é utilizado no construtor da classe LocalMessageSender, pois quero enviar mensagens para este destino. Já o nome local é utilizado pelo LocalMessageReceiver, que é de onde estou interessado em receber mensagens. Mais detalhes sobre estes parâmetros na próxima seção do artigo.

Com isso em funcionamento, ao rodar as aplicações já podemos perceber o resultado. Através da imagem abaixo, vemos que o conteúdo do TextBox da aplicação 01 foi para a aplicação 02 e vice-versa.

Parametrizando as Aplicações

Acima pudemos perceber que a classe que corresponde ao controle do Silverlight (MainPage), foi parametrizada com as duas informações, que correspondem de onde a aplicação quer receber e para onde ela quer enviar informações. Esses nomes não precisam, necessariamente, corresponder a nome de aplicações. A ideia é ter um nome coerente com o tipo de informação que está sendo gerada.

Outro detalhe importante é com relação ao nome que você define para o recebedor das mensagens, pois podemos ter a mesma aplicação carregada em outra instância do navegador, e ao definir o mesmo nome, uma exceção do tipo ListenFailedException será disparada para informar que já existe um recebedor registrado com este mesmo nome.

Para evitar isso, utilizaremos a "ponte" que existe entre o Silverlight e o código HTML que o hospeda. Isso permitirá gerarmos um valor randômico via Javascript e definir na inicialização do plugin, que será encaminhada para aqueles parâmetros que vimos no construtor da classe MainPage. Para que isso funcione, temos que adicionar um novo elemento <param /> na tag object que hospeda a aplicação Silverlight (*.xap), e nomear este parâmetro como initParams. O código abaixo ilustra a adição deste novo parâmetro, com algumas informações suprimidas por questões de espaço.

<object data="data:application/x-silverlight-2," type="application/x-silverlight-2">
    <param name="source" value="ClientBin/Aplicacao01.xap"/>
    <param
        name="initParams"
        value="AplicacaoLocal=Aplicacao01,AplicacaoRemota=Aplicacao02" />
    <!-- Outros Parâmetros -->
</object>

A configuração refere-se à aplicação 01. Para a aplicação 02, esses parâmetros estão invertidos, já que terão papéis diferentes.

Com isso, o valor colocado ali será entregue em formato de um dicionário ao evento Startup da classe Application, que estará acessível através do arquivo App.xaml. É neste momento que extraímos os parâmetros deste dicionário e preenchemos o construtor da classe MainPage, assim como podemos notar através do código abaixo:

private void Application_Startup(object sender, StartupEventArgs e)
{
    this.RootVisual = 
        new MainPage(e.InitParams["AplicacaoLocal"], e.InitParams["AplicacaoRemota"]);
}

Conclusão: Neste artigo vimos a utilização de uma técnica interessante que nos permite a comuicação local (no mesmo computador) de aplicações Silverlight. Podemos utilizar esse recurso para cada vez mais criar aplicações independentes, e se mais tarde, precisarmos de interação entre elas, podemos recorrer à este recurso simples, mas que traz um grande poder as mesmas.

ComunicaoLocalSL.zip (144.66 kb)

Tags:

CSD

Visualizador para JSON

by Israel Aece 19. August 2010 11:23

O JSON é um formato que temos para serializar informações, e que possibilita aplicações AJAX consumirem serviços de forma muito mais simples, dispensando todo o "overhead" do XML ou SOAP. É um formato relativamente simples, assim como podemos ver abaixo, onde temos um cliente e seus respectivos pedidos:

{"Codigo":123,"Email":"ia@israelaece.com","Nome":"Israel","Pedidos":[{"Codigo":1,"Data":"\/Date(1282228004105-0300)\/","Valor":1000},{"Codigo":2,"Data":"\/Date(1282228004144-0300)\/","Valor":129}]

Para facilitar a vida dos desenvolvedores, principalmente quando lidamos com a construção de serviços, que exigem a exposição de informações mais complexas do que essa mostrada acima, pode ser útil termos um visualizador para mostrar graficamente a estrutura do documento JSON. Para isso, podemos recorrer ao JSONViewer, uma ferramenta que não exige nenhuma instalação, e tudo o que você precisa fazer é rodá-la. Abaixo podemos ver a imagem do documento JSON acima, totalmente formatado e de forma gráfica.

Depois de baixar, com uma configuração simples, que você encontra no site do projeto, verá que podemos incorporá-lo ao Fiddler, para já monitorar serviços que retornam os resultados em formato JSON.

Tags: , ,

General

Analisando a exceção ContractException

by Israel Aece 15. August 2010 21:17

A partir de agora, durante a escrita do nosso código, podemos recorrer ao Code Contracts, que é uma biblioteca que está sendo desenvolvida pela Microsoft, e que permite trabalhar com condições e garantir com que elas sejam atendidas durante a execução ou até mesmo de forma estática. Caso alguma das regras impostas seja violada, uma exceção será disparada, caracterizando um bug no sistema que consome este componente. O uso desse novo recurso tende a diminuir consideravelmente o uso do código if-then-throw.

A exceção que é disparada é do tipo ContractException e, propositalmente, ela foi criada como internal. Isso evita que se crie tratadores de erro que capture este tipo de exceção, e com isso burle o processo de verificação que é realizado por essa biblioteca. A aplicação que consome a classe deve se preocupar apenas em capturar exceções tradicionais (ArgumentNullException, IndexOutOfRangeException, etc.), pois enquanto houver exceções do tipo ContractException sendo disparadas, provavelmente o consumidor não está passando as informações da forma correta.

Há alguns momentos em que gostaríamos de mudar este comportamento, como por exemplo, eliminar essa validação durante a escrita de algum teste (isso envolve outra discussão, que é TDD com DbC). Para exemplificar, considere o código abaixo, que possui uma condição pré (Requires) e outra pós (Ensures), que recorre ao Code Contracts para validar e garantir que as informações são passadas da forma correta para o método Creditar e também garante o estado da classe ContaBancaria, após a execução deste mesmo método.

public class ContaBancaria
{
    public decimal Saldo { get; private set; }

    public ContaBancaria(decimal saldo)
    {
        this.Saldo = saldo;
    }

    public void Creditar(decimal quantia)
    {
        Contract.Requires(quantia > 0, "A quantia para deposito deve ser maior que 0");
        Contract.Ensures(Contract.OldValue(this.Saldo) + quantia == this.Saldo);

        this.Saldo += quantia;
    }
}

Se criarmos um código para consumir essa classe e, consequentemente, efetuar um crédito com valor negativo, teremos uma exceção do tipo ContractException. Para contornar esse comportamento, podemos recorrer ao evento estático ContractFailed da classe Contract. Esse evento define o argumento do tipo ContractFailedEventArgs, que expõe alguns membros interessantes, e alguns deles estão listados abaixo:

  • Condition: Uma string com a condição que não foi atentida.
  • FailureKind: Uma das opções exposta pelo enumerador ContractFailureKind, indicando se é uma condição pré, pós ou invariante.
  • Message: Uma string que representa a mensagem que descreve o problema.
  • OriginalException: Retorna a instância da exceção que causou o evento, que é utilizado quando você utiliza métodos que, por questões de compatibilidade, dispara exceções diferentes de ContractException.
  • SetHandled: Método que quando invoca, suprime o disparo da exceção que violou o contrato.
  • SetUnwind: Ao contrário do método anterior, quando invocado ele dispara a exceção ContractException depois que o tratador do evento ContractFailed é encerrado.

Com os membros que vimos acima, podemos agora ter acesso ao tipo do problema que ocorreu, e ainda conseguir burlar o problema de verificação que é realizado pelo Code Contracts. Abaixo temos um exemplo de como podemos proceder para fazer isso funcionar, ou seja, invocando o método SetHandled para que erros que violam o contrato não sejam mais entregues para o código consumidor:

static void Main(string[] args)
{
    Contract.ContractFailed += (sender, args) =>
    {
        Console.WriteLine("{0} - {1}", args.FailureKind, args.Condition);
        args.SetHandled();
    };

    new ContaBancaria(1000).Creditar(-100);
}

Tags:

C#

Sessão e Operações One-way

by Israel Aece 12. August 2010 08:58

O WCF fornece várias tipos de mensagens, e entre eles, temos as operações one-way. Esse tipo de operação deve ser utilizado quando o cliente não precisa de qualquer retorno (resultado ou erro), uma espécie de fire-and-forget.

Esse tipo de mensagem pode ter um comportamento estranho quando exposto através de um binding que suporte sessões nativamente, como é o caso do NetTcpBinding. O protocolo TCP estabelece um canal duplex entre o cliente e o serviço, mantendo uma espécie de conexão ativa, onde a qualquer momento um pode tranquilamente se comunicar com o outro.

É importante dizer que mensagens one-way não são assíncronas, mas o tempo de entrega é tolerável. O maior problema, do qual falava anteriormente, refere-se ao fechamento do proxy depois da mensagem one-way disparada ao destinatário, ou seja, quando invocamos a operação one-way, tão logo já conseguimos continuar trabalhando na aplicação cliente, mas se tentarmos fechar o proxy, ficaremos bloqueados até que a operação one-way seja completamente finalizada. Mas se a ideia é disparar e esquecer, porque eu preciso esperar, mantendo o proxy aberto até finalizar a operação?

Para ter o comportamento fire-and-forget a sério, uma das alternativas que temos é habilitar as mensagens (ou sessões) confiáveis. Isso tornará a comunicação entre as partes muito mais descritiva, onde além das mensagens normais, ainda haverão uma porção de outras mensagens que são geradas pelo protocolo WS-ReliableMessaging, indicando se a mensagem foi entregue, quando ela foi entregue e a ordem de chegada, permitindo ao cliente continuar sem a necessidade de esperar. Para habilitar as mensagens confiáveis, consulte este artigo.

Apesar disso funcionar, a comunicação entre as partes ficará bem mais volumosa, já que várias mensagens de infraestrutura serão trocadas para garantir a entrega da mensagem principal. Para evitar todo este overhead causado pelo protocolo WS-ReliableMessaging, podemos recorrer a construção de um binding customizado, empilhando os vários elementos para compor a comunicação via TCP, mas com um detalhe, que é a adição de um novo elemento, chamado de OneWayBindingElement. A adição deste elemento fará com que o canal de comunicação se comporte semanticamente como um fire-and-forget. O código abaixo ilustra o seu uso, via código imperativo e declarativo, respectivamente:

private static Binding CreateOneWayTcpBinding()
{
    BindingElementCollection currentElements = new NetTcpBinding().CreateBindingElements();
    BindingElementCollection bindingElements = new BindingElementCollection();

    bindingElements.Add(new OneWayBindingElement());

    foreach (BindingElement be in currentElements)
        bindingElements.Add(be);

    return new CustomBinding(bindingElements);
}

<system.serviceModel>
  <bindings>
    <customBinding>
      <binding name="OneWayTcpBinding">
        <oneWay />
        <binaryMessageEncoding />
        <tcpTransport />
      </binding>
    </customBinding>
  </bindings>
</system.serviceModel>

Só que utilizar este procedimento possui dois detalhes importantes: o primeiro é que ao configurá-lo, o canal somente permitirá a comunicação através do modelo one-way, e com isso, o contrato que você está expondo obrigatoriamente precisa definir todas as operações neste mesmo modelo. Se tiver qualquer operação neste contrato do tipo request/reply, ao tentar subir o serviço, você irá se deparar com uma exceção do tipo InvalidOperationException, indicando justamente isso. Se você conseguir garantir com que todas as operações sejam one-way, então utilizar esta técnica pode trazer uma grande melhora em performance, quando comparado à opção anterior.

O segundo detalhe é com relação ao modelo de gerenciamento de instância. Mesmo que você diga ao serviço que ele deve ser PerSession, ele não conseguirá manter a sessão, ou seja, terá o comportamento do modelo PerCall, pois cada chamada para uma operação one-way encerrará a "sessão".

Tags: , ,

WCF

Omitindo tipos genéricos durante a construção

by Israel Aece 10. August 2010 22:38

Os Generics trouxeram um grande poder às linguagens .NET. O tipos genéricos podem ser utilizados por toda a classe onde ele está sendo criado e, consequentemente, podemos utilizar em seus construtores. O maior problema da criação de objetos que exigem um parâmetro genérico, é a necessidade de especificarmos esses tipos durante a sua construção, ou seja, o construtor não é capaz de inferir os tipos, o que torna o código um pouco ilegível. Para exemplificar, considere o seguinte código:

public class ProxyManager<TChannel, TBinding>
{
    private TChannel _channel;
    private TBinding _binding;

    public ProxyManager(TChannel channel, TBinding binding)
    {
        this._channel = channel;
        this._binding = binding;
    }

    //Outros Membros
}

Durante a sua criação, é necessário especificarmos os tipos genéricos para depois conseguir parametrizar o construtor com os valores efetivos. Se repararmos o código abaixo, note que não podemos omitir o que está entre os caracteres < e >, mesmo que construtores são uma espécie de método, eles não possibilitam a omissão dos mesmos, assim como acontece nos métodos genéricos.

var manager = 
    new ProxyManager<ServicoDeUsuariosClient, NetTcpBinding>(
        new ServicoDeUsuariosClient(), 
        new NetTcpBinding());

Para melhorar esse código e torná-lo mais simples de consumir a classe, podemos recorrer a criação de uma nova classe, que conterá um método estático que aceita exatamente os parâmetros genéricos exigidos pelo construtor da classe ProxyManager<TChannel, TBinding>, e o retorno será a própria classe criada, uma espécie de factory. O que acontece aqui é que todo o código burocrático acaba ficando dentro deste método.

public static class ProxyManager
{
    public static ProxyManager<TChannel, TBinding> Create<TChannel, TBinding>(TChannel channel, TBinding binding)
    {
        return new ProxyManager<TChannel, TBinding>(channel, binding);
    }
}

Com isso, a criação de um novo ProxyManager, se resume simplesmente ao código que vemos abaixo:

var manager = 
    new ProxyManager.Create(new ServicoDeUsuariosClient(), new NetTcpBinding());

Tags:

C#

Utilizando o Url Routing no WCF

by Israel Aece 4. August 2010 12:19

Quando recorremos à uma das templates para a construção de serviços WCF (WCF Service Application ou WCF Service), ambas utilizam arquivos *.svc que representam o endpoint do serviço. Dentro deste arquivo temos apenas uma diretiva chamada @ServiceHost, que instrui o ASP.NET a como compilar o referido serviço.

Abaixo podemos visualizar um exemplo deste arquivo, que em seu atributo Service, permite apontar o tipo do serviço. Já no atributo CodeBehind, corresponde ao arquivo físico que possui a classe que representa o serviço e, finalmente, temos a atributo Factory, que é omitido por padrão, mas que tem a finalidade de criar instâncias da classe que gerencia o serviço (ServiceHost ou alguma de suas derivadas).

<%@ ServiceHost
    Language="C#"
    Debug="true"
    Service="ServicoDeClientes"
    Factory="System.ServiceModel.Activation.WebServiceHostFactory"
    CodeBehind="~/App_Code/ServicoDeClientes.cs" %>

No WCF 4.0, a Microsoft incluiu a possibilidade de criarmos serviços WCF sem a necessidade da presença de um arquivo *.svc. Isso eliminará completamente a necessidade deste arquivo. Mas para poder excluir o arquivo, tudo o que precisamos fazer é elencar os serviços no arquivo Web.config, utilizando o sub-elemento serviceActivations, exposto pelo elemento serviceHostingEnvironment:

<system.serviceModel>
  <serviceHostingEnvironment>
    <serviceActivations>
      <add
        relativeAddress="~/ServicoDeClientes.svc"
        service="Servicos.ServicoDeClientes"
        factory="System.ServiceModel.Activation.WebServiceHostFactory"/>
    </serviceActivations>
  </serviceHostingEnvironment>
</system.serviceModel>

Apesar de ainda precisar especifcar o arquivo no relativeAddress, ele não existe fisicamente. Note também que através do atributo service definimos o nome da classe que corresponde ao serviço e, finalmente, como já era de se esperar, podemos utilizar uma factory específica, que já configura o host com tudo o que é necessário para prepará-lo para receber e processar as requisições para uma determina situação. Com isso temos uma aplicação mais simples, onde tudo o que precisamos desenvolver é o contrato (interface) e o serviço (classe), assim como já fazemos com qualquer outro tipo de serviço WCF.

O maior problema desta técnica é a necessidade de ainda precisar informar a extensão do arquivo quando for efetuar uma requisição, e isso não é legal em um modelo REST. Lembre-se de que a funcionalidade que vimos acima, apenas elimina a necessidade do arquivo físico. Remover a extensão *.svc do atributo relativeAddress, não resolverá, pois vamos nos deparar com uma exceção do tipo ConfigurationErrorsException, dizendo que o valor informado no atributo relativeAddress não possui uma extensão válida.

Além do Url Rewrite Module (que já discuti no final deste artigo), temos agora a possibilidade de integrar o sistema de roteamento de URL do ASP.NET aos serviços WCF. Também na versão 4.0 do WCF, a Microsoft incluiu no assembly System.ServiceModel.Activation uma classe chamada ServiceRoute, que permite especificarmos exatamente os mesmos parâmetros que vimos acima e, automaticamente, será processado pelo handler correspondente (ServiceRouteHandler). Com isso, no evento Application_Start do arquivo Global.asax, devemos registrar mais uma rota, essa específica para o nosso serviço:

protected void Application_Start(object sender, EventArgs e)
{
    RouteTable.Routes.Add(
        new ServiceRoute(
            "ServicoDeClientes",
            new WebServiceHostFactory(), 
            typeof(Servicos.ServicoDeClientes)));
}

A string que aparece sendo informada no construtor da classe ServiceRoute, define o nome do recurso para qual estaremos efetuando o roteamento. Os outros dois parâmetros refletem as mesmas configurações que vimos acima. Mas ainda é precisa se atentar a um detalhe: se você estiver utilizando um projeto que não vem com o módulo de roteamento de URL configurado, você terá que fazer isso manualmente, assim como eu mostro abaixo:

<system.web>
  <httpModules>
    <add
      name="UrlRoutingModule"
      type="System.Web.Routing.UrlRoutingModule, System.Web" />
  </httpModules>
</system.web>

O único detalhe aqui é a necessidade de habilitar o modelo de compatibilidade com o ASP.NET, caso contrário, esta funcionalidade não poderá ser utilizada. Para habilitar isso no contrato, precisamos recorrer ao atributo AspNetCompatibilityRequirementsAttribute, definindo-o como Allowed (para permitir que ele seja exposto por outros tipos de hosts), e depois devemos habilitar a compatibilidade no arquivo de configuração, através do elemento serviceHostingEnvironment, definindo o atributo aspNetCompatibilityEnabled como True. Abaixo é exibido as duas configurações:

namespace Servicos
{
    [AspNetCompatibilityRequirements(
        RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class ServicoDeClientes : IServico
    {
        //...
    }
}

<system.serviceModel>
  <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>

Depois destas configurações, já podemos acessar o serviço diretamente sem informar a extensão *.svc. É importante dizer que isso só é necessário quando você hospeda o seu serviço no IIS, já que as requisições são sempre realizadas para um arquivo físico. Quando você cria um serviço REST e deseja expor através de algum outro host, nada disso será necessário.

Tags: ,

WCF

TechEd Brasil 2010 - Palestras

by Israel Aece 3. August 2010 23:12

Nos dias 13, 14 e 15 de Setembro, haverá em São Paulo o evento TechEd 2010. Este evento reune uma grande quantidade de palestras voltadas para as tecnologias mais atuais, e além disso, vários profissionais que trabalham com tecnologias Microsoft. Neste ano, estarei efetuando duas palestras, quais estão listadas abaixo, seguida de sua respectiva descrição:

Título: Visão Geral do Windows Identity Foundation (WIF)
Código: SIA303
Palestrante: Israel Aece
Nível: 300
Descritivo: Autenticação e Autorização são duas preocupações que existem em toda e qualquer aplicação. Dependendo do tipo de aplicação que está sendo construída, há uma forma diferente de você implementar essas funcionalidades, que exige o conhecimento específico da respectiva API que cada uma fornece, e como se isso não bastasse, ainda precisamos nos atentar a alguns detalhes que são comuns para qualquer situação, o que pode tornar certos aspectos redundantes. A finalidade desta palestra é abordar o novo framework da Microsoft chamado Windows Identity Foundation (WIF), qual podemos acoplar as nossas aplicações, para tornar essas tarefas árduas em algo bem mais simples.

Título: Implementando Serviços RESTful usando o Microsoft .NET Framework
Código: DEV305
Palestrante: Israel Aece
Nível: 300
Descritivo: Nesta sessão, aprenda como desenvolvedores .NET podem reutilizar seu conhecimento do Windows Communication Foundation (WCF) para aproveitar as ferramentas integradas e extensibilidade de um framework de WCF único, incluindo WCF WebHttp Services para RESTful Services, WCF Data Services e OData e WCF RIA Services para o desenvolvimento do início ao fim de aplicações Microsoft Silverlight.

Tags: , , ,

WCF | WIF

Powered by BlogEngine.NET 1.5.0.0
Theme by Mads Kristensen

Sobre

Meu nome é Israel Aece e sou especialista em tecnologias de desenvolvimento Microsoft, atuando como desenvolvedor de aplicações para o mercado financeiro utilizando a plataforma .NET. [ Mais ]

Twitter

Host