Chamada do Servidor para Silverlight 3 com WCF Duplex
Recentemente me deparei com a situação onde o servidor precisava enviar dados a um cliente Silverligh, primeiramente pensei em fazer utilizando um timer no cliente onde de tempos em tempos ele fazia uma chamada no servidor e o servidor retornava os dados caso houvessem, mas devido ao alto tráfego de dados que teríamos na rede e pela quantidade de acessos de clientes no sistema essa solução foi descartada e então ficou o desafio, essa chamada deveria ser feita pelo servidor assim não teríamos chamadas desnecessárias e só haveria a troca de mensagens entre servidor e cliente nos momentos em que realmente houvessem dados para serem trafegados.
A Solução veio com o uso de WCF Duplex que nos permite fazer chamadas assíncronas do servidor para o cliente Silverlight.
Benefícios
Você reduz a carga no servidor, em vez dos clientes fazerem chamadas múltiplas periodicamente, enviamos os dados do servidor para os clientes como e quando quisermos.
Podemos eliminar ou reduzir a defasagem de dados em aplicações sensíveis ao tempo. Isto pode ser muito importante para aplicações que necessitam de alterações de dados para mostrar como eles acontecem.
Todos os clientes recebem atualizações ao mesmo tempo.
Existe um aplicativo de exemplo agradável de Mix09 disponível http://code.msdn.microsoft.com/silverlightws/Release/ProjectReleases.aspx?ReleaseId=2401 que cria um bate-papo, bem como um exemplo de chamadas do servidor. Sendo assim um exemplo mais simples seria melhor para nos familiarizarmos com isso, juntamente com um pouco mais explicação. Entretanto iremos utilizar a classe genérica DuplexService que foi criada neste projeto.
O que nossa aplicação vai fazer
Queremos um exemplo simples, e é isso que vamos obter. O servidor irá periodicamente enviar uma mensagem "LiveDataMessage" para qualquer cliente Silverlight que esteja conectado, e o cliente irá exibi-la. Não estou preocupado com os dados no servidor, apenas como enviá-lo para o cliente uma vez que o temos.
Veja como será a estrutura do projeto

Criando o projeto
Primeiro crie um novo projeto do Silverlight, vamos chamá-lo DuplexExample e não esqueça de incluir um Asp.Net Web Application com o nome padrão (DuplexExample.Web). No site Web Adicione uma referência para o System.ServiceModel.PollingDuplex.

Agora no projeto Silverlight também adicione uma referência para System.ServiceModel.PollingDuplex.

Baixe o exemplo Duplex http://code.msdn.microsoft.com/silverlightws/Release/ProjectReleases.aspx?ReleaseId=2401, extraia e copie o arquivo DuplexService.cs para seu web site.
Criando o serviço
Agora poderíamos dicionar um serviço WCF usando os modelos do Visual Studio, mas isso iria cria um monte de coisas que não precisamos que apenas temos que apagar depois, sendo assim, basta adicionar um arquivo de texto e chamá-lo de LiveDataService.svc. Isso nos dará um arquivo em branco no qual você pode adicionar o seguinte:
A única diferença aqui para o conteúdo de um arquivo normal svc é o fato de que não há CodeBehind especificado e sim de forma explícita uma classe Factory. (Veja aqui mais detalhes sobre estas opções: http://msdn.microsoft.com/en-us/library/aa967286.aspx) Desde que tenha especificado uma LiveDataService para nosso serviço e classe LiveDataServiceFactory que será usado para instanciar o serviço de fábrica, vamos ter que ir e criar esses.
Mas antes de fazer isso precisamos de uma classe DataContract chamada LiveDataMessage, esta é a classe simples que o nosso serviço vai enviar para o Silverlight.
[DataContract]
public class LiveDataMessage: DuplexMessage
{
[DataMember]
public int Value { get; set; }
[DataMember]
public string Description { get; set; }
}
Ok, então agora podemos criar nosso "LiveDataService", adicione uma classe no seu web site chamada LiveDataService.cs e adicione o seguinte código. Esta é bem simples, estamos usando um timer para enviar uma mensagem a todos os clientes a cada 5 segundos.
using System;
usingMicrosoft.Silverlight.Cdf.Samples.Duplex;
usingSystem.Threading;
namespace DuplexExample.Web
{
public class LiveDataService :DuplexService
{
Timer liveDataTimer;
public LiveDataService()
{
//Set up uma atualização a cada 5 segundos
this.liveDataTimer = newTimer(newTimerCallback(LiveDataUpdate),null, 0, 5000);
}
void LiveDataUpdate(objecto)
{
LiveDataMessage liveDataMessage = newLiveDataMessage()
{
Description = “Live Data at “+ DateTime.Now.ToLongTimeString(),
Value = newRandom().Next(0, 100)
};
PushToAllClients(liveDataMessage);
}
}
}
A Classe DuplexService
Você vai notar que a classe LiveDataService herda da DuplexService que nós adicionamos ao nosso projeto.

Esta classe também é deve ser marcada com o atributo InstaceContextMode igual a Single, desta forma o serviço pode acompanhar os clientes que estão conectados, porque ela permanece na memória e não é descartada.

Ok, então o DuplexService fornece a abundância da bondade de graça, porém existe uma coisa que precisamos alterar neste arquivo - você já deve ter notado que ele não está compilando. Lá no fundo você verá uma lista de KnownTypes. Estes relacionados para o projeto de exemplo que você baixou e não o que nós queremos. Nós temos somente uma KnownType específica (para além do Conectar e desconectar) chamou LiveDataMessage.
Agora, você precisa fazer a seguinte alteração no arquivo DuplexService.cs (na parte inferior):

A classe LiveDataServiceFactory
Finalmente adicionamos a classe LiveDataServiceFactory, que herda da classe DataServiceFactory no arquivo DuplexService.cs (isso é tudo o que faremos nesta classe)
namespace DuplexExample.Web
{
public class LiveDataServiceFactory : DuplexServiceFactory<LiveDataService> {}
}
Veja que a classe DuplexServiceFactory também herda do arquivo DuplexService.cs, você verá que ele fornece a configuração para o serviço com um custom binding (esta é uma da alternativa de configuração para conserguirmos fazer o Servicço Duplex)

O Projeto Silverlight
Conpile sua solução, em seguida, adicione o serviço de referência do LiveDataService no projeto Silverlight:

Eu criei uma interface bem simples, apenas um Botão e um Listbox:
<Grid x:Name="LayoutRoot" Background="White"> <Grid.RowDefinitions> <RowDefinition Height="75"/> <RowDefinition Height="225"/> Grid.RowDefinitions> <Button Content="Connect" Click="ButtonConnect_Click" x:Name="ButtonConnect" Margin="10"> Button> <ListBox Grid.Row="1" ScrollViewer.VerticalScrollBarVisibility="Visible" x:Name="ListBox1"> ListBox> Grid>

Aqui está todo o código da MainPage.Xaml.cs. Dê uma olhada e então vamos discutir o assunto:
public partial class MainPage : UserControl {
DuplexServiceClient receiver;
ObservableCollection<string> liveDataMessages =
new ObservableCollection<string>();
CustomBinding binding = new CustomBinding(
new PollingDuplexBindingElement(),
new BinaryMessageEncodingBindingElement(),
new HttpTransportBindingElement()
);
public MainPage()
{
InitializeComponent();
ListBox1.ItemsSource = liveDataMessages;
//make sure the endpoint address is correct receiver = new DuplexServiceClient(binding,
new EndpointAddress("http://localhost:6719/LiveDataService.svc"));
receiver.SendToClientReceived += (sender, e) =>
{
if (e.msg is LiveDataMessage)
{
LiveDataMessage msg = (LiveDataMessage)e.msg;
liveDataMessages.Add(string.Format("{0}. Value = {1}", msg.Description, msg.Value));
}
};
}
bool connected = false;
private void ButtonConnect_Click(object sender, RoutedEventArgs e)
{
if (connected)
{
Disconnect();
}
else {
Connect();
}
}
private void Connect()
{
ButtonConnect.Content = "Connecting...";
receiver.SendToServiceCompleted += (sender, e) =>
{
ButtonConnect.Content = "Connected (click to disconnect)";
connected = true;
};
receiver.SendToServiceAsync(new ConnectMessage());
}
private void Disconnect()
{
ButtonConnect.Content = "Disconnecting...";
receiver.SendToServiceCompleted += (sender, e) =>
{
ButtonConnect.Content = "Disconnected (click to connect)";
connected = false;
};
receiver.SendToServiceAsync(new DisconnectMessage());
}
}
No topo deste código, podemos declarar 3 variáveis: o DuplexServiceClient, um CustomBinding (que corresponde ao binding do serviço que criamos no servidor) e um ObservableCollection para armazenar as mensagens que recebemos do servidor. Vamos instanciar o DuplexServiceClient no construtor da classe usando o custom binding e o endpoint (certifique se é este mesmo o endereço correto do seu serviço) e conectar o evento SendToClientReceived que é onde podemos adicionar as mensagens que recebemos do servidor para o ObservableCollection (que por sua vez, nos mostra no ListBox)
No entanto, também é preciso fornecer um método Connect (que envia um ConnectMessage para o servidor), essa chamada é essencial para o serviço Duplex no servidor identificar o cliente acompanhando através da sessão ID. Você pode ver isso no arquivo DuplexService.cs como abaixo (linha 133):

O método de desconexão faz o inverso, envia um DisconnectMessage para o servidor que remove o cliente monitorado pela sessão ID.

Testando o aplicativo

Pressione F5 para executar o aplicativo, clique no botão Connect, veja que as mensagens enviadas para o Silverlight a partir do servidor a cada 5 segundos. Para torná-lo mais interessante, inicie uma segunda instância do navegador e execute a mesma aplicação. Você verá que ambos os clientes estão sendo atualizados exatamente ao mesmo tempo.
Baixe o código fonte aqui: http://cid-fb8b852ef1ab0b35.skydrive.live.com/self.aspx/SampleCode/DuplexExample.zip
Artigo original: http://silverlightforbusiness.net/2009/06/23/pushing-data-from-the-server-to-silverlight-3-using-a-duplex-wcf-service/