Hospedando um serviço WCF em uma Worker Role do Windows Azure


Olá pessoal, hoje vou voltar a falar sobre WCF com vocês, mas com a novidade que eu quero mostrar é a possibilidade de hospedar os serviços no Windows Azure, que é a plataforma de Cloud Computing da Microsoft.

Podemos contar no Windows Azure com os serviços de computação, com possibilidade de utilizarmos estes serviços para web (Web Role) e processamento background (Worker Role). Em uma web role, o WCF pode ser hospedado de maneira similar ao IIS, utilizando arquivos .svc. Já em uma worker role, que pode ser entendida para o equivalente à um Windows Service, precisamos gerenciar o ciclo de vida do WCF nela. Este post fala exatamente sobre WCF com Worker Roles.

Vou iniciar a solução com dois projetos existentes: uma ClassLibrary com a definição do contrato para um serviço de “Echo” (projeto WcfDefinition) e um cliente para o serviço (WcfClientApplication). O contrato do serviço está abaixo:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;

namespace WcfDefinition
{
    [ServiceContract]
    public interface IEchoService
    {
        [OperationContract]
        string Echo(string text);
    }
}

A aplicação cliente é uma aplicação WPF que possui uma caixa de texto, um botão e uma lista para mostrar o retorno de cada chamada ao serviço, um print está abaixo:


image

O seu arquivo de configuração:

<?xml version="1.0" encoding="utf-8" ?>
<
configuration>
  <
system.serviceModel>
    <
bindings>
      <
netTcpBinding>
        <
binding>
          <
security mode="None"/>
        </
binding>
      </
netTcpBinding>
    </
bindings>
    <
client>
      <
endpoint address="net.tcp://localhost:8080/EchoService"
                binding="netTcpBinding"
                contract="WcfDefinition.IEchoService"
                name="WcfDefinition.IEchoService" />
    </
client>
  </
system.serviceModel>
</
configuration>

 

E o código fonte:

public partial class MainWindow : Window
{
    private ObservableCollection<string> _results = new ObservableCollection<string>();

    public MainWindow()
    {
        InitializeComponent();
    }

    private void SendButton_Click(object sender, RoutedEventArgs e)
    {
        ChannelFactory<WcfDefinition.IEchoService> channel = 
new ChannelFactory<WcfDefinition.IEchoService>("WcfDefinition.IEchoService"); WcfDefinition.IEchoService proxy = channel.CreateChannel(); _results.Add(proxy.Echo(ContentTextBox.Text)); } private void Window_Loaded(object sender, RoutedEventArgs e) { ResultListBox.ItemsSource = _results; } }

Até aí tudo normal, não apresentei nenhuma novidade para o WCF. Agora vou incluir o Worker Role para pode hospedar o nosso serviço, é só adicionar um projeto do tipo Windows Azure Cloud Service:

image

E depois adicionar uma Worker Role:

image

Na Worker Role preciso implementar o serviço de Echo:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.ServiceModel;
using WcfDefinition;

namespace WcfServiceWorkerRole
{
    [ServiceBehavior(AddressFilterMode = AddressFilterMode.Any)]
    class EchoService : IEchoService
    {
        public string Echo(string text)
        {
            Trace.WriteLine(string.Format("[EchoService.Echo]: {0}", text), "Information");
            return text;
        }
    }
}

Notem o uso do AddressFilterMode, isso é feito porque o serviço na verdade não é acessado diretamente pelos clientes. As chamadas dos clientes para o serviço passam por um roteamente interno no Windows Azure, se nada fosse utilizado o serviço iria simplesmente recusar a mensagem e retornar um erro.

O arquivo de configuração, exibido parcialmente, da Worker Role está abaixo, notem que ele não traz o endereço do serviço.

  <system.serviceModel>
    <bindings>
      <netTcpBinding>
        <binding>
          <security mode="None"/>
        </binding>
      </netTcpBinding>
    </bindings>
    <services>
      <service name="WcfServiceWorkerRole.EchoService">
        <endpoint address="EchoService" 
binding="netTcpBinding" contract="WcfDefinition.IEchoService" /> </service> </services> </system.serviceModel>

Para que o serviço possa ser exposto em algum endereço, primeiro precisamos avisar o Windows Azure que isso irá acontecer e isso é feito através do arquivo ServiceDefinition.csdef, em formato xml, onde configuro um endereço de endpoint:

<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="WcfWorkerRole" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
  <WorkerRole name="WcfServiceWorkerRole">
    <ConfigurationSettings>
      <Setting name="DiagnosticsConnectionString" />
    </ConfigurationSettings>
    <Endpoints>
      <InputEndpoint name="EchoService" protocol="tcp" port="8080" />
    </Endpoints>
  </WorkerRole>
</ServiceDefinition>

Isso também pode ser feito pela tela de configuração da Worker Role:

image

Depois no método OnStart da Worker Role, configuro o ServiceHost:

public override bool OnStart()
{
    // Set the maximum number of concurrent connections 
    ServicePointManager.DefaultConnectionLimit = 12;

    DiagnosticMonitor.Start("DiagnosticsConnectionString");

    // For information on handling configuration changes
    // see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.
    RoleEnvironment.Changing += RoleEnvironmentChanging;

    CreateServiceHost();

    return base.OnStart();
}

private void CreateServiceHost()
{
    RoleInstanceEndpoint externalEndpoint = 
RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["EchoService"]; string baseAddress = string.Format("net.tcp://{0}/",
externalEndpoint.IPEndpoint); Trace.WriteLine(string.Format("[WorkerRole.CreateServiceHost]: Base Address {0}", baseAddress), "Information"); ServiceHost = new ServiceHost(typeof(EchoService), new Uri(baseAddress)); }

Primeiro é necessário buscar a configuração do endereço para o Windows Azure (RoleInstanceEndpoint externalEndpoint = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["EchoService"];), em seguida é necessário configurar o serviço para utilizá-lo, o que é feito na linha seguinte (string baseAddress = string.Format("net.tcp://{0}/", externalEndpoint.IPEndpoint);).

O último passo é colocar o serviço no ar, através de um ServiceHost.Open() , feito no método Run da Worker Role:

public override void Run()
{
    // This is a sample worker implementation. Replace with your logic.
    Trace.WriteLine("WcfServiceWorkerRole entry point called", "Information");

    ServiceHost.Open();

    while (true)
    {
        Thread.Sleep(10000);
        Trace.WriteLine("Working", "Information");
    }
}

O código fonte pode ser encontrado aqui.

Comments (2)
  1. MumHaBR says:

    Apesar de ser possível fazer isso, entendo que não deveria ser feito. Deveria ser utilizado a WebRole que já permite a hospedagem de WCF e todo o gerenciamento com o AppFabric.

  2. @MumHaBR,

    Vale lembrar que em uma WebRole não temos o AppFabric (acredito que vc esteja se referindo ao Windows Server AppFabric), temos o IIS, que suporta os bindings que trabalham em cima do protocolo Http, o exemplo acima publica o serviço utilizando o NetTcpBinding, logo não funcionaria em cima do IIS.

    Além disso existem cenários e cenários. Alguns cenários podem ser muito bem atendidos pelo IIS e outros não. Eventualmente estes últimos podem precisar de um código customizado, que pode ser feito em uma Worker Role quando pensamos no Windows Azure.

    RG

Comments are closed.

Skip to main content