Multiple wcf services in one solution with multiple endpoints and hosting

You might have tried one wcf service to learn about WCF or some small application. In real application with only one WCF service it is difficult to handle applications all aspects. So in this article I will explain you how to create multiple wcf services to serve different entities in one solution with different endpoint and bindings. And also tells you how to host these services in IIS 7+ or in Windows Services.


For this tutorial we will create two WCF services as 1.CustomerService and 2.OrderService


  1. Start with WCF Service Library

    If you would like to know about how to start with WCF go through the article Create new WCF service library and test using WCFTestClient

  2. Northwind Solution

    Create empty solution by opening Visual Studio and click on File menu -> Project -> Click on Other Project Types from Installed Template -> Select Blank Solution

    Give a name as Northwind.

  3. NorthwindServices Service library

    Add NorthwindServices WCF Service Library to Northwind solution by right click on solution -> Add -> New Project -> Choose Visual C# from Installed templates -> Select WCF -> Select WCF Service Library

    Delete default IService1.cs, Service1.cs files from library.

  4. Service Contracts


    1. Add ServiceContracts Folder to Northwind Service Library project.
    2. Add ICustomerService contract to ServiceContracts folder created in previous step.
      Right click on ServiceContracts and add new Interface to folder. Name it as ICustomerService. Add ServiceContract attribute to ICustomer.
    3. Add OperationContract to ICustomerService which will be accessible to clients. Your ICustomerService should look like.
                              
      using System.ServiceModel;
      
      namespace NorthwindServices.ServiceContracts
      {
          [ServiceContract(Namespace = "http://dotnetmentors.com/services/customer")]
          public interface ICustomerService
          {
              [OperationContract]
              string GetCustomerName(int CustomerID);
      
              [OperationContract]
              string GetCustomerCity(int CustomerID);
      
              [OperationContract]
              int GetCustomerCount();
          }
      }
                          
    4. Add IOrderService contract to ServiceContracts folder and its OperationContract as we added for ICustomerService.

      IOrderService should look like

                              
      using System.ServiceModel;
      
      namespace NorthwindServices.ServiceContracts
      {
          [ServiceContract(Namespace = "http://dotnetmentors.com/services/order")]
          public interface IOrderService
          {
              [OperationContract] 
              string GetOrderDate(int orderID);
              
              [OperationContract] 
              string GetOrderAmount(int OrderID);
      
              [OperationContract] 
              string GetShipCountry(int orderID);
          }
      }
                          

  5. Datastore

    Add two new XML files name it as Customers.xml and Orders.xml. These xml files will be used as datastore for OrderService and CustomerService respectively.


    Customers.xml
                    
    <?xml version="1.0" standalone="yes"?>
    <DocumentElement>
    <Customer>
    <CustomerID>1</CustomerID>
    <CompanyName>Let's Stop N Shop</CompanyName>
    <City>Mumbai</City>
    </Customer>
    <Customer>
    <CustomerID>2</CustomerID>
    <CompanyName>Hungry Coyote Import Store</CompanyName>
    <City>Mumbai</City>
    </Customer>      
    <Customer>
    <CustomerID>4</CustomerID>
    <CompanyName>Andy's Seasoning</CompanyName>
    <City>Delhi</City>
    </Customer>
    </DocumentElement>
                        
                
    Orders.xml
                    
    <?xml version="1.0" standalone="yes"?>
    <DocumentElement>
        <Orders>
        <OrderID>10248</OrderID>
        <OrderDate>1996-07-04</OrderDate>
        <ShippedDate>1996-07-16</ShippedDate>
        <ShipCountry>France</ShipCountry>
        <OrderTotal>650</OrderTotal>
        </Orders>      
        <Orders>
        <OrderID>10250</OrderID>
        <OrderDate>1996-07-08</OrderDate>
        <ShippedDate>1996-07-12</ShippedDate>
        <ShipCountry>Brazil</ShipCountry>
        <OrderTotal>2170</OrderTotal>
        </Orders>
        <Orders>
        <OrderID>10251</OrderID>
        <OrderDate>1996-07-08</OrderDate>
        <ShippedDate>1996-07-15</ShippedDate>
        <ShipCountry>France</ShipCountry>
        <OrderTotal>1057</OrderTotal>
        </Orders>
    </DocumentElement>
                        
                
  6. Implementation of Customer and Order WCF service

    1. Add a Services folder to root of NorthwindServices service library.
    2. Add a new class to Services folder created in previous step. Name the class as CustomerService and implement the ICustomerService service contract.
                              
      using NorthwindServices.ServiceContracts;
      using System.Xml.Linq; 
      
      namespace NorthwindServices.Services
      {
          [ServiceBehavior(Namespace="http://dotnetmentors.com/services/customer")]  
          public class CustomerService : ICustomerService 
          {
              public string GetCustomerName(int CustomerID)
              {
                  XDocument doc = XDocument.Load("C:\\Customers.xml");
      
                  string companyName =
                      (from result in doc.Descendants("DocumentElement")
                      .Descendants("Customer")
                          where result.Element("CustomerID").Value 
                              == CustomerID.ToString()
                          select result.Element("CompanyName").Value)
                      .FirstOrDefault<string>();
      
                  return companyName;
              }
      
              public string GetCustomerCity(int CustomerID)
              {
                  XDocument doc = XDocument.Load("C:\\Customers.xml");
      
                  string companyName =
                      (from result in doc.Descendants("DocumentElement")
                      .Descendants("Customer")
                          where result.Element("CustomerID").Value 
                              == CustomerID.ToString()
                          select result.Element("City").Value)
                      .FirstOrDefault<string>();
      
                  return companyName;
              }
      
              public int GetCustomerCount()
              {
                  XDocument doc = XDocument.Load("C:\\Customers.xml");
      
                  return doc.Descendants("Customer").Count();  
              }
          }
      }
                      
    3. Add a new class to Services folder. Name the class as OrderService and implement the IOrderService service contract.

                              
      using NorthwindServices.ServiceContracts;
      using System.Xml.Linq;
      
      namespace NorthwindServices.Services
      {
          [ServiceBehavior(Namespace="http://dotnetmentors.com/services/order")]  
          public class OrderService : IOrderService
          {
              public string GetOrderDate(int orderID)
              {
                  XDocument doc = XDocument.Load("C:\\Orders.xml");
      
                  string orderDate =
                      (from result in doc.Descendants("DocumentElement")
                      .Descendants("Orders")
                          where result.Element("OrderID").Value 
                              == orderID.ToString()
                          select result.Element("OrderDate").Value)
                      .FirstOrDefault<string>();
      
                  return orderDate;
              }
      
              public string GetOrderAmount(int orderID)
              {
                  XDocument doc = XDocument.Load("C:\\Orders.xml");
      
                  string orderTotal =
                      (from result in doc.Descendants("DocumentElement")
                      .Descendants("Orders")
                          where result.Element("OrderID").Value 
                              == orderID.ToString()
                          select result.Element("OrderTotal").Value)
                      .FirstOrDefault<string>();
      
                  return orderTotal;
              }
      
              public string GetShipCountry(int orderID)
              {
                  XDocument doc = XDocument.Load("C:\\Orders.xml");
      
                  string shipCountry =
                      (from result in doc.Descendants("DocumentElement")
                      .Descendants("Orders")
                          where result.Element("OrderID").Value 
                                  == orderID.ToString()
                          select result.Element("ShipCountry").Value)
                      .FirstOrDefault<string>();
      
                  return shipCountry;
              }
          }
      }                   
                     

      Sometimes in service implementation exception occurs. Service exception needs to be handle by using FaultContract.

  7. Service Endpoint

    Add Service Endpoints for CustomerService and OrderService.

    In real time applications wsHttpBinding is used for http communication like with web applications and netNamedPipeBinding. is used for the applications which are running on same machine for example to execute some jobs, update inventory by back office application.

    netNamedPipeBinding gives you the best possible performance if client is on same machine.

    So for CustomerService and OrderService we will use both bindings.

    Add below service model configuration to your service library configuration.

                    
    <system.serviceModel>
    <services>
    <service name="NorthwindServices.Services.CustomerService" 
                        behaviorConfiguration ="ServiceBehavior">
    <host>
        <baseAddresses>
        <add baseAddress="http://localhost:7741/NorthwindServices/Services
                                /CustomerService" /> 
        <add baseAddress="net.pipe://localhost/Services/CustomerService" />
        </baseAddresses>
    </host>
    
    <endpoint address ="" binding="wsHttpBinding"
            contract="NorthwindServices.ServiceContracts.ICustomerService"
            bindingNamespace = "http://dotnetmentors.com/services/customer" />
    <endpoint address="mex" binding="mexHttpBinding" 
                    contract="IMetadataExchange"/>
    
    <endpoint address ="" binding ="netNamedPipeBinding" 
            contract ="NorthwindServices.ServiceContracts.ICustomerService"
            bindingNamespace = "http://dotnetmentors.com/services/customer"  />
    <endpoint address="mex" binding="mexNamedPipeBinding" 
                    contract="IMetadataExchange"/>
    </service>
    
    <service name="NorthwindServices.Services.OrderService" 
                            behaviorConfiguration ="ServiceBehavior">
    <host>
        <baseAddresses>
        <add baseAddress="http://localhost:7741/NorthwindServices/Services
                                    /OrderService" />
        <add baseAddress="net.pipe://localhost/Services/OrderService" />
        </baseAddresses>
    </host>
    
    <endpoint address ="" binding="wsHttpBinding"
            contract="NorthwindServices.ServiceContracts.IOrderService"
            bindingNamespace = "http://dotnetmentors.com/services/order" />
            
    <endpoint address="mex" binding="mexHttpBinding" 
                    contract="IMetadataExchange"/>
    
    <endpoint address = "" binding ="netNamedPipeBinding"
            contract = "NorthwindServices.ServiceContracts.IOrderService"
            bindingNamespace = "http://dotnetmentors.com/services/order"  />
    <endpoint address="mex" binding="mexNamedPipeBinding" 
                    contract="IMetadataExchange"/>
            
    </service>
    </services>    
    <behaviors>
        <serviceBehaviors>
        <behavior name ="ServiceBehavior" >
            <serviceMetadata httpGetEnabled="True"/>
            <serviceDebug includeExceptionDetailInFaults="False" />
        </behavior>
        </serviceBehaviors>
    </behaviors>
    </system.serviceModel>    
                        
                
  8. Hosting Services to IIS and Windows Services

    We will be hosting Customer service and Order Service to IIS and Windows Services.

    1. Hosting WCF Services in IIS 7.0+ Go through the article for hosting services in IIS WCF service in IIS
      In article we have use the ProductService to host. You need to follow same steps for Customer Service and Order Service.
      Create a folder Hosts in your service library application and place the CustomerServiceHost.svc and OrderServiceHost.svc before hosting the service in IIS.
      While hosting WCF service with netNamedPipeBinding in IIS some bindings errors might occur. This article hosting wcf service with netNamedPipeBinding in IIS might help you to sesolve those errors.
    2. Hosting WCF Services in Windows Services Host WCF CustomerService and OrderService in Windows service.
      Make sure <System.ServiceModel> of app.config file of Windows Services and WCF Service Library are identical.

  9. CustomerService and OrderService Clients

    Add client application as suggested in previous step. Ideally we should add have two application to use those services.

    Console application to use netNamedPipeBindings and web application to test wsHttpBinding (you can test both bindings from any application as long as service and client are on same machine.)

    1. Console Application Add reference to CustomerService and OrderService. Use below addresses to add service reference.
                              
              net.pipe://localhost/Services/CustomerService
      
              net.pipe://localhost/Services/OrderService
                                  
                      

      When you add service you will have client endpoint in your console applications app.config. You will have both netNamedPipeBinding and wsHttpBinding endpoint in your client app.config.

      Add below code to client application

                              
      using NorthwindBackOffice.CustomerServiceRef;
      using NorthwindBackOffice.OrderServiceRef;
      
      namespace NorthwindBackOffice
      {
      class Program
      {
      static void Main(string[] args)
      {
          ShowCustomerDetails();
          Console.WriteLine(); 
          ShowOrderDetails();
          Console.Read(); 
      }
      
      private static void ShowCustomerDetails()
      {
          string customerCity = string.Empty;
          string customerName = string.Empty;
          int customerCount = 0;
      
          using (CustomerServiceClient client =
          new CustomerServiceClient("NetNamedPipeBinding_ICustomerService"))
          {
                  customerCity = client.GetCustomerCity(2);
                  customerName = client.GetCustomerName(2);
                  customerCount = client.GetCustomerCount();   
          }
      
          Console.WriteLine("******* Customer Data **************");
          Console.WriteLine("Customer Name : " + customerName);   
          Console.WriteLine("Customer City : " + customerCity);
          Console.WriteLine("Total customer count : "
                                  + customerCount.ToString());    
      }
      
      private static void ShowOrderDetails()
      {
          string orderAmount = string.Empty;
          string orderDate = string.Empty;
          string orderShip = string.Empty;
      
          using (OrderServiceClient client = 
          new OrderServiceClient("NetNamedPipeBinding_IOrderService"))
          {
              orderAmount = client.GetOrderAmount(10250);
              orderDate = client.GetOrderDate(10250);
              orderShip = client.GetShipCountry(10250);
          }
      
          Console.WriteLine("******* Order Data **************");
          Console.WriteLine("Order Amount : " + orderAmount);
          Console.WriteLine("Order Date : " + orderDate);
          Console.WriteLine("Ship Country : " + orderShip);
      }
      }
      }
                      

      Notice that we have mentioned binding name while creating the instance of service because two endpoints are available for one service with different bindings.

    2. WebApplication as client for WCF services Add a web application to solution and add service reference using below address.
          http://localhost:7741/NorthwindServices/Services/CustomerService
      
          http://localhost:7741/NorthwindServices/Services/OrderService
                      

Download source code.

Speak your mind :
Leave a comment for this article on dotnetbloogers.com