What's New in Windows Communication Foundation (WCF) 4.0 Part- II - Developing Routing Service

Posted by: Mahesh Sabnis , on 9/16/2009, in Category .NET Framework
Views: 37981
Abstract: In part 1 of this article, we went through a new feature of WCF - ‘Simple Configuration’. In this second part of the article series, we will see how WCF 4.0 performs routing.
What's New in Windows Communication Foundation (WCF) 4.0 Part- II - Developing Routing Service
 
In the part 1 of this article, What's New in Windows Communication Foundation (WCF) 4.0 Part- I, we went through a new feature of WCF called  ‘Simple Configuration’. In this part, we will see how WCF 4.0 performs routing. Note: This article is based on the Beta 1 release of .NET 4.0 and can change in future.
As a .NET 3.x service provider, whenever I am with my client, a frequently asked question is how can the client application make a request to one or more WCF services through a single service interface? My clients have been expecting that a single WCF service interface should automatically route messages to multiple WCF services. And I have been giving them various solutions, however they were clumsy to implement.
As part of Microsoft .NET 4.0, with WCF 4.0, a message routing feature is provided. This helps to define a routing service. This service contains endpoint information of the WCF service(s) to which a message can be routed. Along with endpoint information, routing service also defines filters. Filter is the most important part of the routing service. Routing determines how message can be forwarded when request from the client is received. Here are the following filter types available:
·         Action
·         MatchAll
·         Address
·         AddressPrefix
·         And
·         Custom
·         Endpoint
·         XPath.
In the following example we will see how WCF Routing can be implemented. The following architecture is used in the application I will demonstrate in this article:
WCFService
Task 1: Creating WCF Service.
Step 1: Open VS 2010 and create a Blank solution. Name this as ‘WCF_Routing_Service’. In this project add a new WCF ‘WCF Service Application’ project as below:
AddNewProject
Step 2: Rename ‘IService1.cs’ to ‘IQtrwiseSales.cs’ and name ‘Service1.csv’ to ‘CQtrwiseSales.svc’.
Step 3: Right click on ‘CQtrwiseSales.svc’ and select ‘View Markup’ and write the following:
<%@ ServiceHost Language="C#" Debug="true" Service="WCF_ServiceQtrwsieSales.CQtrwiseSales" CodeBehind="CQtrwiseSales.svc.cs" %>
Step 4: Write the following code in ‘IQtrwiseSales.cs’:
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
 
namespace WCF_ServiceQtrwsieSales
{
    [ServiceContract]
    public interface IQtrwiseSales
    {
        [OperationContract]
        List<Sales> GetSalesDetsils();
    }
     [DataContract]
    public class Sales
    {
        [DataMember]
        public int CompanyId { get; set; }
        [DataMember]
        public string CompanyName { get; set; }
        [DataMember]
        public decimal Q1 { get; set; }
        [DataMember]
        public decimal Q2 { get; set; }
        [DataMember]
        public decimal Q3 { get; set; }
        [DataMember]
        public decimal Q4 { get; set; }
    }
}
 
VB.NET
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Runtime.Serialization
Imports System.ServiceModel
Imports System.ServiceModel.Web
Imports System.Text
 
Namespace WCF_ServiceQtrwsieSales
      <ServiceContract> _
      Public Interface IQtrwiseSales
            <OperationContract> _
            Function GetSalesDetsils() As List(Of Sales)
      End Interface
 
 
      <DataContract> _
      Public Class Sales
            Private privateCompanyId As Integer
            <DataMember> _
            Public Property CompanyId() As Integer
                  Get
                        Return privateCompanyId
                  End Get
                  Set(ByVal value As Integer)
                        privateCompanyId = value
                  End Set
            End Property
            Private privateCompanyName As String
            <DataMember> _
            Public Property CompanyName() As String
                  Get
                        Return privateCompanyName
                  End Get
                  Set(ByVal value As String)
                        privateCompanyName = value
                  End Set
            End Property
            Private privateQ1 As Decimal
            <DataMember> _
            Public Property Q1() As Decimal
                  Get
                        Return privateQ1
                  End Get
                  Set(ByVal value As Decimal)
                        privateQ1 = value
                  End Set
            End Property
            Private privateQ2 As Decimal
            <DataMember> _
            Public Property Q2() As Decimal
                  Get
                        Return privateQ2
                  End Get
                  Set(ByVal value As Decimal)
                        privateQ2 = value
                  End Set
            End Property
            Private privateQ3 As Decimal
            <DataMember> _
            Public Property Q3() As Decimal
                  Get
                        Return privateQ3
                  End Get
                  Set(ByVal value As Decimal)
                        privateQ3 = value
                  End Set
            End Property
            Private privateQ4 As Decimal
            <DataMember> _
            Public Property Q4() As Decimal
                  Get
                        Return privateQ4
                  End Get
                  Set(ByVal value As Decimal)
                        privateQ4 = value
                  End Set
            End Property
      End Class
End Namespace
 
The above service contract, defines an operation named ‘GetSalesDetasils’ which returns ‘List<Sales>’ object. DataContract maps with the ‘Sales’ data table in the Sql Server 2005.
Step 5: In ‘CQtrwiseSales.svc.cs’ write the following code:
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using System.Data.SqlClient;
using System.Data;
 
namespace WCF_ServiceQtrwsieSales
{
    public class CQtrwiseSales : IQtrwiseSales
    {
        SqlConnection Conn;
        SqlCommand Cmd;
        SqlDataReader Reader;
 
        #region IQtrwiseSales Members
 
        public List<Sales> GetSalesDetsils()
        {
            List<Sales> lstSales = new List<Sales>();
            Conn = new SqlConnection("Data Source=.;Initial Catalog=Company;Integrated Security=SSPI");
            Conn.Open();
            Cmd = new SqlCommand("Select * from Sales", Conn);
 
            Reader = Cmd.ExecuteReader();
 
            while (Reader.Read())
            {
                lstSales.Add
                    (
                    new Sales()
                            {
                                CompanyId = Convert.ToInt32(Reader["CompanyId"]),
                                CompanyName=Reader["CompanyName"].ToString(),
                                Q1=Convert.ToInt32(Reader["Q1"]) ,
                                Q2=Convert.ToInt32(Reader["Q2"]),
                                Q3=Convert.ToInt32(Reader["Q3"]),
                                Q4=Convert.ToInt32(Reader["Q4"])
                            }
                    ); 
            }       
            Conn.Close();
             return lstSales;
        }
        #endregion
    }
}
 
VB.NET
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Runtime.Serialization
Imports System.ServiceModel
Imports System.ServiceModel.Web
Imports System.Text
Imports System.Data.SqlClient
Imports System.Data
 
Namespace WCF_ServiceQtrwsieSales
      Public Class CQtrwiseSales
            Implements IQtrwiseSales
            Private Conn As SqlConnection
            Private Cmd As SqlCommand
            Private Reader As SqlDataReader
 
            #Region "IQtrwiseSales Members"
 
            Public Function GetSalesDetsils() As List(Of Sales)
                  Dim lstSales As New List(Of Sales)()
                  Conn = New SqlConnection("Data Source=.;Initial Catalog=Company;Integrated Security=SSPI")
                  Conn.Open()
                  Cmd = New SqlCommand("Select * from Sales", Conn)
 
                  Reader = Cmd.ExecuteReader()
 
                  Do While Reader.Read()
                        lstSales.Add (New Sales() With {.CompanyId = Convert.ToInt32(Reader("CompanyId")), .CompanyName=Reader("CompanyName").ToString(), .Q1=Convert.ToInt32(Reader("Q1")), .Q2=Convert.ToInt32(Reader("Q2")), .Q3=Convert.ToInt32(Reader("Q3")), .Q4=Convert.ToInt32(Reader("Q4"))})
                  Loop
                   Conn.Close()
                   Return lstSales
            End Function
            #End Region
      End Class
End Namespace
The above code makes call to the ‘Company’ database and retrieves data from ‘Sales’ table.
Step 6: In the Web.Config file make the following changes:
<system.serviceModel>
 <services>
    <service behaviorConfiguration="ServBehave"
      name="WCF_ServiceQtrwsieSales.CQtrwiseSales">
      <endpoint address="" binding="wsHttpBinding"
        contract="WCF_ServiceQtrwsieSales.IQtrwiseSales">
        <identity>
          <dns value="localhost" />
        </identity>
      </endpoint>
      <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
    </service>
 </services>
 <behaviors>
    <serviceBehaviors>
      <behavior name="ServBehave">
        <serviceMetadata httpGetEnabled="true"/>
        <serviceDebug includeExceptionDetailInFaults="false"/>
      </behavior>
    </serviceBehaviors>
 </behaviors>
</system.serviceModel>
 
Step 7: Publish the WCF Service Application to IIS by creating a virtual directory.
Task 2: Creating Routing service.
Step 1: In the same solution add a new console application, name this as ‘WCF_TempRoutingService’.
Step 2: Add the reference to following namespace in this project:
System.ServiceModel.
System.ServiveModel.Routing.
Step 3: In this project add the App.Config file and write the following code:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
 <system.serviceModel>
    <services>    <service name="System.ServiceModel.Routing.RoutingService" behaviorConfiguration="MyRoutedServBehave">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:5643/MyServ"/>
          </baseAddresses>
        </host>
        <endpoint
                  address=""
                  binding="wsHttpBinding"                 name="MyRoutingEndpoint" contract="System.ServiceModel.Routing.IRequestReplyRouter"/>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="MyRoutedServBehave">
          <serviceMetadata httpGetEnabled="True"/>
          <serviceDebug includeExceptionDetailInFaults="True"/>
          <routing routingTableName="ServiceRouterTable"/>
          <!--The Router Table Contains Entries for services-->
        </behavior>
      </serviceBehaviors>
    </behaviors>
 
    <!--Define Services Here-->
    <client>
      <endpoint
      name="WCF_QtrwiseSalesService" binding="wsHttpBinding"
      address="http://localhost/WCF40_QtrwiseSalesVD/CQtrwiseSales.svc"
      contract="*">
      </endpoint>
    </client>
    <!--Routing Defination-->
    <routing>
      <!--Filter For Detecting Messages Headers to redirect-->
      <filters>
        <filter name="MyFilter_1" filterType="MatchAll"/>
      </filters>
      <!--Define Routing Table, This will Map the service with Filter-->
      <routingTables>
        <table name="ServiceRouterTable">
          <entries>
            <add filterName="MyFilter_1" endpointName="WCF_QtrwiseSalesService"/>
          </entries>
        </table>
      </routingTables>
    </routing>
 </system.serviceModel>
</configuration>
 
The above configuration contains the Routing service ‘System.ServiceModel.Routing.RoutingService’ hosted on the address ‘http://localhost:5643/MyServ’ and uses ‘wsHttpBinding’. This uses contract ‘System.ServiceModel.Routing.IRequestReplyRouter’. The configuration file contains endpoint information of the ‘WCF_ServiceQtrwsieSales’. The contract value ‘*’ represents all contracts that will be referred from the service. Service behavior defines routing table name.  
Routing section of the configuration defines filters. This is the heart of the routing mechanism. Based upon the filter, the routing service will redirect the request received from the client to the WCF service. Routing table maps filter with the WCF service endpoint.
Step 4: In the ‘Program.cs’ write the following code:
C#
 
static void Main(string[] args)
{
            ServiceHost Host = new ServiceHost(typeof(RoutingService));
            try
            {
                Host.Open();
                Console.WriteLine("Routing Service is Started...............");
                Console.ReadLine();
                Host.Close();
 
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            Console.ReadLine();
}
VB.NET
 
Shared Sub Main(ByVal args() As String)
                  Dim Host As New ServiceHost(GetType(RoutingService))
                  Try
                        Host.Open()
                        Console.WriteLine("Routing Service is Started...............")
                        Console.ReadLine()
                        Host.Close()
                   Catch ex As Exception
                        Console.WriteLine(ex.Message)
                  End Try
                  Console.ReadLine()
End Sub
Task 3: Creating Client Application
Step 1: In the solution, add a new WPF project and name it as ‘WPF_Client_RoutingService’. In this project add the service reference of the ‘WCF_ServiceQtrwsieSales’. This will add App.config file in the client application.
Step 2: Since the client should only know the interface information of the service, but will communicate to it using routing service, so delete existing contents of the ‘App.Config’ as below:
<configuration>
 <system.serviceModel>
    <client>
      <endpoint name="clientEdpQtrwiseSales"
                               address="http://localhost:5643/MyServ"
                               binding="wsHttpBinding"
                               contract="MyRefQtrSales.IQtrwiseSales"></endpoint>
    </client>
 </system.serviceModel>
</configuration>
Step 3: Add the DataGrid on WPF window as below:
<DataGrid x:Name="dgQtrwiseSales" Grid.Column="0" AutoGenerateColumns="True"></DataGrid>
Step 4: In the Window.xaml.cs write the following code:
C#
MyRefQtrSales.QtrwiseSalesClient ProxyQtrwsieSales;
MyRefQtrSales.Sales[] arrQtrSales;
 
void Window1_Loaded(object sender, RoutedEventArgs e)
{
            
           ProxyQtrwsieSales = new WPF_Client_RoutingService.MyRefQtrSales.QtrwiseSalesClient("clientEdpQtrwiseSales");
              
            arrQtrSales = ProxyQtrwsieSales.GetSalesDetsils();
            gQtrwiseSales.ItemsSource = arrQtrSales;     
}
 
VB.NET
Private ProxyQtrwsieSales As MyRefQtrSales.QtrwiseSalesClient
Private arrQtrSales() As MyRefQtrSales.Sales
 
Private Sub Window1_Loaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
               ProxyQtrwsieSales = New WPF_Client_RoutingService.MyRefQtrSales.QtrwiseSalesClient("clientEdpQtrwiseSales")
               arrQtrSales = ProxyQtrwsieSales.GetSalesDetsils()
               gQtrwiseSales.ItemsSource = arrQtrSales
End Sub
Step 5: Run the Routing Service and the client application. The following output will be displayed:
RoutingService
Conclusion:
WCF 4.0 Routing message is in my opintion the best facility provided by .NET 4.0. This reduces the complication and the time for developing routings using code.
The entire source code of this article can be downloaded over here

This article has been editorially reviewed by Suprotim Agarwal.

Absolutely Awesome Book on C# and .NET

C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.

We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).

Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.

Click here to Explore the Table of Contents or Download Sample Chapters!

What Others Are Reading!
Was this article worth reading? Share it with fellow developers too. Thanks!
Share on LinkedIn
Share on Google+

Author
Mahesh Sabnis is a DotNetCurry author and a Microsoft MVP having over two decades of experience in IT education and development. He is a Microsoft Certified Trainer (MCT) since 2005 and has conducted various Corporate Training programs for .NET Technologies (all versions), and Front-end technologies like Angular and React. Follow him on twitter @maheshdotnet or connect with him on LinkedIn


Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!
Comment posted by Anup Hosur on Saturday, September 19, 2009 2:52 AM
great article..
Comment posted by Atanu on Tuesday, May 17, 2011 4:22 AM
How routing is playing a role here....
This can be achieved without routing filters and all...

Please explain
Comment posted by Jasper on Wednesday, July 6, 2011 5:09 AM
You didn't give an example for actual routing ? Routing from where to where ? There's only 1 address in your example. Please describe 'routing' not how to build Service Contract or pull data from database...