Tuesday, July 19, 2011

Windows Azure Service Bus configuration and accessing on-premise WCF service using service bus in a web role application


Azure Service Bus configuration and accessing on-premise WCF service using service bus in a web role application.
Finally, after 1 month, I learned a new feature of Azure. It is AppFabric Service bus. Pretty cool stuff!!
Today, I will be talking about service bus basics and what code you need to write to make it work. Ok, so here we go!!


In simple terms, Service Bus is intended to be used on-premises to publish service endpoints on Internet that can't be accessed from Internet because the existing firewalls or NAT (Network Address Translators).
Network devices like these typically allow applications to initiate outbound network connections but prevent them from accepting inbound network connections. To establish a connection through these types of network devices, developers often end up writing custom logic that deals with establishing connections across network topologies. Because there are many different types of network topologies, this logic often becomes very complex and cumbersome.
The AppFabric Service Bus provides the communication infrastructure that protects all of us from having to create the complex code necessary to achieve connectivity (I really love this!!). It allows you to expose a service to the Internet from behind your firewall or NAT (I really really like it!!).
The good part of Service Bus is, it is built on Windows Communication Foundation (WCF) and uses standard internet protocols.


Alright, enough of theory. Time to go for some coding part.
We need to configure the Service bus in our Azure Portal subscription first. Then we will use this Azure Portal Service Bus Configuration in our visual studio application.
Login to Azure Portal and click on “Service Bus, Access control and Caching” button in left hand panel. Then select “service Bus” option. Click on “NEW” button present in upper left panel. This opens a window where Service Bus configuration details are asked.
Provide service namespace name in appropriate textbox. A service namespace provides an application boundary for each application exposed through the Service Bus and is used to construct service bus endpoints for the application. Provide namespace (check the availability), country/ Region, and Connection pack size information. Then click on “Create Namespace” button. This completes the service bus configuration on Azure Management Portal.
Create a project in visual studio containing Cloud Project, web Role, WCF service library and a console application which will act as a host for WCF. We will host WCF in Console application and access in cloud web role through service bus. The solution structure is as follows.

Add reference of WCF library to web role project, so that we will be able to access WCF contract (In our case IService1 as shown in above screenshot) in the web role application. In real practice you should create separate library having only service contracts and another library having only implementation of these contracts. Then add reference of only contract library to web role project.
For the demo purpose I am adding reference of WCF library having contract and its implementation in the same library, to web role project.
Modify GetData method and add custom description string in the code in Service1.cs as shown –
public string GetData(int value)
        {
            return "I am on-premise WCF service and being accessed in cloud web role through service bus configuration.";
        }
Also add a label to Default.aspx in web role project. Now delete app.config file from WCF library project. Then add reference of WCF library project to console application. Then add app.config file in console application and add following code –

<?xml version="1.0"?>
<configuration>
  <system.serviceModel>
    <bindings>
      <netTcpRelayBinding>
        <binding name="TestTimeouts" closeTimeout="01:00:10" openTimeout="01:00:10" receiveTimeout="01:00:10" sendTimeout="01:00:10">
          <reliableSession ordered="false" enabled="false"/>
        </binding>
      </netTcpRelayBinding>

      <basicHttpBinding>
      </basicHttpBinding>

      <customBinding>
      </customBinding>
    </bindings>
    <services>
      <!--service endpoint-->
      <service name="SampleWcfServiceLibrary.Service1">
        <endpoint
          address=""
          name="ServiceEndpoint"
          contract="SampleWcfServiceLibrary.IService1"
          binding="netTcpRelayBinding"
          bindingConfiguration="TestTimeouts"
          behaviorConfiguration="sharedSecretCredentials"
          >
        </endpoint>
      </service>
    </services>
    <behaviors>
      <endpointBehaviors>
        <behavior name="sharedSecretCredentials">
          <transportClientEndpointBehavior credentialType="SharedSecret">
            <clientCredentials>
              <sharedSecret issuerName="owner" issuerSecret="YourSecretKey- Obtain from Azure Portal Service Bus panel - Default key button."/>
            </clientCredentials>
          </transportClientEndpointBehavior>
        </behavior>
      </endpointBehaviors>
    </behaviors>

    <client>
    </client>
  </system.serviceModel>
 
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>


The behavior part “sharedSecretCredentials” above is actually Appfabric Access Control which is used to secure the Service Bus endpoints. To accomplish this task, AC receives an issuer name and an issuer secret (32-bit key). If they are correctly authenticated, it issues a security token (called Simple Web Token) that is then trusted by the service itself. All messages sent to and via the Service Bus must contain a valid security token. I have configured it through app.config.
Open web.config file of web role and add following code in <configuration> section –

<system.serviceModel>   
    <bindings>
      <netTcpRelayBinding>
        <binding name="TestTimeouts" closeTimeout="01:00:10" openTimeout="01:00:10" receiveTimeout="01:00:10" sendTimeout="01:00:10" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" maxBufferPoolSize="2147483647">
          <reliableSession ordered="false" enabled="false" />
        </binding>
      </netTcpRelayBinding>

      <customBinding>       
      </customBinding>

      <basicHttpBinding>       
      </basicHttpBinding>
    </bindings>
    <client>
      <!--WCF service endpoint-->
      <endpoint address="sb://YourServiceBusNameSpace.servicebus.windows.net/myservice" name="ServiceEndpoint" contract="SampleWcfServiceLibrary.IService1" binding="netTcpRelayBinding" bindingConfiguration="TestTimeouts" behaviorConfiguration="sharedSecretCredentials">
      </endpoint>
     
    </client>
    <behaviors>
      <endpointBehaviors>
        <behavior name="sharedSecretCredentials">
          <transportClientEndpointBehavior credentialType="SharedSecret">
            <clientCredentials>
              <sharedSecret issuerName="owner" issuerSecret="YourSecretKey- Obtain from Azure Portal Service Bus panel - Default key button."/>
            </clientCredentials>
          </transportClientEndpointBehavior>
        </behavior>
      </endpointBehaviors>
    </behaviors>
  </system.serviceModel>

Yellow marked area above will change with your values obtained from Azure Portal. Red marked area – “myservice” we will use in next section. Red marked area – “Serviceendpoint” is same as value given in app.config of console host project.
Now it is time to write code for service bus configuration in console host project for hosting WCF. Add reference of Microsoft.ServiceBus.dll from GAC to console host project. Path for dll is - C:\Windows\assembly\GAC_MSIL\Microsoft.ServiceBus\1.0.0.0__31bf3856ad364e35\Microsoft.ServiceBus.dll
Another path can be - %ProgramFiles%\Windows Azure AppFabric SDK\V1.0\Assemblies\NET4.0
Also add reference of Service model dll.
Open Program.cs of console application and add following code -
Using block - using System.ServiceModel;
using Microsoft.ServiceBus;
using SampleWcfServiceLibrary;

code under main method -
ServiceBusEnvironment.SystemConnectivity.Mode = ConnectivityMode.Http;

            //open WCF service           
            Uri address = ServiceBusEnvironment.CreateServiceUri("sb", "YourServiceBusNameSpace", "myservice");
            ServiceHost host = new ServiceHost(typeof(Service1), address);
            host.Open();
            Console.WriteLine("Service open at: " + address.ToString());
            Console.ReadLine();

Red marked is same as name used in endpoint in web.config of web role.
Preparing Client for WCF hosted using Service Bus –
Add reference of System.ServiceModel.dll to web role project. In Page load of default.aspx write following code –
using (ChannelFactory<IService1> factory = new ChannelFactory<IService1>("ServiceEndpoint"))//same name as given in app config file of console host
            {
                //create channel for service endpoint
                var client = factory.CreateChannel();

                //retrieve data and populate the details
                string dataFromWCF = client.GetData(5);

                //populate to label
                Label1.Text = dataFromWCF;               
            }

Run console application. This will open WCF. Then run your web role in development environment and get the desired output on web page. J
This completes the service bus configuration for on premise WCF and client of WCF. In our case client of WCF or the application that consumes WCF is web role.
Next host your web role in Azure and access the web role default.aspx page. This will internally call the service bus through which on-premise WCF will be accessed.
Big article but I tried at my level best to make it simple.
Cheers…
Happy Coding!!

2 comments:

  1. Sanganak,

    Nice post, can you do a similar post for hosting the on-premise wcf service on IIS and accessing it via service bus ?

    ReplyDelete
  2. Hi pavan,
    I think if you configure above WCF with all config settings in IIS then it should work. Hope this helps.

    ReplyDelete