Blog Home  Home Feed your aggregator (RSS 2.0)  
.Net Jonesie - Azure .Net Service Bus & TCP
A simple programmers blog
 
# Wednesday, July 22, 2009

We recently implemented the .Net Service bus to expose some in-house WCF services to the world wide world. It may be useful for me and others if I describe how to do this :) This setup allows you to switch between tcp and http relay binding with configuration.

The Host

For the in-house systems you need to create a host – you cant use IIS as the service bus requires a connection to be initiated by both ends of the communication.  We created a Windows Service application that also runs as a console app.  This is much simpler when developing and debugging.  To create this service:

1) create a new windows service using the standard VS template and add a reference to Microsoft.ServiceBus (in addition to your service and data contracts which I hope are in separate assemblies!)

2) change the Application Output Type to Console Applications.

3) add some code to Program.cs to flick to console mode:

if (args.Length > 0 && args[0].ToLower() == "/console")
{
  myService.RunConsole(args);
}
else
{
  ServiceBase.Run(ServicesToRun);
}

4) in your service code add the following method:

internal void RunConsole(string[] args)
{
  OnStart(args);
  Console.WriteLine("My ServiceHost is running... Press Enter to stop the service");
  Console.ReadLine();
  OnStop();
}

Now for the service bus stuff.

5) in the service class, add a member for the service host:

ServiceHost _host = null;

6) in the OnStart method of your service add the following :

// create a behavior for the service bus – it need creds of some type
TransportClientEndpointBehavior behavior = new TransportClientEndpointBehavior();
behavior.CredentialType = TransportClientCredentialType.UserNamePassword;
behavior.Credentials.UserName.UserName = Properties.Settings.Default.ServiceBusSolutionName;
behavior.Credentials.UserName.Password = Properties.Settings.Default.ServiceBusPassword;

// create an address for the service bus.  config allows a switch between tcp and http
Uri address;

if(Properties.Settings.Default.ServiceBusBinding == "nettcp")
{

  address = ServiceBusEnvironment.CreateServiceUri("sb", Properties.Settings.Default.ServiceBusSolutionName, Properties.Settings.Default.ServiceBusServiceName);
}
else
  if(Properties.Settings.Default.ServiceBusBinding == "basichttp")
  {
    address = ServiceBusEnvironment.CreateServiceUri("http", Properties.Settings.Default.ServiceBusSolutionName, Properties.Settings.Default.ServiceBusServiceName);
  }
  else
    throw new ArgumentException("Invalid binding for Service Bus");

// create the host
_host = new ServiceHost(typeof(MyService), address);

// update all the end points with the new behavior – you may need more than one – or not – up to you
foreach (ServiceEndpoint endpoint in _host.Description.Endpoints)
{
    endpoint.Behaviors.Add(behavior);
}

// open the portal to another dimension – a dimension of sight and sound
_host.Open();

Now for some config.  For me this was the hardest part.  Hard coding WCF config is much simpler!

7) create some service model bindings for netTcpRelayBinding & basicHttpRelayBinding

<bindings>
  <netTcpRelayBinding>
    <binding name="default" />
  </netTcpRelayBinding>
  <basicHttpRelayBinding>
    <binding name="default">
      <security mode="None" />
    </binding>
  </basicHttpRelayBinding>
</bindings>

8) add an endpoint for your service:

<endpoint name="MyServiceEndpoint"
          address=""
          binding="netTcpRelayBinding"
          contract="MyApp.ServiceContracts.IMyService"
          bindingConfiguration="default" />

 

9) if you want to use  basic http then add this instead:

<endpoint name="MyServiceEndpoint"
                address=
http://mysolution.servicebus.windows.net/MyService
                binding="basicHttpRelayBinding"
                contract="MyApp.ServiceContracts.IMyService"
                bindingConfiguration="default" />

And that’s about it for the service host.  If you need to have metadata support (WSDL) then that’s a whole other story that I will try to blog about seperately.

The Client

Azure worker roles do not have a web or app .config you can use for WCF configuration settings.  Web roles do have a web.config but this can only be changed by a redeploy of package so it’s not the best idea to put anything but service configuration in there.  In my case, I needed to access the in-house services from both the web and worker roles so I created a class lib project with a single helper class.

1) create a Windows Class Library and add references for Microsoft.ServiceBus plus your service and data contracts.

2) Create a static class with a single static method – call it what you like but something like GetClientChannel() will do.  Add the following code:

IMyChannel channel;  // this is a simple combo interface of IChannel and IMyService

Uri address;


// create the behavior for SB creds
TransportClientEndpointBehavior behavior = new TransportClientEndpointBehavior();
behavior.CredentialType = TransportClientCredentialType.UserNamePassword;

// get the creds from the cloud config
behavior.Credentials.UserName.UserName = RoleManager.GetConfigurationSetting("ServiceBusSolutionName");
behavior.Credentials.UserName.Password = RoleManager.GetConfigurationSetting("ServiceBusPassword");

// create a channel factory

ChannelFactory<IMyChannel> channelFactory = new ChannelFactory<IMyChannel>();

// create the binding – config allows us to select http or tcp

if (RoleManager.GetConfigurationSetting("ServiceBusBinding").ToLower() == "basichttp")
{
  channelFactory.Endpoint.Binding = new BasicHttpRelayBinding(EndToEndBasicHttpSecurityMode.None, RelayClientAuthenticationType.None);
  address = ServiceBusEnvironment.CreateServiceUri("http", RoleManager.GetConfigurationSetting("ServiceBusSolutionName"), RoleManager.GetConfigurationSetting("ServiceBusServiceName"));
}
else if (RoleManager.GetConfigurationSetting("ServiceBusBinding").ToLower() == "nettcp")
{
  channelFactory.Endpoint.Binding = new NetTcpRelayBinding(EndToEndSecurityMode.Transport, RelayClientAuthenticationType.None);
  address = ServiceBusEnvironment.CreateServiceUri("sb", RoleManager.GetConfigurationSetting("ServiceBusSolutionName"), RoleManager.GetConfigurationSetting("ServiceBusServiceName"));
}
else
{
  throw new ArgumentException("Invalid service bus binding configuration option: " + RoleManager.GetConfigurationSetting("ServiceBusBinding"));
}

// update the factory for A B & C

channelFactory.Endpoint.Address = new EndpointAddress(address);
channelFactory.Endpoint.Behaviors.Add(behavior);

channelFactory.Endpoint.Contract.ContractType = typeof(ICRMChannel);

channel = channelFactory.CreateChannel(new EndpointAddress(address));
channel.Open();

return channel;

 

Tada!  All done.  Provided I haven’t introduced any bugs then this should give you a connection to you in-house services, by passing any firewall crap that those pesky IT people seem to insist on.

Enjoy :)

Wednesday, July 22, 2009 9:42:56 AM (New Zealand Standard Time, UTC+12:00)  #    Comments [0]    | 
Comments are closed.
Copyright © 2012 Peter G Jones. All rights reserved.
DasBlog 'Portal' theme by Johnny Hughes.
Pick a theme: