maandag 17 juni 2013

Onderzoek naar Windows Azure Service Bus (deel 3)

Windows Azure Service Bus is een mooie dienst waarmee services, die zich in besloten on-premise omgevingen bevinden, kunnen worden ontsloten zonder daarbij de firewall noemenswaardig te ondermijnen. Het idee is dat de buitenwereld de service bus aanspreekt en dat die op zijn beurt weer de on-premise dienst benadert. Er zijn op dit moment drie scenario's mogelijk (een vierde, de Notification Hub, is momenteel nog in de preview fase)
  1. Service Bus Relay
  2. Service Bus Queue
  3. Service Bus Topic/Subscriptions
De Service Bus Relay kun je gebruiken om de communicatie naar on-premise services mogelijk te maken zonder al te veel gedoe met de firewall. Deze techniek is en een eerdere blog al beschreven.
De Service Bus Queue is ideaal om diensten, die veel te verwerken krijgen, te ontlasten. Denk hierbij aan Load Leveling of Load Balancing. Dit scenario is in het tweede deel van deze blogreeks beschreven.
In dit deel gaan we kijken naar de Service Bus Topic/Subscriptions.

De Service Bus Topic/Subscriptions lijkt in veel opzichten op de Service Bus Queue. Clients, zoals mobiele applicaties, services en andere toepassingen, schieten berichten in een speciale queue; de Topic. Het grote verschil zit hem in het feit dat op de Topic niet direct wordt gelezen, zoals dat bij de queue wel het geval is, maar dat de berichten in zogenaamde virtuele queues, de Subscriptions, geplaatst worden. Iedere subscription ontvangt een kopie van het originele bericht.  Welk bericht in welke subscription wordt geplaatst, is weer afhankelijk van het filter dat is ingesteld op de subscription.
Kort samengevat, alle berichten verschijnen in een Topic en worden op basis van een filter naar de subscriptions gekopieerd die dan weer kunnen worden bekeken door applicaties die geïnteresseerd zijn in een subscription (afbeelding 1)


Afbeelding 1. Het principe van Topic/Subscriptions. Diverse applicaties sturen hun berichten naar de Topic die op zijn beurt kopieën, op basis van een filterdefinitie, naar de subscription stuurt. De betreffende subscriptions kunnen dan worden uitgelezen door belangstellende applicaties. Bron: Windows Azure
Hoewel je zo'n topic met bijbehorende subscriptions vanuit de Azure Portal kunt opzetten, is het in dit geval handiger om dat vanuit code te doen omdat je dan meteen filters kunt definiëren op de subscriptions. Iets dat vanuit de portal niet kan. Om de topics en subscriptions op te zetten, hebben we de access key van de owner nodig. Die heeft tenslotte manager rechten.
De code om de topic en subscriptions op te zetten ziet er als volgt uit:

private static void CreateTopicAndSubscriptions()
{
    string topicName = "input";
    TokenProvider tokenProvider = TokenProvider.CreateSharedSecretTokenProvider("owner""f4lCnMAkco8Yoc=");
    Uri svcUri = ServiceBusEnvironment.CreateServiceUri("sb""nspasit"string.Empty);
    NamespaceManager manager = new NamespaceManager(svcUri, tokenProvider);
    if (!manager.TopicExists(topicName))
    {
        manager.CreateTopic(topicName);
        SqlFilter f1 = new SqlFilter("EXISTS(complaint) OR EXISTS(sold)");
        manager.CreateSubscription(topicName, "sales", f1);
        SqlFilter f2 = new SqlFilter("EXISTS(sold)");
        manager.CreateSubscription(topicName, "warehouse", f2);
        SqlFilter f3 = new SqlFilter("EXISTS(complaint)");
        manager.CreateSubscription(topicName, "support", f3);
    }
}

Eerst wordt de NamespaceManager opgezet op basis van de tokenProvider en de url van de service bus. Vervlogens wordt een topic in elkaar gezet en drie subscriptions. Iedere subscription krijgt een filter mee die bepaalt welke berichten hij wil ontvangen en welke niet. In alle gevallen test ik op de aanwezigheid van een bepaalde eigenschap op het bericht ("sold" en "complaint"). Het resultaat van de uitvoering van deze code is in afbeelding 2 te zien.


Afbeelding 2. De topic "input" met de drie subscriptions "sales", "support" en "warehouse"
Vervolgens kunnen we berichten in de topic schieten. Dit gaat bijna hetzelfde als bij de queue.

static void Main(string[] args)
{
    TokenProvider tokenProvider = TokenProvider.CreateSharedSecretTokenProvider("writer""YpmQzUYtkTfszs=");
    Uri svcUri = ServiceBusEnvironment.CreateServiceUri("sb""nspasit"string.Empty);
    MessagingFactory mFactory = MessagingFactory.Create(svcUri, tokenProvider);
    TopicClient client = mFactory.CreateTopicClient("input");

    ProductData data = new ProductData { Brand = "ACME", Product = "Explosive Device", Price = 299.99M };
    BrokeredMessage message = new BrokeredMessage(data);
    message.Properties["complaint"] = "Exploded too early";
    client.Send(message);

    data = new ProductData { Brand = "Philips", Product = "Tooth Brush", Price = 99.99M };
    message = new BrokeredMessage(data);
    message.Properties["sold"] = 2;
    client.Send(message);

    Console.ReadLine();
}

Merk op dat er nu een TopicClient wordt aangemaakt. Daarnaast wordt aan ieder bericht een aantal eigenschappen (properties) toegekend die overeenkomen met één van de waarden uit de filterdefinities ("compaint" en "sold"). Wanneer we deze code uitvoeren zien we het resultaat terug in afbeelding 3.


Afbeelding 3. De twee berichten zijn in de subscription aangekomen. Merk op dat de sales subscription twee berichten bevat omdat die filterdefinitie beide eigenschappen in zich heeft.
Het uitlezen van de subscription gaat bijna hetzelfde als bij de queue. Alleen wordt er nu gebruik gemaakt van een SubscriptionClient.


class Program
{
    static void Main(string[] args)
    {
        TokenProvider tokenProvider = TokenProvider.CreateSharedSecretTokenProvider("reader""b/cSFuJUyv7dftB0=");
        Uri svcUri = ServiceBusEnvironment.CreateServiceUri("sb""nspasit"string.Empty);
        MessagingFactory mFactory = MessagingFactory.Create(svcUri, tokenProvider);
        SubscriptionClient client = mFactory.CreateSubscriptionClient("input""sales"ReceiveMode.PeekLock);
        BrokeredMessage msg = client.Receive();
        if (msg != null)
        {
            ProductData data = msg.GetBody<ProductData>();
            Console.WriteLine("{0} {1} {2}", data.Brand, data.Product, data.Price);
            msg.Complete();
        }

        Console.ReadLine();
    }
}

In dit codevoorbeeld wordt de "sales" subscription uitgelezen hetgeen na twee keer uitvoeren tot het resultaat in afbeelding 4 leidt.


Afbeelding 4. Wanneer de "sales" subscription twee keer is uitgelezen, staat de berichtenteller weer op 0.
In dit voorbeeld zie je dat Service Bus Topic/Subscriptions veel op de Service Bus Queue lijkt. Het grote verschil is, waar de Service Bus Queue 1 op 1 werkt, werkt de Service Bus Topic/Subscriptions 1 op n. Bij Service Bus Topic/Subscriptions heb je dezelfde voordelen als bij Service Bus Queue, zoals load leveling en load balancing. Bij Service Bus Queue zul je in het algemeen met één soort applicatie de queue uitlezen. Welke applicatie het bericht van de queue haalt is minder van belang omdat ze toch hetzelfde doen. Als je dit probeert met verschillende soorten applicaties, zal iedere applicatie zelf moeten bepalen of het bericht van de queue kan. Dit impliceert dan weer kennis van andere applicaties hetgeen niet wenselijk is. Hierin schuilt het grote voordeel van de Service Bus Topic/Subscriptions, ieder soort applicatie gebruikt zijn eigen queue met berichten die voor hem interessant zijn.

maandag 10 juni 2013

Onderzoek naar Windows Azure Service Bus (deel 2)

Windows Azure Service Bus is een dienst in Windows Azure die het mogelijk maakt om on-premise services samen te laten werken met services in de cloud en applicaties buiten de cloud. Hierbij kun je denken aan klanten die jouw services willen integreren in hun applicatie, maar ook mobiele toepassingen. Windows Azure Service Bus geeft de mogelijk om toegang aan te bieden zonder dat de beveiliging van de on-premise omgeving noemenswaardig wordt aangetast.
Windows Azure Service Bus bestaat uit drie onderdelen:

  1. Service Bus Relay
  2. Queues
  3. Topics en Subscriptions
In de vorige blog hebben we stilgestaan bij de Service Bus Relay. In dit deel kijken we naar de Service Bus Queue.
Een queue is een wachtrij waarin je berichten plaatst. Wie het eerst in de wachtrij komt, wordt ook het eerst geholpen. Dit principe noemen we First In First Out (FIFO). Aan de ene kant heb je applicaties die berichten in de queue plaatsen. Dit kunnen desktop applicaties zijn of mobiele toepassingen, maar ook services. Aan de andere kant heb je één of meerdere applicaties draaien die de queue uitlezen (afbeelding 1). Het mooie van de queue is dat de berichten, als ze eenmaal in de queue staan, niet zomaar zullen verdwijnen (reliability). Dat is mooi want als de applicatie, die de queue uitleest, offline gaat, is het wel zo fijn dat de berichten bij terugkomst nog beschikbaar zijn (in het ergste geval kunnen de berichten in de "dead letter queue" belanden wanneer ze niet op tijd gelezen worden).


Afbeelding 1. Het principe van een queue. Diverse toepassingen schieten berichten in de queue (Message Senders) en aan de andere kant worden de berichten weer uitgelezen (Message Receiver). Bron: Windows Azure
Een queue zul je gaan gebruiken als er heel veel berichten op jouw server worden afgevuurd die de server niet meer kan verwerken (druk druk druk). In zulke situaties wordt de queue gebruikt om er berichten in op te slaan, zodat ze later alsnog kunnen worden verwerkt (load leveling), of de queue wordt door meerdere servers uitgelezen (load balancing).
Er was al een queue in Windows Azure aanwezig (bij Azure Storage), maar de Service Bus Queue biedt meer mogelijkheden. Op de Windows Azure site zijn de verschillen mooi in kaart gebracht.

We gaan nu bekijken hoe je de sevice Bus Queue opzet. Hierbij willen we dat de "Message Sender" berichten in de queue kan schieten, maar deze niet kan uitlezen. Daarnaast zal de "Message Receiver" de queue kunnen uitlezen, maar er geen berichten in kunnen zetten.
Allereerst zet je een namespace op in de Service Bus Queue (vanuit de Windows Azure Portal) en daarna kun je een queue aanmaken (zie afbeelding 2) waarbij je de naam van de queue opgeeft, de regio waarin hij komt te draaien en tenslotte de eerder aangemaakte service bus namespace.


Afbeelding 2. Het aanmaken van de queue
Vervolgens moeten we de rechten afregelen van de "Message Sender" en de "Message Receiver". Dit doe je via de ACS management portal. Om op de ACS management portal te komen, selecteer je eerst de zojuist aangemaakte queue en klik je op "ACCESS KEY" onderin beeld (afbeelding 3). Dit geeft het dialoogje in afbeelding 4 van waaruit je naar de ACS Management Portal gaat (afbeelding 5).


Afbeelding 3. Het verborgen knopje onderin beeld waarmee je  de key informatie te zijn krijgt, maar ook toegang krijgt tot de ACS Management Protal

Afbeelding 4. De toegang tot de ACS Management Portal. Listig verborgen.

Afbeelding 5. De ACS Management Portal.
Op de ACS Management Portal ga je naar de "Service Identities". Daarin zie je één identity staan; de owner. Dit is de administrator identity die alles mag op de queue. Natuurlijk kun je die gebruiken, maar dat is niet aan te bevelen. We gaan twee identities toevoegen via de "Add" knop in afbeelding 5. Het brengt ons naar het scherm in afbeelding 6 waarin we bij Name "reader" opgeven. Zorg er ook voor dat er een symmetrische key gegenereerd wordt. Die zul je nodig hebben om berichten uit de queue te lezen.


Afbeelding 6. Het aanmaken van een nieuwe service identity.
Maak op dezelfde manier ook een service identity aan voor "writer". Vervolgens ga je naar de "Rule groups" en selecteer je "Default Rule Group for ServiceBus" (afbeelding 7). Dit leidt je naar het scherm in afbeelding 8 waarin je een lijstje van de bestaande rules voor de service identity "owner" ziet staan. 

Afbeelding 7. De Rule Groups
Afbeelding 8. De bestaande Rule groups voor "owner". Van hieruit kun je nieuwe rules aanmaken.
Wanneer je op "Add" klikt, kun je nieuwe rules aanmaken voor de service identities die je zo-even hebt toegevoegd. In afbeelding 9 zie je hoe je de Rule definieert voor de service identity "reader".


Afbeelding 9. Het aanmaken ven een nieuwe rule.
Bij "Input claim issuer" selecteer je "Access Control Service". Bij "Input claim type" neem je de standaard waarde "name identifier" over en bij "Input claim value" geef je de service identity "reader" op. Bij "Output claim type" selecteer je "Enter type" en geef je de waarde "net.windows.servicebus.action" op. Bij "Output claim value" selecteer je "Enter value" met als waarde "Listen" (een gereserveerde actie van de Service Bus Queue die je het recht geef om berichten uit de queue te lezen. Je hebt ook nog "Send" om berichten in de queue te plaatsen en "Manage" die alles mag). Nadat je de rule hebt opgeslagen, doe je hetzelfde voor de "writer" met als veschil dat je bij "Input claim value" de waarde "writer" opgeeft en bij "Output claim value" de waarde "Send".

Nu we de rules gedefinieerd hebben, kunnen we aan het coderen gaan. Eerst zullen we een applicatie maken die berichten in de queue schiet. Dit wordt een gewone console applicatie die we verrijkt hebben met het "Windows Azure Service Bus" package vanuit NuGet (weer ervan uitgaand dat de Azure SDK al geïnstalleerd is). De code voor de "Message Sender" staat hieronder weergegeven.


class Program
{
    static void Main(string[] args)
    {
        TokenProvider tokenProvider = TokenProvider.CreateSharedSecretTokenProvider("writer""YpmQzUYtNdyQrAf0AdOrnlI");
        Uri svcUri = ServiceBusEnvironment.CreateServiceUri("sb""nspasit"string.Empty);
        MessagingFactory mFactory = MessagingFactory.Create(svcUri, tokenProvider);
        QueueClient client = mFactory.CreateQueueClient("test");

        Data data = new Data { FirstName = "Patrick", LastName = "Schmidt" };
        BrokeredMessage msg = new BrokeredMessage(data);
        msg.TimeToLive = TimeSpan.FromSeconds(30);
        client.Send(msg);

        Console.WriteLine("Message sent");
        Console.ReadLine();
    }
}

[DataContract]
public class Data
{
    [DataMember]
    public string FirstName { getset; }
    [DataMember]
    public string LastName { getset; }
}

Bij TokenProvider.CreateSharedSecretToken() geef je de service identity "writer" op en de bijbehorende key die je eerder hebt gegenereerd (afbeelding 6). de volgende stap is het aanmaken van de ServiceUri die de url naar de service bus construeert. Met de tokenProvider en de svcUri kun je een MessageFactory initialiseren van waaruit je de QueueClient genereert. Vervolgens maak je een BrokeredMessage object aan waarin je de te verzenden data stopt en tenslotte roep je op de QueueClient de Send() methode aan die het bericht op de queue plaatst. Wanneer alles goed verloopt, kun je het bericht zien in de queue op de Azure Portal (afbeelding 10)


Afbeelding 10. Het bericht is in de queue aangekomen.
Een bericht uit de Queue lezen gaat bijna op dezelfde manier. Hiervoor maken we weer een Console applicatie aan die we verrijken met de "Windows Azure Service Bus" package. Het uitlezen gaat dan zoals in de listing hieronder.

class Program
{
    static void Main(string[] args)
    {
        TokenProvider tokenProvider = TokenProvider.CreateSharedSecretTokenProvider("reader""b/cSFuJUyv7dftlA/3I");
        Uri svcUri = ServiceBusEnvironment.CreateServiceUri("sb""nspasit"string.Empty);
        MessagingFactory mFactory = MessagingFactory.Create(svcUri, tokenProvider);
        QueueClient client = mFactory.CreateQueueClient("test"ReceiveMode.PeekLock);

        BrokeredMessage msg = client.Receive();
        if (msg != null)
        {
            Data data = msg.GetBody<Data>();
            Console.WriteLine("{0} {1}", data.FirstName, data.LastName);
            msg.Complete();
        }

        Console.ReadLine();
    }
}

Bij de CreateSharedSecretToken() specificeer je nu de service identity "reader" en de bijbehorende key en vervolgens maak je weer de QueueClient aan. Let op dat ik als extra argument ReceiveMode.PeekLock opgeef. Deze optie is niet standaard (ReceiveAndDelete) en laat het bericht op de queue staan totdat ik zeg dat hij eraf kan via msg.Complete(). Op de QueueClient kun je nu via Receive() het bericht opvragen en, als die een geldige waarde heeft, via GetBody<Type>() het object terug halen.

Het werken met Windows Azure service Bus Queue is dus bijzonder eenvoudig. Met de nieuwste toevoeging AMQP (Advanced Message Queuing Protocol) kun je nu ook message-based applicaties bouwen die onafhankelijk zijn OS-platforms, leveranciers en talen.
Er kleven ook een paar nadelen aan Windows Azure Service Bus Queues. Zo worden transacties wel op queue-nivo ondersteund, maar niet gedistribueerd. Dwz dat een queue en bijvoorbeeld een database samen geen transactionele eenheid kunnen vormen.
Daarnaast moet je ook de kosten in de gaten houden. De kosten zijn per hoeveelheid berichten per maand. Op dit moment €75,- per 100.000.000 berichten per maand. Daarbij moet je ook opletten dat de berichten niet groter dan 64kb zijn, anders krijg je extra berichtkosten voor iedere 64kb die je overschrijdt. 

maandag 3 juni 2013

Onderzoek naar Windows Azure Service Bus (deel 1)

Software voor bedrijven is altijd een heikel punt geweest. Ze willen niet dat derden bij hun kostbare data komen. Vandaar dat die applicaties in het algemeen in een zwaar geïsoleerde omgeving (het intranet) draaien. Nadeel van deze benadering is dat je erg veel geld kwijt bent aan de softwarepakketten, infrastructuur en updates. Vanwege de groeiende populariteit van het internet worden steeds meer diensten aangeboden in de cloud. Die zijn veelal goedkoper omdat ze op één plaats worden geïnstalleerd en onderhouden en meerdere klanten kunnen van die specifieke dienst gebruik maken. Dan kun je wel eens een probleem krijgen met de integratie van jouw intranet applicatie met zo'n dienst. Wellicht wil je juist wat intranetdiensten naar buiten openen om bijvoorbeeld mobiele applicaties te ondersteunen. Dan heb je geen zin om allemaal gaten in jouw firewall te schieten. Hier komt nu Windows Azure Service Bus om de hoek kijken.

Windows Azure Service Bus is een technologie om applicaties eenvoudig met elkaar te kunnen laten communiceren en wel zo dat de voordelen van de intranet omgeving, zoals veiligheid, betrouwbaarheid en snelheid niet aangetast worden.
In Windows Azure Service Bus kun je drie soorten van communicatie onderscheiden:
  1. Service Bus Relay. Hierbij moeten toepassingen, waar ook ter wereld, kunnen communiceren met jouw (on-premise) service, waarvan het adres in het algemeen niet bekend of onbereikbaar is.  
  2. Queues. Wanneer je een stortvloed aan berichten krijgt die door één server niet meer te behappen zijn, maar wel behandeld moeten worden. Zo'n queue is een wachtrij waarin de berichten voor een langere tijd kunnen worden opgeslagen totdat ze afgehandeld kunnen worden door een server.
  3. Topic/Subscriptions. Hierbij heb je te maken met softwarepakketten die geïnteresseerd zijn in bepaalde onderwerpen. Denk hierbij aan een verkooponderwerp. Wanneer een verkoop plaats vindt, zullen andere toepassingen, zoals een inventarisatiesysteem of een boekhoudsysteem, hiervan op de hoogte willen worden gebracht, zodat ze hierop gepaste actie kunnen onderemen in hun systeem.
In dit eerste artikel wil ik kijken naar Service Bus Relay.
Service Bus Relay maakt het mogelijk om services, zoals een WCF service, bereikbaar te maken voor toepassingen buiten het intranet (zie afbeelding 1).

Afbeelding 1. Service Bus Relay. Applicaties buiten het intranet kunnen communiceren met jouw WCF-service die in de beveiligde omgeving draait. Bron: Windows Azure
Service Bus Relay neemt hierbij de rol van een Message Broker aan, dat wil zeggen, externe applicaties sturen hun berichten naar de Message Broker die vervolgens het bericht naar de echte WCF-service doorstuurt. Eventuele reacties worden via de Message Broker weer naar de applicatie teruggestuurd. Service Bus Relay ondersteunt een scala aan communicatiepatronen, zoals request/response, fire and forget en duplex communicatie. Laten we maar meteen beginnen met het lastigste scenario, de duplex communicatie.

Bij duplex communicatie kan niet alleen de client contact opnemen met de service, maar de service kan ook contact opnemen met de client. Chatservers zullen dit principe in het algemeen toepassen. Wanneer een client iets te melden heeft, stuurt hij dat bericht naar de service die op zijn beurt het bericht doorstuurt naar alle andere clients. Eerst maar eens zo'n service in elkaar schroeven.

[ServiceContract(Namespace = "http://blog.pasit.nl/relay",
                         CallbackContract = typeof(IClientContract))]
public interface IMessenger
{
    [OperationContract(IsOneWay = true)]
    void SendMessage(string input);

    [OperationContract(IsOneWay = true)]
    void Register();
}

[ServiceContract(Namespace = "http://blog.pasit.nl/relay")]
public interface IClientContract
{
    [OperationContract(IsOneWay = true)]
    void PushMessage(string message);
}

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class MessengerImp : IMessenger
{
    private List<IClientContract> subscribers =
                                              new List<IClientContract>();

    public void SendMessage(string input)
    {
        foreach (IClientContract subscriber in subscribers)
        {
            subscriber.PushMessage("From service: " + input);
        }
    }
    public void Register()
    {
        IClientContract subscriber =
          OperationContext.Current.GetCallbackChannel<IClientContract>();
        subscribers.Add(subscriber);
    }
}

IMessenger is de interface voor de service, IClientContract wordt door de client applicatie geïmplementeerd. MessengerImp is de service implementatie. Het idee is dat clients zich aanmelden bij deze service (via Register()) en wanneer een client iets te melden heeft, doet hij dat via SendMessage  (ik ga verder niet op alle implementatiedetails in).
De volgende stap is het maken van een host programma (zo'n uitvoerbaar programma dat processortijd en RAM voor de service aanlevert).

class Program
{
    static void Main(string[] args)
    {
        ServiceHost host = new ServiceHost(typeof(MessengerImp));
        ServiceEndpoint ep = CreateLocalServiceEndpoint();
        host.AddServiceEndpoint(ep);

        host.Open();
        Console.WriteLine("Service is running...");
        Console.ReadLine();
        host.Close();
    }
    static ServiceEndpoint CreateLocalServiceEndpoint()
    {
        string address = "net.tcp://localhost:9998/message";
        NetTcpBinding binding = new NetTcpBinding();
        Type contract = typeof(IMessenger);
        ServiceEndpoint ep = new ServiceEndpoint(
                                          ContractDescription.GetContract(contract),
                                          binding,
                                          new EndpointAddress(address));

        return ep;
    }
}

In CreateLocalServiceEndpoint() wordt nu een endpoint opgezet die luistert op poort 9998. 
De service is nu helemaal af. Nu kunnen we aan de slag gaan met de client. Daarvoor heb ik in ieder geval de interfaces (IMessenger en IClientContract) uit de eerste listing nodig.


[ServiceContract(Namespace = "http://blog.pasit.nl/relay",
                         CallbackContract = typeof(IClientContract))]
public interface IMessenger
{
    [OperationContract(IsOneWay = true)]
    void SendMessage(string input);

    [OperationContract(IsOneWay = true)]
    void Register();
}

[ServiceContract(Namespace = "http://blog.pasit.nl/relay")]
public interface IClientContract
{
    [OperationContract(IsOneWay = true)]
    void PushMessage(string message);
}

public class ClientImp : IClientContract
{
    public void PushMessage(string message)
    {
        Console.WriteLine(message);
    }
}

class Program
{
    static void Main(string[] args)
    {
        IMessenger proxy = CreateLocalProxy();
        proxy.Register();
        proxy.SendMessage("Hello World");
        Console.ReadLine();
    }
    static IMessenger CreateLocalProxy()
    {
        string address = "net.tcp://localhost:9998/message";
        NetTcpBinding binding = new NetTcpBinding();
        Type contract = typeof(IMessenger);
        ClientImp imp = new ClientImp();
 
        DuplexChannelFactory<IMessenger> factory =
                    new DuplexChannelFactory<IMessenger>(
                           imp, binding, address.ToString());

        return factory.CreateChannel();
    }
}

ClientImp is de implementatie van IClientContract die wordt aangeroepen als de service iets te melden heeft. Verder is het wederom het Endpoint opbouwen in CreateLocalProxy(). Dit is de traditionele benadering. Nu wil ik de communicatie via Service Bus Relay laten verlopen. Daarvoor moet ik eerst een Service Bus namespace aanmaken in Windows Azure. In het portalmenu selecteer je "SERVICE BUS" en vervolgens klik je op de enorme "+" links onderin beeld. Je krijgt dan het scherm uit afbeelding 2. Hierin selecteer je "Quick Create" en je kunt de namespace en region opgeven.


Afbeelding 2. Het instellen van de namespace.
Wanneer de namespace is aangemaakt, kunnen we proberen om de WCF-service via Service Bus Relay te laten communiceren. Hiervoor moeten we eerst de Windows Azure Service Bus SDK installeren. Een versie komt al mee met de Windows Azure SDK, maar via NuGet kun je ook de laatste versie installeren.
Het enige dat aan de eerdere implementatie verandert, zijn de endpoints, zowel bij de client als bij de service (beide moeten immers identiek zijn). Hiervoor levert de Windows Azure Service Bus SDK een aantal Relay bindingen, zoals NetTcpRelayBinding en WsHttpRelayBinding die je in zult moeten zetten. Daarnaast zullen client en service beide een een security token moeten configureren (shared secret) om te kunnen communiceren. De informatie voor dit token vind je in de Azure Portal onder het menu "Service Bus". Onderin beeld zie je een knop "ACCESS KEY". Wanneer je daar op drukt, krijg je het venster uit afbeelding 3 waarin de default issuer en de default key getoond worden. Beide heb je nodig. (overigens kun je ook andere issuers en keys aanmaken. Dat is zelfs aan te bevelen).
De endpoint configuratie op de service en de client wordt nu:

static ServiceEndpoint CreateServiceBusEndpoint()
{
    Uri address = ServiceBusEnvironment.CreateServiceUri(
                          "sb""pasitns""MessengerImp");
    NetTcpRelayBinding binding = new NetTcpRelayBinding();
    Type contract = typeof(IMessenger);

    ServiceEndpoint ep =
             new ServiceEndpoint(ContractDescription.GetContract(
                    contract), binding, new EndpointAddress(address));
    TransportClientEndpointBehavior tokenBehavior =
                         new TransportClientEndpointBehavior();
    tokenBehavior.TokenProvider =
              TokenProvider.CreateSharedSecretTokenProvider(
                   "owner""AQsRfnCYMvxIBEqmM/7wrHpkNKtV=");
    ep.EndpointBehaviors.Add(tokenBehavior);
    return ep;
}
Wanneer je nu de applicatie start, krijg je de foutmelding uit afbeelding 4. 


Afbeelding 4. Het gaat niet helemaal goed.
Het probleem is dat Windows Azure Service Bus via een speciale poort wil communiceren. Voor NetTcpRelayBinding is dat poort 9350. Deze zullen we in de firewall moeten openzetten, maar daarna loopt het ook meteen. In deze demonstratie heb ik de service in een virtuele omgeving laten draaien en de client erbuiten. Normaal is het een hele toestand om de zaak aan het draaien te krijgen, maar met Windows Azure Service Bus werkt het meteen (afbeelding 5).


Afbeelding 5. Het resultaat van de communicatie tussen de service op de virtuele omgeving en de client op de Windows omgeving.
Dit is nog maar één toepassing. Het is ook mogelijk om Windows Azure Service Bus Relay in te zetten als een soort van discovery service. Ideaal voor services die op een staging omgeving, waarvan het adres onmogelijk te voorspellen is, draaien.