29 janeiro, 2008

Integrando Silverlight 1.1 com Web Services ASP.NET 2.0

O objetivo desse post é descrever os passos necessários para desenvolver uma aplicação em Silverlight 1.1 que utilize um Web Service feito em ASP.NET 2.0. As motivações para isso são bem simples:

1 - Há muitos web sites desenvolvidos utilizando ASP.NET 2.0 e algumas empresas têm um processo burocrático para instalar novas versões de aplicativos (como o .NET Framework 3.0 ou 3.5).

2 - O Silverlight 1.1 tem uma série de limitações que se tornam mais evidentes quando se tenta utilizar um web service desenvolvido em ASP.NET 2.0.

Como o primeiro argumento é auto explicativo, vamos para as limitações do Silverlight 1.1.

Não é possível acessar conteúdo cross-domain, ou seja, não dá para acessar web services ou fazer downloads de sites hospedados em um domínio diferente da aplicação Silverlight. Essa limitação existe por uma questão de segurança.

O Silverlight só é capaz de se comunicar com web services utilizando o protocolo JSON. Ou seja, os seus web services atuais não podem ser acessados pelo Silverlight. Essa limitação existe devido ao fato de o Silverlight utilizar a infraestrutura do aplicativo host (o browser do usuário) para acessar o conteúdo. O web service então é acessado do mesmo modo que os seus aplicativos AJAX já fazem hoje.

Até aqui nada demais, até que você tenta desenvolver e descobre que, apesar de ter conseguido fazer a web reference sem problemas no silverlight, o seu aplicativo não funciona. Segue abaixo um passo a passo para que você possa criar um aplicativo web para hospedar o aplicativo Silverlight 1.1 e o web service que será utilizado por ele. Esse roteiro foi o que eu utilizei para desenvolver o aplicativo apresentado no TechEd 2007 do qual falei no post anterior. Para seguir o passo a passo será necessário ter o Visual Studio 2008 Standard ou superior instalado, além do toolkit do Silverlight 1.1.

Abra o Visual Studio 2008 e crie um novo Web Aplication ASP.NET 2.0. Isso também pode ser feito utilizando um Web Site.

1 

Adicione um web service ao site. Para que o web service funcione via JSON, é necessário adicionar os atributos ScriptService e ScriptMethod no código, conforme mostrado abaixo, mas para isso será necessário fazer referência ao assembly System.Web.Extensions.

2

3

Ainda falta um detalhe para que o seu web service possa ser acessado via JSON. Esse foi justamente o detalhe que me deu mais problemas para descobrir. É necessário acrescentar algumas informações no web.config para que o handler de web service do assembly System.Web.Extensions seja utilizado ao invés no handler padrão. É ele que vai interpretar toda a comunicação do seu web service com os aplicativos clientes a partir de agora, proporcionando o uso do protocolo JSON e, consequentemente, possibilitando o acesso pelo Silverlight. Basta acrescentar as linhas abaixo na seção system.web do seu arquivo web.config:

<httpHandlers>
    <remove verb="*" path="*.asmx"/>
    <add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</httpHandlers>

Agora o seu web service já está pronto para ser acessado pelo Silverlight. Então vamos a ele. Adicione um novo aplicativo Silverlight 1.1 à solução.

4

Agora adicione uma web reference no aplicativo Silverlight para o web service recém criado.

5

Adicione um campo texto no xaml com o código abaixo:

<TextBlock x:Name="txtResultado" />

Agora falta pouco. Edite o evento Page_Load do arquivo Page.xaml.cs e acrecente a chamada ao web service como abaixo:

public void Page_Loaded(object o, EventArgs e) {
    // Required to initialize variables
    InitializeComponent();
    ChamarServico();
}

private void ChamarServico() {
    var servico = new Servico.Servico();
    txtResultado.Text = servico.HelloWorld();
}

Agora é necessário vincular o aplicativo web com o aplicativo silverlight. Para isso, primeiro é necessário compilar a sua solução para que todos os arquivos necessários sejam gerados. Depois, clique com o botão direito no aplicativo web e escolha a opção "Add Silverlight Link". Em seguida aparecerá uma janela para escolher o aplicativo silverlight que será vinculado. Depois aparecerá uma janela perguntando se você quer habilitar o debug para aplicação Silverlight recém vinculada.

Depois de feito o vínculo, você poderá notar que foi criada uma pasta chamada ClientBin, onde foram colocadas uma dll e um pdb. Esses arquivos são o código do seu aplicativo Silverlight já devidamente compilado e o arquivo de símbolos, necessários apenas para permitir o debug do aplicativo Silverlight. Além disso, foi adicionado também o arquivo Page.xaml, referente à tela principal da sua aplicação Silverlight.

Agora tudo o que você precisa fazer é adicionar o aplicativo Silverlight à uma página web, da mesma forma que faria com um aplicativo ou banner feito em Flash. Há vários jeitos de fazer isso (e eu vou abordar em mais detalhes em outro post), mas no momento o que eu vou fazer é copiar o código existente na página de testes que está no projeto do aplicativo Silverlight.

Em detalhes, o que eu fiz foi copiar o código abaixo para a página Default.aspx do aplicativo web. Depois copiei os 2 javascripts do projeto Silverlight para o projeto web e fiz referencia a eles na página Default.aspx.

<div  id="SilverlightControlHost" class="silverlightHost" >
    <script type="text/javascript">
        createSilverlight();
    </script>   
</div>

Agora é só teclar F5 e testar. Se estiver tudo certo, deverá aparecer o texto "Hello World" no seu browser. Se você clicar com o botão direito do mouse, verá que o texto está no Silverlight.

Agora algumas dicas para aperfeiçoar a utilização de sua aplicação silverlight com web services:

1 - Crie uma classe facade para acessar o web service. Eu costumo criar classes estáticas para esse fim. Nessa classe, crie um método público para cada método do web service e um método privado que irá instanciar a web reference. Com isso, em todos os pontos da sua aplicação onde for necessário acessar o web service, bastará chamar um desses métodos estáticos que ele se encarregará de instanciar a web reference e fazer a chamada ao método.

2 - Silverlight não "gosta" de métodos void em web service. Eu não sei dizer direito o motivo disso mas, se você criar um método void no seu web service e chamar a partir do Silverlight, o método será executado com sucesso mas será lançada uma excessão no Silverlight. Eu consegui contornar isso fazendo chamadas assincronas aos métodos void (como não há retorno, o comportamento da aplicação não muda). Como a minha aplicação utiliza apenas a classe facade, só é necessário mudar em 1 lugar. Você também pode contornar isso alterando o web service para que não tenha mais métodos void. Eu achei mais elegante fazer a chamada assíncrona pois preserva o código original do web service.

3 - Informe a Url relativa do web service antes de chamar qualquer método. Se você não fizer isso, o seu projeto só irá funcionar localmente pois o seu aplicativo Silverlight vai tentar chamar um web service em uma url semelhante a "http://localhost:49571/Servico.asmx", que com certeza não vai funcionar em produção. No código desse aplicativo de testes, bastaria acrescentar a linha "servico.Url = "Servico.asmx";" para que o aplicativo funcione em qualquer lugar (local ou publicado em servidor). Pode ser qualquer Url relativa a raiz do site. Se você fizer a classe facade, só terá que fazer essa alteração da url em 1 lugar.

Espero que esse post seja útil para os seus estudos de Silverlight 1.1. Talvez algumas implementações utilizadas nesse exemplo tenham que ser alteradas quando a versão 2.0 do Silverlight for lançada, assim como algumas limitações podem mudar. Seja como for, já dá para ter uma boa noção de como funciona e o que é necessário para começar a estudar e viabilizar novas formas de interação com os usuários dos seus aplicativos.

Se alguém tiver interesse nos códigos fontes utilizados para escrever esse artigo, basta deixar um comentário que eu envio por email.

Até o próximo post.