The code for this solution can be found in GitHub.
I had a common firewall problem. I needed to connect to a service behind a firewall. Normally, this would have two possible solutions:
- Open a port in the firewal
- Setup a VPN to the network
#1 can be a massive politicial hurdle. IT and security staff usually only allow well-known and common services through their firewall.
#2 can be equally difficult. There’s pricing and infrastructure fees to be discussed.
Both of these options bring too many other people into the discussion. One major factor to software delivery delays are the inclusion of too many third parties and external resources. Azure Service Bus Relay gives me a third option.
Service Bus Relay allows me to make a persistent connection to Azure from inside a firewall. A client can connect to the service via the relay as if it was a direct connection.
The first step to this is to add a service bus namespace to your Azure account.
Select Service Bus from your portal screen.
Select the Create A New Namespace.
Choose a namespace and region. The namespace will be used in the code configuration. Note: when providing the namespace use only the namespace you provide, NOT **NAMESPACE**.servicebus.windows.net.
Lastly, get the Connection Information.
You’ll need the owner and default key
Following these instructions, you should have three pieces of information:
- Namespace
- Owner
- Default Key
This is all that’s needed to use the service bus from Azure. Now, on to the code which can be downloaded from GitHub. There are three projects, a client, a server, and a common interface. Let’s look at the common inteface first.
For this example, we’re using the ever-popular calculator with an interface defined as:
[ServiceContract(Name = "IBasicMath", Namespace = "http://samples.microsoft.com/ServiceModel/Relay/")]
public interface IBasicMath
{
[OperationContract(IsOneWay = false)]
double PerformOperation(double first, double second, Operation operation);
}
public interface IBasicMathChannel : IBasicMath, IClientChannel { }
You’ll see a few extra points here. There’s also a IBasicMathChannel interface. This is used by the client’s channel factory. The IBasicMath interface is defined as a ServiceContract with a single method which is expected to return a double.
The server code is very simple:
static void Main(string[] args)
{
string serviceNamespace = "";
string issuerName = "";
string issuerSecret = "";
TransportClientEndpointBehavior relayCredentials = new TransportClientEndpointBehavior();
relayCredentials.TokenProvider = TokenProvider.CreateSharedSecretTokenProvider(issuerName, issuerSecret);
Uri address = ServiceBusEnvironment.CreateServiceUri("sb", serviceNamespace, "BasicMath");
ServiceHost host = new ServiceHost(typeof(BasicMath), address);
host.AddServiceEndpoint(typeof(IBasicMath), new NetTcpRelayBinding(), address).Behaviors.Add(relayCredentials);
host.Open();
Console.WriteLine("Service address: " + address);
Console.WriteLine("Press [Enter] to exit");
Console.ReadLine();
host.Close();
}
In the first three variables, you’ll need to enter the information collected in the Azure setup. The steps are fairly easy.
- Create the credentials
- Create the service uri using any name you want. This must match in the client!
- Create the host specifying the ServiceContract inteface and NetTcpRelayBinding for relay support.
- Open the host
I’m using a console in this example with ReadLine() to hold the service open.
The client code is very similar:
string serviceNamespace = "";
string issuerName = "";
string issuerSecret = "";
TransportClientEndpointBehavior relayCredentials = new TransportClientEndpointBehavior();
relayCredentials.TokenProvider = TokenProvider.CreateSharedSecretTokenProvider(issuerName, issuerSecret);
Uri serviceUri = ServiceBusEnvironment.CreateServiceUri("sb", serviceNamespace, "BasicMath");
ChannelFactory channelFactory = new ChannelFactory(new NetTcpRelayBinding(), new EndpointAddress(serviceUri));
channelFactory.Endpoint.Behaviors.Add(relayCredentials);
IBasicMathChannel channel = channelFactory.CreateChannel();
channel.Open();
Console.WriteLine("Press any key to exit");
Random rnd = new Random();
while (!Console.KeyAvailable)
{
double retval = channel.PerformOperation(rnd.Next(1, 40), rnd.Next(1, 40), Operation.ADD);
Console.WriteLine("return value = {0}", retval);
}
channel.Close();
channelFactory.Close();
- Add the Azure information
- Create the credentials
- Create the service URI
Instead of creating a host, the client uses the ChannelFactory to create a channel (IBasicMathChannel) which exposes our interface (IBasicMath). This allows us to call our “PerformOperation” method on the channel and get the value.
I hope you find this helpful. This is a good tool to have in your box when you need to write services which need access across firewalls.