.NET Service Bus (Part 1) – Hands On with Relays

I’m on the road this week and had expected to get more accomplished then I did sitting in the office. I started drafting this blog post at 5:30am last Sunday but opted to start over completely and this is the end result. The upside to all this lost time is that I have worked out the next 3-4 articles I want to post. And if all goes well I should be able to throw them all out in rapid succession. 🙂  Lucky you.

Today we’re going to start diving into the first of three features of .NET Services, the Service Bus. I’m running the July CTP bits on a Windows 7 VPC with Visual Studio 2008. This article series has taken longer to come together than I would have liked because just like when I was working with Azure storage and REST calls, I’m a bit of a noob when it comes to WCF. And while WCF isn’t required for working with the Service Bus, its the easiest way to work with it when using .NET (there are Java, PHP, and Ruby SDK’s either already ready or in the works).

An Internet Service Bus?

Go ahead and snicker. An IBM centric cohort of mine did as well. Yes, this is a simple Service Bus brought to an internet scope. It performs the basic function of allowing you to relay messages between processes, including some queuing and routing dynamics. It even includes some integrated access control functionality. Where it really deviates from the norm is that this service bus was created to operate in the cloud. This has required that the implementation be designed in such a way as to be friendly when dealing with issues like firewalls, NAT’s, and proxy addresses. You know. all those little annoying things that have been created to help keep our internet exposed applications safe.

The rules under which this is accomplished are actually fairly straight forward. First and foremost, all application connections are outbound to the service bus. The bus doesn’t need to know the address of any service you’re hosting because that service will reach out and connect to the .NSB (.Net Service Bus, I’m gonna be lazy from here on out). It acts like its own DMZ, with all the interested parties needing to step up to the table if they want to talk. Secondly, all communications will be done over a limited number of ports. For TCP based relays, you will need 808, 818, 819, 828. For http connections, good old port 80 will be sufficient (be sure to refer to the official docs for the latest updates on required ports).

New WCF Bindings

As I mentioned earlier, when doing .NET development, the ideal way to interact with the .NSB is through WCF. To that end, a new series of bindings and binding elements have been created to account for this. For the most part, these new bindings and elements are simply counterparts to traditional WCF bindings. Here they are:

Standard WCF Binding Equivalent Relay Binding Relay Transport Element
BasicHttpBinding BasicHttpRelayBinding Http(s)RelayTransportBindingElement
WebHttpBinding WebHttpRelayBinding Http(s)RelayTransportBindingElement
WSHttpBinding WSHttpRelayBinding Http(s)RelayTransportBindingElement
WS2007HttpBinding WS2007HttpRelayBinding Http(s)RelayTransportBindingElement
WSHttpContextBinding WSHttpRelayContextBinding Http(s)RelayTransportBindingElement
WS2007HttpFederationBinding WS2007HttpRelayFederationBinding Http(s)RelayTransportBindingElement
NetTcpBinding netTcpRelayBinding TcpRelayTransportBindingElement
NetTcpContextBinding netTcpRelayContextBinding TcpRelayTransportBindingElement
N/A netOnewayRelayBinding OnewayRelayTransportBindingElement
N/A netEventRelayBinding OnewayRelayTransportBindingElement

 

On an only semi-related note, this blog will likely on a bit of a hiatus this fall as I get back to working on some longer overdue certs. This includes trying to get certified with WCF, so I won’t even try and talk like an expert in the subject right now. Suffice to say that each of these new bindings are useful for for specific circumstances. And knowing when and how to use which one will be your challenge.

Creating our Service Bus Project

Before we dive into creating our solution, we need to make sure our hosted service bus is setup. Head over to the .NET Service portal at portal.ex.azure.microsoft.com and sign in. If you don’t already have a solution, click on “Add Solution” to create it. When giving it a name, be careful as you won’t be able to delete or rename you solution (at least not currently).

hss_servicesportal

You’ll notice that for each of the two solutions displayed above, we have access to both the .NET Services Access Control Services, as well as the Service Bus. We’ll need a couple pieces of data from here for our initial sample project. The Solution name, our password, and the endpoint URI. The URI can be viewed by clicking on the “Service Bus Registry” link.

A single instance of the service bus can easily host multiple relays. To take advantage of this, we are going to put “SimpleService” on the end of your URI to target things a bit more narrowly. And since we’re using the .NSB, we need to change our URI protocol from tcp or http to “sb”. The final URI looks like this:

sb://<solutionname>servicebus.windows.net/SimpleService/

Our first relay

So lets start with a simple example. I originally wanted to do this demo using Azure Hosted applications, but decided that I’ll save that for its own post at a later date. So for this first example, we’re going to use two Windows Console applications. Our simple service will expose a single “GetDate” method which will in turn be consumed by a second console application.

Fire up Visual Studio and start by creating a Windows Console application. I called mine “SimpleService”. We then add a second Windows Console application (“SimpleClient”), as well as a class library (“SimpleServiceDefs”). The SimpleService app will host our service using an outbound tcp binding, connect to the Service Bus Relay. Simple client will then connect to the bus as well to consume our service.

Our Service Contract

Next up, we need to add classes to the SimpleServiceDefs class library that define the contract for our WCF Service. I’ve opted to put it in its own library (I’m a firm believer in the use of class libraries as a best practice), but you could just as easily put it in either of the other two projects. First, add a reference to System.ServiceModel. We need the System.ServiceModel reference because the classes that define our contract will be decorated with a few attributes tags to help define it. I then add an interface, iSimpleService, and the class SimpleService. The SimpleService has only one method, GetDate, which accepts no parameters and returns a datetime.

The iSimpleService interface

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

     namespace SimpleServiceDefs
     {
         [ServiceContract]
         public interface iSimpleService
         {
             [OperationContract]
             DateTime GetDate();
         }
     }

 

The SimpleService class

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

     namespace SimpleServiceDefs
     {
         public class SimpleService : iSimpleService
         {
             public DateTime GetDate()
             {
                 Console.WriteLine("GetDate called");
                 return DateTime.Now;
             }
         }
     }

And there we have our service contract. Next we have to create a host for it.

The Service Host

Our SimpleService project will be the host of our service. We’ll start by adding in a reference for System.ServiceModel and a new assembly, Microsoft.ServiceBus. This second reference is for a component of the .NET Service SDK. It contains the definitions for all the new bindings and endpoints that we mentioned above. We’re then going to add an application configuration file.

Lets start with the configuration file. We’ll use this to define the properties of our WCF hosted service. Here’s my configuration…

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
      <service name="SimpleServiceDefs.SimpleService">
        <endpoint address="sb://[solution].servicebus.windows.net/SimpleService/"
                  binding="netTcpRelayBinding"
                  contract="SimpleServiceDefs.SimpleService"
                  behaviorConfiguration="default" />
      </service>
    </services>
    <behaviors>
      <endpointBehaviors>
        <behavior name="default">
          <transportClientEndpointBehavior credentialType="UserNamePassword">
            <clientCredentials>
              <userNamePassword userName="[solution]"
                                password="[password]" />
            </clientCredentials>
          </transportClientEndpointBehavior>
        </behavior>
      </endpointBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

Start by substituting the “solution” and “password” values. These values come from the service bus project we created above. Next up, look at the binding I used, netTCPRelayBinding. This is one of the new service bus relay bindings. This particular one is simply a service bus specific version of netTCPBinding. You’ll also notice that the transportClientEndpointBehavior node remains underlined. This is normal, although I’m hoping that it will eventually be fixed. For now its just an annoyance.

Now all that’s left is the code within our service host application. Start by adding using clauses for System.ServiceModel and SimpleServiceDefs. Then insert the following code.

        static void Main(string[] args)
        {
            ServiceHost myHost = new ServiceHost(typeof(SimpleServiceDefs.SimpleService));

            myHost.Open();

            Console.WriteLine("Press Enter to exit...");
            Console.ReadLine();

            myHost.Close();
        }

If we’ve done everything correctly, the console application should start up and display the “press enter” message. However, we have no way to know if we’re actually connected to the service bus. Lets add two more “using” clauses, Microsoft.ServiceBus and System.ServiceModel.Description. Next, between the declaration of the service host and its opening, we need to insert a few extra lines.

            // set endpoint as publically discoverable
            ServiceRegistrySettings settings = new ServiceRegistrySettings();
            settings.DiscoveryMode = DiscoveryType.Public;

            // set all host endpoints as publically visible
            foreach (ServiceEndpoint se in myHost.Description.Endpoints)
                se.Behaviors.Add(settings);

This code sets the service so its discoverable. You can see it by going to the ATOM feed for our service. Here’s mine…

image

No, I’m not afraid of sharing this. Because without my password, you still can’t use the service. I just wanted to touch on this for now. So we’ll leave a more in-depth discussion on security and the Access Control Service for another post.

The Service Client

With the service bus host built and running, we’re ready to build a client to consume our service. Add the same references to the ServiceClient project that we added to SimpleService: SimpleServiceDefs, ServiceModel and ServiceBus. We’ll also add an app.config file and copy the contents of the app.config used for our service to the client. We’re gonna make one minor tweak to the config by adding a name attribute to the endpoint node as shown below.

      <endpoint address="sb://[solution].servicebus.windows.net/SimpleService/"
                binding="netTcpRelayBinding"
                contract="SimpleServiceDefs.iSimpleService"
                name="RelayEndpoint" 
                behaviorConfiguration="default" />

Now we dive into the code of our client. We’ll add using clauses for ServiceModel and SimpleServiceDefs, then paste the following into the ‘Main’ method.

            ChannelFactory<iSimpleService> channelFactory =
                new ChannelFactory<iSimpleService>("RelayEndpoint");
            iSimpleService channel = channelFactory.CreateChannel();

            DateTime response = channel.GetDate();

            Console.WriteLine("Current Date is {0}", response.ToShortDateString());
            Console.WriteLine("Press enter to end program.");
            Console.ReadLine();

            channelFactory.Close();

In this code, we declare our WCF channel, call the remote service (channel.GetDate), and then display the result on the screen. While my method returns a date, you could just as easily return a string, or pass some parameters and operate on them. But lets test it and make sure it works.

Start by running the service host application manually. I find it easiest to just right-click on the project in the solution explorer and click the “Open Folder in Windows Explorer” option. Once you get its “press enter” message, we’re ready to run the client. Make the ServiceClient application our start project and then start debugging it. If all goes well, you could end up with two console windows like these…

SimpleService_Console   SimpleService_Client

On the next episode of “As the Cloud Turns”…

Before I close things out for this post, I want to thank Aaron Skonnard of Pluralsight for his great whitepapers, the folks on the MSDN forums, and all the tweeps on twitter. They’ve all helped me get a hand on the .NSB and WCF. Its a great community and I hope I’m at least giving back as much as I’m getting.

That’s all I have for today, but not all I have to share with you. In the coming weeks we’ll cover topics such as security, queues and routers, and hosting our services in Windows Azure worker roles. Once those topics have been covered, we’ll move on to the Access Control service, and once its available again, even hosted Workflows.

Till then, thanks for reading and be sure to drop me a comment to let me know if there’s anything related to this topic you’d like to see. TTFN!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: