Azure Service Bus Relay with WCF Routing Service

Azure Service Bus (SB) Relay provides us the ability create public endpoints for our internal on-premise/ corporate WCF services that resides behind proxy/firewall. This is quite useful during the development phase of any external apps that consume any on-premise LOB services. For example we can use our development cloud (MSDN) that in most cases don’t have Site to Site VPN setup to connect to these services. But if our app talk to more than 1 on premise services then each of them requires a SB Relay endpoint, so we need to manage multiple endpoint that point to the SB namespace. Luckily WCF 4.0 support routing service that enable message forwarding based on the different rules such as endpoint addresses. This diagram below shows the architecture:

SBRelayRoutingA WCF routing service host with  Azure Bus Relay endpoint maintains a routing table that maps the request URLs to on premise WCF service endpoints. I will outline the steps to set this up though it won’t be detail steps as most of them are covered in these MSDN articles (article_1 and article_2). So basically we need to combined the configuration from both articles.

  1. Setup Windows Azure Service Namespace as shown in this article_1. Let say that the service namespace is MyRouting
  2. Setup the Routing Service with Service Bus Endpoint: Create a Visual Studio’s Console Application or Windows Service, Add the Windows Azure Service Bus NuGet package (it will add the require dll and also add some WCF extensions that used by Service Bus Relay  in the app.config) and also System.ServiceModel.dll as well as System.ServiceModel.Routing.dll.
  3. In your console app’s program.cs (in windows service you add this routine in OnStart & OnStop methods) add the code below as shown in this article_2
     public static void Main(string[] args)
     {
        var host = new ServiceHost(typeof(RoutingService));
        host.Open();
        Console.WriteLine("host is listening");
        Console.ReadLine();
        host.Close();
     }
  4. Configuring the service host with SB endpoint and routing capability. Basically it combines the service host endpoint configuration as shown in this article 1 and routing xml as shown in the article 2. Which ending up likes below:
    <services>
          <service behaviorConfiguration="RoutingConfiguration"
                   name="System.ServiceModel.Routing.RoutingService">
            <endpoint binding="basicHttpRelayBinding"
                      contract="System.ServiceModel.Routing.IRequestReplyRouter"
                      address="https://myrouting.servicebus.windows.net/rttest"
                      behaviorConfiguration="sbTokenProvider"
                      bindingConfiguration="httpServiceBusBinding"/>
          </service>
    </services>

    The routing is defined in the service’s behavior configuration called Routing Configuration, it contains the ‘routing table’. As the endpoint is using the basicHttpRelayBinding the address is using https protocol.

  5. The behavior configuration as shown as below
     <behaviors>
          <serviceBehaviors>
            <behavior name="RoutingConfiguration">
              <routing filterTableName="LOBFilterTable" routeOnHeadersOnly="false" />
              <serviceDebug includeExceptionDetailInFaults="False"  />
            </behavior>
          </serviceBehaviors>
          <endpointBehaviors>
            <behavior name="sbTokenProvider">
              <transportClientEndpointBehavior>
                <tokenProvider>
                  <sharedSecret issuerName="owner" issuerSecret="**key**" />
                </tokenProvider>
              </transportClientEndpointBehavior>
            </behavior>
          </endpointBehaviors>
    </behaviors>
    <bindings>
           <basicHttpRelayBinding>
              <binding name="httpServiceBusBinding">
                <security mode="Transport" relayClientAuthenticationType="None" />
              </binding>
           </basicHttpRelayBinding>
    </bindings>

    The RoutingConfiguration defines the routing table with name LOBFilterTable and the Service Bus Relay endpoint is using sbTokenProvider endpoint’s behavior connect to the Azure Service Bus Relay. As my on-premise WCF services are using the basicHttpBinding, I use basicHttpRelayBinding for the Azure Service Bus endpoint’s binding.

  6. Next step is defining the routing table as shown below. The filterTable matches the filters with the client’s endpoint. The routing is based on EndpointAddress (this article shows different filter that we can use in WCF Routing Service), in this case the public endpoint on service bus is mapped to wcf client’s endpoint (on-premise WCF services endpoint).
     <routing>
          <filters>
            <filter name="LobSvc_A" filterType="EndpointAddress" filterData="https://myrouting.servicebus.windows.net/rttest/WcfEndpointA" />
            <filter name="LobSvc_B" filterType="EndpointAddress" filterData="https://myrouting.servicebus.windows.net/rttest/WcfEndpointB"/>
            <filter name="LobSvc_C" filterType="EndpointAddress" filterData="https://myrouting.servicebus.windows.net/rttest/WcfEndpointC"/>
          </filters>
          <filterTables>
            <filterTable name="LOBFilterTable">
              <add filterName="LobSvc_A" endpointName="LobSvc_A_Client" />
              <add filterName="LobSvc_B" endpointName="LobSvc_B_Client"/>
              <add filterName="LobSvc_B" endpointName="LobSvc_C_Client"/>
            </filterTable>
          </filterTables>
    </routing>
  7. Finally we put the client configuration as shown below. As you can see that the client endpoint’s names match with those in the filterTable
    <client>
      <endpoint address="your.onPremise.WCF.A.url" contract="*"
            binding="basicHttpBinding" name="LobSvc_A_Client" />
      <endpoint address="your.onPremise.WCF.B.url" contract="*"
            binding="basicHttpBinding" name="LobSvc_B_Client" />
      <endpoint address="your.onPremise.WCF.C.url" contract="*"
            binding="basicHttpBinding" name="LobSvc_C_Client" />
    </client>

    Of course you can add your own binding configuration and endpoint’s behavior to the client, such as connect using certain credentials. We have finished with the host so the next step is setting up the client connect this host.

  8. The client can be a web role in Azure or any external applications that need to connect to the on-premise WCF services. This code below show a generic method to create Service Bus Channel. the endpoint string parameter is the last part of endpoint in the filterdata filter’s configuration. In our example it can be WcfEndpointA, WcfEndpointB or WcfEndpointC, so WcfEndpointA will be routed to on-premise WCF A service.
     private static ChannelFactory<T> CreateChannelFactory<T>(string endPoint)
     {
       var binding = new BasicHttpRelayBinding();
       binding.Security.Mode = EndToEndBasicHttpSecurityMode.Transport;
       binding.Security.RelayClientAuthenticationType = RelayClientAuthenticationType.None;
                
       var serviceBusEndpoint = new EndpointAddress(ServiceBusEnvironment.CreateServiceUri("https", "myrouting", "rttest/" + endPoint));
       ChannelFactory<T> sbChannelFactory = new ChannelFactory<T>(binding, serviceBusEndpoint);
       sbChannelFactory.Endpoint.Behaviors.Add(
              new TransportClientEndpointBehavior { 
                 TokenProvider = TokenProvider.CreateSharedSecretTokenProvider("owner", "your sb secret key") 
       });
       return sbChannelFactory;
     }
  9. In conclusion we can have one Service Bus Endpoint that map to many on-premise WCF Services by utilizing WCF Routing Service capability.

Comments are closed.