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 in all aspects.
So in this article, I will explain to you how to create multiple WCF services to serve different entities in one solution with different endpoints 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
If you would like to know about how to start with WCF go through the article Create a new WCF service library and test using WCFTestClient
Create an 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.
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.
Add the ICustomerService contract to the ServiceContracts folder created in the previous step.
Right click on ServiceContracts and add new Interface to folder. Name it as ICustomerService. Add ServiceContract attribute to ICustomer.
Add OperationContract to ICustomerService which will be accessible to the clients. Your ICustomerService should look like.
using System.ServiceModel;
namespace NorthwindServices.ServiceContracts
{
[ServiceContract(Namespace = "https://geeksarray.com/services/customer")]
public interface ICustomerService
{
[OperationContract]
string GetCustomerName(int CustomerID);
[OperationContract]
string GetCustomerCity(int CustomerID);
[OperationContract]
int GetCustomerCount();
}
}
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 = "https://geeksarray.com/services/order")]
public interface IOrderService
{
[OperationContract]
string GetOrderDate(int orderID);
[OperationContract]
string GetOrderAmount(int OrderID);
[OperationContract]
string GetShipCountry(int orderID);
}
}
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>
using NorthwindServices.ServiceContracts;
using System.Xml.Linq;
namespace NorthwindServices.Services
{
[ServiceBehavior(Namespace="https://geeksarray.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();
}
}
}
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="https://geeksarray.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 .
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 the client is on the 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 = "https://geeksarray.com/services/customer" />
<endpoint address="mex" binding="mexHttpBinding"
contract="IMetadataExchange"/>
<endpoint address ="" binding ="netNamedPipeBinding"
contract ="NorthwindServices.ServiceContracts.ICustomerService"
bindingNamespace = "https://geeksarray.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 = "https://geeksarray.com/services/order" />
<endpoint address="mex" binding="mexHttpBinding"
contract="IMetadataExchange"/>
<endpoint address = "" binding ="netNamedPipeBinding"
contract = "NorthwindServices.ServiceContracts.IOrderService"
bindingNamespace = "https://geeksarray.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>
We will be hosting Customer service and Order Service to IIS and Windows Services.
Hosting WCF Services in IIS 7.0+ Go through the article for hosting services in IIS WCF service in IIS this gives you steps to host the ProductService WCF Servie in IIS. 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 resolve those errors.
Make sure <System.ServiceModel> of app.config file of Windows Services and WCF Service Library are identical.
Add client application as suggested in the previous step. Ideally, we should have add two applications 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 the same machine.)
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 the 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 a binding name while creating the instance of service because two endpoints are available for one service with different bindings.
WebApplication as a client for WCF services Add a web application to the solution and add service reference using the below address.
http://localhost:7741/NorthwindServices/Services/CustomerService http://localhost:7741/NorthwindServices/Services/OrderService