This sample demonstrates how to use the Windows Azure Service Bus and the NetTcpRelayBinding binding. See the Service Bus documentation for more information about the Service Bus before exploring the samples.

This sample shows a simple service and client that communicate through the Service Bus. When the service application is started, it asks for your issuer credentials and opens an endpoint on the Service Bus. After it is opened, this endpoint has a well-known URI on the Service Bus and is reachable from anywhere, whether or not your computer resides behind a firewall or Network Address Translation (NAT). Clients that access the endpoints must have permission to talk to the endpoint. Therefore, the client application also asks for your issuer credentials, authenticates with the Access Control service, and acquires an access token that proves to the Service Bus infrastructure that the client is authorized to access the endpoint. After the client is connected, you can type messages into the client application, which will be echoed back by the service.

Prerequisites

If you haven't already done so, please read the release notes document that explains how to sign up for a Windows Azure account and how to configure your environment.

Echo Service

The service implements a simple contract with a single operation named Echo. The Echo service accepts a string and echoes the string back.

C# 
 [ServiceBehavior(Name = "EchoService", Namespace = "http://samples.microsoft.com/ServiceModel/Relay/")]
class EchoService : IEchoContract
{
   public string Echo(string text)
   {
      Console.WriteLine("Echoing: {0}", text);
      return text; 
   }
}

The service configuration is shown below:

Xml 
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
      <!-- Application Service -->
      <service name="Microsoft.ServiceBus.Samples.EchoService">
        <endpoint contract="Microsoft.ServiceBus.Samples.IEchoContract"
      binding="netTcpRelayBinding" />
      </service>
    </services>
  </system.serviceModel>
</configuration>

Assuming you have some prior knowledge of the structure of configuration files for the Windows Communication Foundation (WCF), you will find that the configuration file is similar to any other WCF configuration file, with the exception that the configured service endpoint refers to a NetTcpRelayBinding binding, which is not part of the .NET Framework.

The NetTcpRelayBinding binding is one of the bindings introduced with the Service Bus, and the respective configuration element needs to be added to the application configuration file.

The code that hosts the service (in Program.cs or Program.vb) contains two key aspects of interest:

  • How does addressing work?

  • How do authentication and authorization work?

C# 
Console.Write("Your Service Namespace: ");
string serviceNamespace = Console.ReadLine();
Console.Write("Your Issuer Name: ");
string issuerName = Console.ReadLine();
Console.Write("Your Issuer Secret: ");
string issuerSecret = Console.ReadLine();

// create the service URI based on the service namespace
Uri address = ServiceBusEnvironment.CreateServiceUri("sb", serviceNamespace, "EchoService");

// create the credentials object for the endpoint
TransportClientEndpointBehavior sharedSecretServiceBusCredential = new TransportClientEndpointBehavior();
sharedSecretServiceBusCredential.TokenProvider = TokenProvider.CreateSharedSecretTokenProvider(issuerName, issuerSecret);            

// create the service host reading the configuration
ServiceHost host = new ServiceHost(typeof(EchoService), address);

// create the ServiceRegistrySettings behavior for the endpoint
IEndpointBehavior serviceRegistrySettings = new ServiceRegistrySettings(DiscoveryType.Public);

// add the Service Bus credentials to all endpoints specified in configuration
foreach (ServiceEndpoint endpoint in host.Description.Endpoints)
{
   endpoint.Behaviors.Add(serviceRegistrySettings);
   endpoint.Behaviors.Add(sharedSecretServiceBusCredential);
}

// open the service
host.Open();

Console.WriteLine("Service address: " + address);
Console.WriteLine("Press [Enter] to exit");
Console.ReadLine();

// close the service
host.Close();

To implement a service that listens to the Service Bus, the Service Bus service must be able to verify that the owner of the listening service is authorized to do so.

Authentication and authorization are both performed by the Access Control service. To make these steps simple, the Microsoft.ServiceBus namespace contains a set of transport client credential helpers that automatically handle the acquisition of the required security tokens.

The credential used in this example is a simple user name/password credential that is backed by the issuer credentials you set up when signing up for a Windows Azure account. To associate a listener endpoint with its Service Bus credentials, you must add a TransportClientEndpointBehavior behavior to the respective endpoint behavior collection. If your service exposes multiple endpoints through the Relay, you can add the same behavior instance to all those endpoints.

Each service namespace automatically owns a branch of the Service Bus global namespace. Your service namespace branch is rooted at:

 
[scheme]://<service-namespace>.servicebus.windows.net/ 

in which [scheme] is either sb (as in this example) or http or https. The namespace owner can subdivide that namespace and organize services onto that namespace as needed and define rules in Access Control to guard access to branches of the namespace.

The preceding code prompts for the issuer credential and then constructs the listening URI using that information. The static ServiceBusEnvironment.CreateServiceUri function is provided to help construct the URI using the correct format and domain name. It is strongly recommended that you use this function instead of building the URI from scratch because the URI construction logic and format might change in future releases. At present, the resulting listener URI is scheme://<service-namespace>.servicebus.windows.net/EchoService/. These URIs can be used as absolute listening URIs for endpoints, or as the base address of the service.

Echo Service Client

The client application mirrors the service in terms of its configuration.

Xml 
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <client>
      <!-- Application Endpoint -->
      <endpoint name="RelayEndpoint"
                contract="Microsoft.ServiceBus.Samples.IEchoContract"
                binding="netTcpRelayBinding"/>
    </client>
  </system.serviceModel>
</configuration>

When it runs, the client prompts for the service namespace credentials, creates a channel to the service, and sends requests by calling the Echo operation. After the interaction is complete, the client closes the channel and exits.

C# 
Console.Write("Your Service Namespace: ");
string serviceNamespace = Console.ReadLine();
Console.Write("Your Issuer Name: ");
string issuerName = Console.ReadLine();
Console.Write("Your Issuer Secret: ");
string issuerSecret = Console.ReadLine();

// create the service URI based on the service namespace
Uri address = ServiceBusEnvironment.CreateServiceUri("sb", serviceNamespace, "EchoService");

// create the credentials object for the endpoint
TransportClientEndpointBehavior sharedSecretServiceBusCredential = new TransportClientEndpointBehavior();
sharedSecretServiceBusCredential.TokenProvider = TokenProvider.CreateSharedSecretTokenProvider(issuerName, issuerSecret);            

// create the channel factory loading the configuration
ChannelFactory<IEchoChannel> channelFactory = new ChannelFactory<IEchoChannel>("RelayEndpoint", new EndpointAddress(serviceUri));

// apply the Service Bus credentials
channelFactory.Endpoint.Behaviors.Add(sharedSecretServiceBusCredential);

// create and open the client channel
IEchoChannel channel = channelFactory.CreateChannel();
channel.Open();

Console.WriteLine("Enter text to echo (or [Enter] to exit):");
string input = Console.ReadLine();
while (input != String.Empty)
{
   try
   {
      Console.WriteLine("Server echoed: {0}", channel.Echo(input));
   }
   catch (Exception e)
   {
      Console.WriteLine("Error: " + e.Message);
   }
   input = Console.ReadLine();
}

channel.Close();
channelFactory.Close();

Running the Sample

To run the sample, build the solution in Visual Studio or from the command line, then run the two resulting executable files. Run the service first, and then run the client. Both programs prompt for your service namespace and the issuer credentials. For the issuer secret, be sure to use the "Default Issuer Key" value from the portal, rather than one of the management keys.

When the service and the client are running, you can start typing messages into the client application. These messages are echoed by the service.

Expected Output - Service

Your Service Namespace: <service-namespace>
Your Issuer Name: <issuer-name>
Your Issuer Secret: <issuer-secret>
Service address: sb://<service-namespace>.servicebus.windows.net/services/EchoService/
Press [Enter] to exit

Expected Output - Client

Your Service Namespace: <service-namespace>
Your Issuer Name: <issuer-name>
Your Issuer Secret: <issuer-secret>
Enter text to echo (or [Enter] to exit): Hello, World!
Server echoed: Hello, World!


Did you find this information useful? Please send your suggestions and comments about the documentation.