Wednesday 11 January 2012

Implementing Azure AppFabric Service Bus - Part 3



In my last post, I had explained about how to create service bus namespace. From this post, we will consider creating a WCF Service and exposing to Azure Service Bus.

Below are the steps followed.

Step 1: Open Visual Studio 2010 and select New Project from Start Page (or File => New => Project) for creating new WCF Service project.

The Visual Studio must start in Administrative mode. So, right click the Visual studio shortcut and select Run as Administrator when opening Visual studio.

Step 2: Select the preferred language (here C#) and WCF Service Application (from WCF) from the Installed Templates. Enter the project name (DotNetTwitterSOPService) and preferred Location then press OK to create.


Step 3: (Optional) By default Visual Studio will add Service1.svc, IService1.cs files in the project. We are not planning to use this service, so if required delete those files.

Step 4: As I already explained in previous post, we are creating this service for doing CRUD operations on Customer data. So we required to define a data contract class for Customer data.

So, right click the project, select Add => Class (Shift + Alt + C) and provide class name (Customer.cs) for adding a new class into the project.


Note: I am going to use Northwind database configured in my on-premise SQL Server for data storage. So make sure to have Northwind database for implementing this source code. (You can get the database script from here)

Step 5: Define the list of properties in the Customer class. Use the below is the source code.
[DataContract]
public class Customer
{
    [DataMember]
    public string CustomerID { get; set; }

    [DataMember]
    public string CompanyName { get; set; }

    [DataMember]
    public string ContactName { get; set; }

    [DataMember]
    public string ContactTitle { get; set; }

    [DataMember]
    public string Address { get; set; }

    [DataMember]
    public string City { get; set; }

    [DataMember]
    public string Region { get; set; }

    [DataMember]
    public string PostalCode { get; set; }

    [DataMember]
    public string Country { get; set; }

    [DataMember]
    public string Phone { get; set; }

    [DataMember]
    public string Fax { get; set; }
}

Add below namespace reference in the header
using System.Runtime.Serialization;
Step 6: Now we can create a Customer Service for defining the Customer data operations.

Right click the project and select Add => New Item. Select WCF Service from the Installed Template and provide the file name (CustomerService.svc). Press Add.


Visual Studio will add three files such as ICustomerService.cs, CustomerService.svc and CustomerService.svc.cs in the project.

Step 7: Before doing any operations for each operation contract, we required to define the connection string in the Web.Config file. So open the Web.Config file and define the connection string with key name as SQLConnection.
<connectionStrings>
  <add name="SQLConnection" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=Northwind;User Id=sa; Password=test@123;" providerName="System.Data.SqlClient" />
</connectionStrings>
Step 8: Open the ICustomerService.cs file and define the Service Contract for the interface ICustomerService.
/// <summary>
/// Interface for defining the Customer Service functionalities.
/// </summary>
[ServiceContract]
public interface ICustomerService
{
    /// <summary>
    /// Method to get all the Customers
    /// </summary>
    /// <returns>List of Customers</returns>
    [OperationContract]
    IList<Customer> GetAll();

    /// <summary>
    /// Method to get a particular Customer based on Customer Id
    /// </summary>
    /// <param name="customerID">Customer Id</param>
    /// <returns>Customer Object</returns>
    [OperationContract]
    Customer Get(string customerID);

    /// <summary>
    /// Method to create a new Customer record in the system
    /// </summary>
    /// <param name="customer">Customer object</param>
    /// <returns>No of Row affected</returns>
    [OperationContract]
    int Create(Customer customer);

    /// <summary>
    /// Method to Update existing Customer in the System
    /// </summary>
    /// <param name="customer">Customer object</param>
    /// <returns>No of Row affected</returns>
    [OperationContract]
    int Update(Customer customer);

    /// <summary>
    /// Method to Delete an existing Customer from the system
    /// </summary>
    /// <param name="customerID">Customer Id</param>
    /// <returns>No of Row affected</returns>
    [OperationContract]
    int Delete(string customerID);
}
The code contains the comments for explaining what each contract is for.

Step 9: Open the CustomerService.svc.cs file and define the operations for each operation contract defined in service contract ICustomerService.
public class CustomerService : ICustomerService
{
    /// <summary>
    /// Method to get all the Customers
    /// </summary>
    /// <returns>List of Customers</returns>
    public IList<Customer> GetAll()
    {
        try
        {
            // Opening the connection
            using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLConnection"].ConnectionString))
            {
                string strSQL = "Select CustomerID, CompanyName, ContactName, ContactTitle, Address, City, Region, PostalCode, Country, Phone, Fax From Customers";
                SqlCommand command = new SqlCommand(strSQL, connection);

                connection.Open();
                SqlDataReader dr = command.ExecuteReader(CommandBehavior.CloseConnection);

                IList<Customer> customerList = new List<Customer>();
                while (dr.Read())
                {
                    Customer customer = new Customer();
                    customer.CustomerID = dr["CustomerID"].ToString();
                    customer.CompanyName = dr["CompanyName"].ToString();
                    customer.ContactName = dr["ContactName"].ToString();
                    customer.ContactTitle = dr["ContactTitle"].ToString();
                    customer.Address = dr["Address"].ToString();
                    customer.City = dr["City"].ToString();
                    customer.Region = dr["Region"].ToString();
                    customer.PostalCode = dr["PostalCode"].ToString();
                    customer.Country = dr["Country"].ToString();
                    customer.Phone = dr["Phone"].ToString();
                    customer.Fax = dr["Fax"].ToString();

                    customerList.Add(customer);
                }
                return customerList;
            }
        }
        catch (Exception ex)
        {
            // Log
        }
        throw null;
    }

    /// <summary>
    /// Method to get a particular Customer based on Customer Id
    /// </summary>
    /// <param name="customerID">Customer Id</param>
    /// <returns>Customer Object</returns>
    public Customer Get(string customerID)
    {
        try
        {
            using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLConnection"].ConnectionString))
            {
                string strSQL = "Select CustomerID, CompanyName, ContactName, ContactTitle, Address, City, Region, PostalCode, Country, Phone, Fax From Customers " +
                                "Where CustomerID = '" + customerID + "'";
                SqlCommand command = new SqlCommand(strSQL, connection);

                connection.Open();
                SqlDataReader dr = command.ExecuteReader(CommandBehavior.CloseConnection);

                Customer customer = new Customer();
                while (dr.Read()) // If more then one record for a customer, it will return last one
                {
                    customer.CustomerID = dr["CustomerID"].ToString();
                    customer.CompanyName = dr["CompanyName"].ToString();
                    customer.ContactName = dr["ContactName"].ToString();
                    customer.ContactTitle = dr["ContactTitle"].ToString();
                    customer.Address = dr["Address"].ToString();
                    customer.City = dr["City"].ToString();
                    customer.Region = dr["Region"].ToString();
                    customer.PostalCode = dr["PostalCode"].ToString();
                    customer.Country = dr["Country"].ToString();
                    customer.Phone = dr["Phone"].ToString();
                    customer.Fax = dr["Fax"].ToString();
                }
                return customer;
            }
        }
        catch (Exception ex)
        {
            // Log
        }
        throw null;
    }

    /// <summary>
    /// Method to create a new Customer record in the system
    /// </summary>
    /// <param name="customer">Customer object</param>
    /// <returns>No of Row affected</returns>
    public int Create(Customer customer)
    {
        try
        {
            using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLConnection"].ConnectionString))
            {
                string strSQL = "Insert into Customers (CustomerID, CompanyName, ContactName, ContactTitle, Address, City, Region, Country, Phone, Fax) " +
                                "values ('" + customer.CustomerID.Replace("'", "") + "', '" + customer.CompanyName.Replace("'", "''") + "', '" +
                                                customer.ContactName.Replace("'", "''") + "', '" + customer.ContactTitle.Replace("'", "''") + "', '" +
                                                customer.Address.Replace("'", "''") + "', '" + customer.City.Replace("'", "''") + "', '" +
                                                customer.Region.Replace("'", "''") + "', '" + customer.Country.Replace("'", "''") + "', '" +
                                                customer.Phone.Replace("'", "''") + "', '" + customer.Fax.Replace("'", "''") + "')";

                SqlCommand command = new SqlCommand(strSQL, connection);

                connection.Open();

                return command.ExecuteNonQuery();
            }
        }
        catch (Exception ex)
        {
            // Log
        }
        return 0;
    }

    /// <summary>
    /// Method to Update existing Customer in the System
    /// </summary>
    /// <param name="customer">Customer object</param>
    /// <returns>No of Row affected</returns>
    public int Update(Customer customer)
    {
        try
        {
            using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLConnection"].ConnectionString))
            {
                string strSQL = "Update Customers Set " +
                                " CompanyName = '" + customer.CompanyName.Replace("'", "''") + "'," +
                                " ContactName = '" + customer.ContactName.Replace("'", "''") + "'," +
                                " ContactTitle = '" + customer.ContactTitle.Replace("'", "''") + "'," +
                                " Address = '" + customer.Address.Replace("'", "''") + "'," +
                                " City = '" + customer.City.Replace("'", "''") + "'," +
                                " Region = '" + customer.Region.Replace("'", "''") + "'," +
                                " Country = '" + customer.Country.Replace("'", "''") + "'," +
                                " Phone = '" + customer.Phone.Replace("'", "''") + "'," +
                                " Fax = '" + customer.Fax.Replace("'", "''") + "'" +
                                " Where CustomerID = '" + customer.CustomerID + "'";

                SqlCommand command = new SqlCommand(strSQL, connection);

                connection.Open();

                return command.ExecuteNonQuery();
            }
        }
        catch (Exception ex)
        {
            // Log
        }
        return 0;
    }

    /// <summary>
    /// Method to Delete an existing Customer from the system
    /// </summary>
    /// <param name="customer">Customer object</param>
    /// <returns>No of Row affected</returns>
    public int Delete(string customerID)
    {
        try
        {
            Customer customer = Get(customerID);
            using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLConnection"].ConnectionString))
            {
                string strSQL = "Delete from Customers Where CustomerID = '" + customer.CustomerID + "'";

                SqlCommand command = new SqlCommand(strSQL, connection);

                connection.Open();

                return command.ExecuteNonQuery();
            }
        }
        catch (Exception ex)
        {
            // Log
        }
        return 0;
    }
}
Add below namespace reference in the header
using System.Data.SqlClient;
using System.Configuration;
using System.Data;
The code has comments for explaining the method functionalities.

Step 10: Now the WCF service is ready to use. So, you can test the WCF service if required.

Step 11: To expose the standard WCF Service to public on Azure, we required to run the service under IIS (Internet Information Service) instead of Visual Studio Development Server. Because while exposing the WCF Service to Azure, it required to use some features on IIS.

(By default, ASP.NET project will run under Visual Studio Development Server, which comes as part of Visual Studio for testing ASP.NET applications without the need of IIS on development system)

To run the WCF Service under IIS Manager, right click the WCF project and select Properties. The Visual Studio will show Properties page. Select the Web tab on the properties page.

The Visual Studio will show the default settings which includes Use Visual Studio Development Server selection under Servers section.

Select the Use Local IIS Web server and press Create Virtual Directory button. The Visual Studio will create a virtual directory under Default Web Site and show The virtual directory was created successfully message.



Run the WCF application and test whether the service running under IIS perfectly.

Step 12: The next step is to make the WCF service discoverable to Public.

To make the service discoverable to Public, we required to use the Service Bus libraries comes as part of Azure SDK. So add reference Microsoft.ServiceBus.dll to the service project by right click the Reference folder and Add Reference…

Normally the Microsoft.ServiceBus.dll will be located in below path. (Currently I am using Vista x86, it might slight different in x64 versions – not sure)

C:\Program Files\Windows Azure SDK\v1.6\ServiceBus\ref\Microsoft.ServiceBus.dll - in Vista - x86

C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.Core.dll - in Windows Server 2008 R2 - x64


Step 13: To make the service discoverable to public, we required to create a custom class (MyServiceRegistrySettingsElement) by extending BehaviorExtensionElement.

So create a class file by Right click the project add Add => Class file. Name the file name as MyServiceRegistrySettingsElement.cs. This custom class will extend BehaviorExtensionElement to extend the behavior of WCF service, so that it can be discoverable to Public.

Below is the code for MyServiceRegistrySettingsElement class.
public class MyServiceRegistrySettingsElement : BehaviorExtensionElement
{
    private const string displayNameId = "displayName";
    private const string discoveryModeId = "discoveryMode";

    public override Type BehaviorType
    {
        get { return typeof(ServiceRegistrySettings); }
    }

    protected override object CreateBehavior()
    {
        return new ServiceRegistrySettings()
        {
            DiscoveryMode = this.DiscoveryMode,
        };
    }

    [ConfigurationProperty(discoveryModeId, DefaultValue = DiscoveryType.Private)]
    public DiscoveryType DiscoveryMode
    {
        get { return (DiscoveryType)this[discoveryModeId]; }
        set { this[discoveryModeId] = value; }
    }

    [ConfigurationProperty(displayNameId)]
    public string DisplayName
    {
        get { return (string)this[displayNameId]; }
        set { this[displayNameId] = value; }
    }
}
Add the below references in the class files.
using System.ServiceModel.Configuration;
using Microsoft.ServiceBus;
using System.Configuration;
Step 14: We have to do some configuration settings for exposing the WCF service to service bus. So open the Web.Config file and replace the <system.servicemodel> configuration section with below settings.
<system.serviceModel>
  <services>
    <clear />
    <service behaviorConfiguration="MyServiceTypeBehavior" name="DotNetTwitterSOPService.CustomerService">
      <endpoint address="http://localhost/DotNetTwitterSOPService/CustomerService.svc/LocalCustomerService" binding="basicHttpBinding" bindingConfiguration="BasicHttpConfig" name="Basic" contract="DotNetTwitterSOPService.ICustomerService" />
      <endpoint address="https://ComDotNetTwitterSOP.servicebus.windows.net/Http/CustomerService/Test/V0100/" behaviorConfiguration="sharedSecretClientCredentials" binding="basicHttpRelayBinding" bindingConfiguration="HttpRelayEndpointConfig" name="RelayEndpoint" contract="DotNetTwitterSOPService.ICustomerService" />
      <endpoint address="sb://ComDotNetTwitterSOP.servicebus.windows.net/NetTcp/CustomerService/Test/V0100/" behaviorConfiguration="sharedSecretClientCredentials" binding="netTcpRelayBinding" bindingConfiguration="NetTcpRelayEndpointConfig" name="RelayEndpoint" contract="DotNetTwitterSOPService.ICustomerService" />
    </service>
  </services>
  <bindings>
    <basicHttpBinding>
      <binding name="BasicHttpConfig" />
    </basicHttpBinding>
    <!--service bus binding-->
    <basicHttpRelayBinding>
      <binding name="HttpRelayEndpointConfig">
        <security relayClientAuthenticationType="RelayAccessToken" />
      </binding>
    </basicHttpRelayBinding>
    <netTcpRelayBinding>
      <binding name="NetTcpRelayEndpointConfig">
        <security relayClientAuthenticationType="RelayAccessToken" />
      </binding>
    </netTcpRelayBinding>
  </bindings>
  <behaviors>
    <endpointBehaviors>
      <behavior name="sharedSecretClientCredentials">
        <transportClientEndpointBehavior credentialType="SharedSecret">
          <clientCredentials>
            <sharedSecret issuerName="owner" issuerSecret="DpMUy110dpc+CO4Z9HVu1K0xkLRtpXGOfjJBTnwnF2U=" />
          </clientCredentials>
        </transportClientEndpointBehavior>
        <ServiceRegistrySettings discoveryMode="Public" />
      </behavior>
    </endpointBehaviors>
    <serviceBehaviors>
      <behavior name="MyServiceTypeBehavior">
        <serviceMetadata httpGetEnabled="true" />
        <serviceDebug includeExceptionDetailInFaults="true" />
      </behavior>
    </serviceBehaviors>
  </behaviors>
  <extensions>
    <behaviorExtensions>
      <add name="transportClientEndpointBehavior" type="Microsoft.ServiceBus.Configuration.TransportClientEndpointBehaviorElement, Microsoft.ServiceBus, Version=1.6.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
      <add name="ServiceRegistrySettings" type="DotNetTwitterSOPService.MyServiceRegistrySettingsElement, DotNetTwitterSOPService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
    </behaviorExtensions>
    <bindingExtensions>
      <add name="basicHttpRelayBinding" type="Microsoft.ServiceBus.Configuration.BasicHttpRelayBindingCollectionElement, Microsoft.ServiceBus, Version=1.6.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
      <add name="netTcpRelayBinding" type="Microsoft.ServiceBus.Configuration.NetTcpRelayBindingCollectionElement, Microsoft.ServiceBus, Version=1.6.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
    </bindingExtensions>
  </extensions>
</system.serviceModel>

We required to understand the sections defined in the above configuration for using in other services. So let us take each one of them and understand what changes are required and for what.
  1. <services> - This <services> section defines the list of services which are exposed under the service project. This also defines the end point addresses, service behavior name reference and binding reference for each etc. for each service.
    For Example as per our example project:
    <services>
      <clear />
      <service behaviorConfiguration="MyServiceTypeBehavior" 
        name="DotNetTwitterSOPService.CustomerService">
        <endpoint address="http://localhost/DotNetTwitterSOPService/CustomerService.svc/LocalCustomerService" 
        binding="basicHttpBinding" 
        bindingConfiguration="BasicHttpConfig" 
        name="Basic" 
        contract="DotNetTwitterSOPService.ICustomerService" />
        <endpoint address="https://ComDotNetTwitterSOP.servicebus.windows.net/Http/CustomerService/Test/V0100/" 
        behaviorConfiguration="sharedSecretClientCredentials" 
        binding="basicHttpRelayBinding" 
        bindingConfiguration="HttpRelayEndpointConfig" 
        name="RelayEndpoint" 
        contract="DotNetTwitterSOPService.ICustomerService" />
        <endpoint address="sb://ComDotNetTwitterSOP.servicebus.windows.net/NetTcp/CustomerService/Test/V0100/" 
        behaviorConfiguration="sharedSecretClientCredentials" 
        binding="netTcpRelayBinding" 
        bindingConfiguration="NetTcpRelayEndpointConfig" 
        name="RelayEndpoint" 
        contract="DotNetTwitterSOPService.ICustomerService" />
      </service>
    </services>
    In this section,

    Ø  behaviorConfiguration="MyServiceTypeBehavior" refers the service behavior name (MyServiceTypeBehavior) defined in the <extensions><behaviorExtensions> section.

    Ø name="DotNetTwitterService.CustomerService" refers the class name of the service implemented.

    Ø We have defined three endpoint addresses in this configurations for different binding.

    v  binding="basicHttpBinding" – As we already seen in previous post, this is one of the standard WCF service binding method (basicHttpBinding) which actually publishing for our local environment. This endpoint cannot be used in public.

    v  binding="basicHttpRelayBinding" – This is the relay binding equalent to basicHttpBinding, for relaying on Relay Service with http protocol.

    v  binding="netTcpRelayBinding" – This is TCP based relay binding relaying on Relay Service on Azure.

    Ø contract="DotNetTwitterSOPService.ICustomerService" refers the service contract exposing thro' the service bus.

    Ø bindingConfiguration="NetTcpRelayEndpointConfig" refers the name of the binding configuration which configured in <bindings> section.

    Ø behaviorConfiguration="sharedSecretClientCredentials" refers the name of the behavior configuration which configured in <behaviors> section.

    Note: 1. To expose the service to Azure, the on-premise service must have some ports to be open for each binding. Please look at the below url for more information http://msdn.microsoft.com/en-us/library/ee732535.aspx
    2. The http based endpoint address exposing to local network only. But the other two endpoint addresses (https://, sb://) are exposed to public. So those endpoint addresses must be as per the standard defined in organisation level. I follow the standards defined in previous post.
  2. <bindings> - This <bindings> section defines the list of binding method and the security configuration for each binding.
    For Example as per our example project:
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpConfig" />
      </basicHttpBinding>
      <!--service bus binding-->
      <basicHttpRelayBinding>
        <binding name="HttpRelayEndpointConfig">
          <security relayClientAuthenticationType="RelayAccessToken" />
        </binding>
      </basicHttpRelayBinding>
      <netTcpRelayBinding>
        <binding name="NetTcpRelayEndpointConfig">
          <security relayClientAuthenticationType="RelayAccessToken" />
        </binding>
      </netTcpRelayBinding>
    </bindings>
  3. <behaviors> - This <behaviors> section defines the behaviour of the service. This is where we are configuring the service should be exposed in public.
    For Example as per our example project:
    <behaviors>
      <endpointBehaviors>
        <behavior name="sharedSecretClientCredentials">
          <transportClientEndpointBehavior credentialType="SharedSecret">
            <clientCredentials>
              <sharedSecret issuerName="owner" issuerSecret="DpMUy110dpc+CO4Z9HVu1K0xkLRtpXGOfjJBTnwnF2U=" />
            </clientCredentials>
          </transportClientEndpointBehavior>
          <ServiceRegistrySettings discoveryMode="Public" />
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="MyServiceTypeBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    Ø  <sharedSecret issuerName="owner" issuerSecret="DpMUy110dpc+CO4Z9HVu1K0xkLRtpXGOfjJBTnwnF2U=" /> - this is an important configuration which refers the issuerName and issuerSecret key which was noted while creating service bus namespace (previous post - Step 5).
    Ø  <ServiceRegistrySettings discoveryMode="Public" /> - this configuration makes the service to be exposed in public.
  4. <extensions> - This <extensions> section extend the behavious and binding methods for service bus to handle.
    For Example as per our example project:
    <extensions>
      <behaviorExtensions>
        <add name="transportClientEndpointBehavior" type="Microsoft.ServiceBus.Configuration.TransportClientEndpointBehaviorElement, Microsoft.ServiceBus, Version=1.6.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add name="ServiceRegistrySettings" type="DotNetTwitterSOPService.MyServiceRegistrySettingsElement, DotNetTwitterSOPService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
      </behaviorExtensions>
      <bindingExtensions>
        <add name="basicHttpRelayBinding" type="Microsoft.ServiceBus.Configuration.BasicHttpRelayBindingCollectionElement, Microsoft.ServiceBus, Version=1.6.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add name="netTcpRelayBinding" type="Microsoft.ServiceBus.Configuration.NetTcpRelayBindingCollectionElement, Microsoft.ServiceBus, Version=1.6.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
      </bindingExtensions>
    </extensions>
    Ø  Here an important settings is the highlighted line, which refers the custom extension class we had created in Step 8 (MyServiceRegistrySettingsElement).
Step 15: Now we have completed our service application and ready to test. So run the application (press F5). Visual studio will open the browser and show the localhost endpoint exposed as shown below.

The wsdl script of the same endpoint would be

Step 16: If we get the above screens, the services are exposed to public on the Service Bus. So we can access the public endpoints from any other system and see the Service Registry.

Service Registry is an Atom 1.0 feeds, which displays list of endpoint namespace exposed on the Service Gateway. So whenever any new endpoint exposed, the endpoint will be registered automatically in the registry. Initially it display the top level namespace hierarchy as below.


As shown in the above image, it displayes the top level namespace from the endpoint. For example, the two public endpoints in our examples are

https://ComDotNetTwitterSOP.servicebus.windows.net/Http/CustomerService/Test/V0100/
sb://ComDotNetTwitterSOP.servicebus.windows.net/NetTcp/CustomerService/Test/V0100/

The endpoint address in black bold is requested from the browser and it displays the top level namespaces in a list according to the endpoint requested(blue bold).

When you click any of the namespace (http or nettcp), you will get the next level namespace exposed for the endpoint address. Below is the result of the screen when I click the http namespace.


By looking at the url in the address bar, we can see the url requested is https://comdotnettwittersop.servicebus.windows.net/Http. So it shows the next top level namespace hierarchy.

When I click the customerservice namespace, I will be getting the next level namespace in the hierarchy and so on.



download the working example of the source code in c# here.

Possible Errors

1. The on-premise server which is exposing the WCF service to Azure must have some out-bound ports open based on the binding method on which exposing. You can find the list of ports from the msdn site (http://msdn.microsoft.com/en-us/library/ee732535.aspx). Incase if the on-premise server does not open the required ports, the browser will show error as below

2. When the issuerSecret key is not replaced perfectly as given in the Management Portal, the browser may throw below error.

3. When namespace is not refered correctly in the configuration or not created from the Management Portal, the browser may throw below error.

4. In sometime, you may get error "Unable to start debugging on the web server. See help for common configuration erros. Running the web page outside of the debugger may provide further information.".


If you get this error, verify the Web.config of the service project which has like the following configuration exist.
<microsoft.applicationServer>
  <hosting>
   <serviceAutoStart>
    <add relativeVirtualPath="CustomerService.svc" />
   </serviceAutoStart>
  </hosting>
</microsoft.applicationServer>
This error may happen when you are copying the Service Bus project source code from other system and running in different system which does not have Windows Server Appfabric installed and not configured for Auto Start in IIS.

To know more about the use of Windows Server Appfabic, verify the next post.

If Windows Server Appfabric not installed, you can try installing the same and run the project by configuring for Auto Start in IIS. Otherwise, remove specified configuration from Web.config and try running the project.

5. For other errors, please look at the below urls.
http://msdn.microsoft.com/en-us/library/windowsazure/ee706702.aspx
http://msdn.microsoft.com/en-us/library/windowsazure/ee706729.aspx http://social.technet.microsoft.com/wiki/contents/articles/troubleshooting-connectivity-issues-in-the-windows-azure-appfabric-service-bus.aspx


0 Responses to “Implementing Azure AppFabric Service Bus - Part 3”

Post a Comment