WCF 4 comes with many new features for a better developer experience. There is a high integration with workflow service. Making a WCF REST service more developer friendly and a configuration-less WCF service. In short WCF 4 tries to address a common scenario easily and at the same time gives us more options for communicatation between service and client.
Below are the few new features of WCF 4.0:
- Dynamic Service and End Point discovery
- Intermediate Routing Pattern ( Generic Routing Services)
- Discovery announcement
- Simplified Configuration
- Protocol bridging and Fault tolerance
- Default End Points.
- .svc-less activation of REST services or making REST URI nice.
- Default Protocol Mapping
- Help page enabled for WCF Rest service and many more.
In this article we will see in detail three exciting features of WCF 4.0 and in further articles we will see the other features.
In this article we are going to see:
- EndPoint Discovery
- Default EndPoints
- Help page enabled for WCF REST Service
Problem
People say; you need to know only ABC of a service to expose End Point of that service. And client or service consumer needs to know only End Point to consume the service. But wait for a while here, and think; what if? Binding needs to change at the service side from basic to WS over HTTP. This is a very basic change but to accommodate this the client has to update the service again. And this is very error prone. It is a very tedious task to update the client about all the basic frequent changes at the service side. To solve this issue, there should be some mechanism and that is called End Point Discovery or Dynamic Service.
In absolute technical words
WCF 4.0 supports WS -Discovery standard or protocol.
WS-Discovery Standard
- This is a multicast protocol that issues a SOAP message over UDP.
- WS-Discovery is a Standard that defines a lightweight discovery mechanism for discovering services based on multicast messages. It enables a service to send a Hello announcement message when it is initialized and a Bye message when is removed from the network.
- Client or consumer can discover services by multicasting a Probe message to which a service can reply with a ProbeMatch message containing the information necessary to contact the service.
- Client or consumer can find services that have changed endpoint by issuing a Resolve message to which respond with a ResolveMatchmessage.
So, we can say WS -Discovery is a UDP based multicast message exchange. This message receives End Point information from Service and uses this as discovery information. Client uses discovery information to discover the available service on the network.
WCF Service Discovery API
WCF provides, WCF Discovery API for dynamic publish and discovery of web service using WS -Discovery protocol. This API helps service to publish them and helps client to find service on the network.
Modes
![WCF1.gif]()
Managed Mode
- In managed mode there is a centralized server called a discovery proxy that services use to publish themselves and clients use to retrieve information about available services.
- When a new service starts up it sends an announcement message to the discovery proxy.
- The discovery proxy saves information about each available service to storage.
- When a client must search for a service it sends a Probe request to the discovery proxy and it determines whether any of the services that have been published match the request.
- If there are matches the discovery proxy sends a ProbeMatch response back to the client.
- The client can then contact the service directly using the service information returned from the proxy.
Ad-Hoc Mode
- There is no centralized server.
- Service announcements and client requests are sent in a multicast fashion.
- If a service is configured to send out a Hello announcement on start up, it sends it out over a well-known, multicast address using the UDP protocol.
- Therefore, clients have to actively listen for these announcements and process them accordingly.
- When a client issues a Probe request for a service it is also sent over the network using a multicast protocol.
- Each service that receives the request determines whether it matches the criteria in the Probe request and responds directly to the client with a ProbeMatch message if the service matches the criteria specified in the Probe request.
Sample
In this sample, we will create a very basic service and at the client side, first the client will discover the service in Ad-Hoc mode and then consume that.
To run and go through this sample, you need Visual Studio 2010 Beta.
To make a service discoverable, a ServiceDiscoveryBehavior must be added to the service host and a discovery endpoint must be added to specify where to listen for and send a discovery message.
Step 1
Open VS2010. Create a new project by choosing WCF Service Application Project template.
Step 2
Delete all the code which is generated by Visual studio. After deleting Contract and Service Implantation is as follows.
IService1.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
namespace WcfService1
{
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetMessage(string msg);
}
}
Service1.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
namespace WcfService1
{
public class Service1 : IService1
{
public string GetMessage(string msg)
{
return msg;
}
}
}
The above is a simple Service Contract and implantation of that.
Step 3
Open Web.Config file. And modify the System.ServiceModel. Add the code which is in a red rectangle below.
Web.Config
![WCF2.gif]()
Explanation of Config file
-
One new End Point is being added.
-
The kind of the newly added End Point is udpDiscoveryEndpoint.
-
This End Point will be used to discover the service.
-
ServiceDiscovery behavior is also added.
Step 4
Press F5 to run the service. The service will be hosted in an ASP.Net web server.
![WCF3.gif]()
Step 5
Add a new console project to the solution.
Step 6
Add a Reference of System.ServiceModel.Discovery.dll to the console project.
![WCF4.gif]()
Step 7
Add a namespace using System.ServiceModel.Discovery;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ConsoleApplication1.ServiceReference1;
using System.ServiceModel;
using System.ServiceModel.Discovery;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
DiscoveryClient discoverclient = new DiscoveryClient(new UdpDiscoveryEndpoint());
FindResponse response = discoverclient.Find(new FindCriteria(typeof(IService1)));
EndpointAddress address = response.Endpoints[0].Address;
Service1Client client = new Service1Client(new WSHttpBinding(), address);
string str= client.GetMessage("Hello WCF 4 ");
Console.WriteLine(str);
Console.ReadKey(true);
}
}
}
Explanation of the code
-
We are making object of DiscoveryClient class. This class is used to discover an available service.
-
In the constructor of this class, we are passing UdpDiscoveryEndPoint of the service.
-
Then we are calling a Find method with contract name as argument to get FindResponse.
-
Now the FindResponse variable has all the available addresses for the contract passed in the Find method.
-
We are creating the client proxy and passing the discovered address as argument.
-
Calling the service operation on the client proxy.
Output
![WCF5.gif]()
Default End Points and Protocol mapping
For a normal developer like me, it was a great challenge working with WCF 3.x was configuration of End Points in config file. The developer had to add endpoints to setup a WCF service. In WCF 4, the defualt End Point is associated with the service, if we don't configure any WCF endpoint.
Walkthrough
To see how a default EndPoint works, follow the steps below.
Step 1
Create a WCF service application.
Let us create two service contracts.
IService1.cs
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetData();
}
IService2.cs
[ServiceContract]
public interface IService2
{
[OperationContract]
string GetMessage();
}
Now let us implement the service as below,
public class Service1 : IService1, IService2
{
public string GetData()
{
return "Hello From Iservice1 ";
}
public string GetMessage()
{
return " Hello From Iservice2";
}
Step 2
Now we will host this service in a console application. Create a new console application project.
Add a reference of a WCF service application project and also add reference of System.serviceModel in the console application project.
Note: There is no App.Config associated with the console application.
![WCF6.gif]()
Here, we are registering two base addresses with the servicehost. One for http binding and the other for nettcp binding.
Now we don't have any configuration for the service EndPoint. ServiceHost will create a default EndPoints.
Now ServiceHost will configure EndPoints for two base addresses.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Description;
using WcfService1;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(WcfService1.Service1),
new Uri("http://localhost:8080/service"),
new Uri("net.tcp://localhost:8081/service"));
host.Open();
foreach (ServiceEndpoint se in host.Description.Endpoints)
{
Console.WriteLine("Address: " + se.Address.ToString() +
" Binding: " + se.Binding.Name +
" Contract :"+ se.Contract.Name);
}
Console.ReadKey(true);
}
}
}
Output would be
![WCF7.gif]()
The default protocol mapping for default EndPoints are mapped as below:
![WCF8.gif]()
Since HTTP is mapped with basicHttpBinding, the default EndPoint is basicHttpBinding.
Default EndPoint will only get created if there is not a single Endpoint configured. If we add a single EndPoint then there won't be any default EndPoint configured.
If we add one EndPoint as below:
![WCF9.gif]()
We added one service EndPoint and now the output we would get for below code is as below:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Description;
using WcfService1;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(WcfService1.Service1),
new Uri("http://localhost:8080/service"),
new Uri("net.tcp://localhost:8081/service"));
host.AddServiceEndpoint(typeof(IService1),
new WSHttpBinding(),
"myBinding");
host.Open();
foreach (ServiceEndpoint se in host.Description.Endpoints)
{
Console.WriteLine("Address: " + se.Address.ToString() +
" Binding: " + se.Binding.Name +
" Contract :"+ se.Contract.Name);
}
Console.ReadKey(true);
}
}
}
Output
![WCF10.gif]()
Now we see that if we configure an EndPoint then WCF does not support default Endpoints.
If we closely look at the output then we will see that by default WCF maps protocol to binding as below.
![WCF11.gif]()
So if we are not configuring any EndPoint, then for the http type base address in default EndPoint created by WCF will have basicHttpBinding.
If we see the above mapping, by default the http type is mapped to basicHttpBinding, net.tcp type is mapped to netTcpBinding and so on.
If we want to change this, we can change this default mapping
![WCF12.gif]()
Now when we do the above change in the Web.Config file then when we do not define any EndPoint then for HTTP type base address, WCF will create the EndPoint with wsHttpBinding.
So to understand more, what I am talking about
-
Create a WCF Service application
-
Create a Service contract as below
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetData();
}
-
Implement the Service as below
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetData();
}
3. Implement the Service as below
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
namespace WcfService1
{
public class Service1 : IService1
{
public string GetData()
{
return "Hello From Iservice1 ";
}
}
4. Now we will host this service in a console application. Create a new console application project. Add a reference of WCF service application project and also add a reference of System.serviceModel in the console application project.
5. Right click on the console project and add app.config file to the console project. Right the below configuration in App.Config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<protocolMapping >
<add scheme ="http" binding ="wsHttpBinding" bindingConfiguration ="" />
</protocolMapping>
</system.serviceModel>
</configuration>
6. Now write the below code to fetch the default Endpoint created by WCF
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Description;
using WcfService1;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(WcfService1.Service1),
new Uri("http://localhost:8080/service"));
host.Open();
foreach (ServiceEndpoint se in host.Description.Endpoints)
{
Console.WriteLine("Address: " + se.Address.ToString() +
" Binding: " + se.Binding.Name +
" Contract :"+ se.Contract.Name);
}
Console.ReadKey(true);
}
}
}
And the output we would get is:
![WCF13.gif]()
So we can see how we modified the default mapping using Protocol mapping in System.ServiceModel.
Enabling Help page for REST Service in WCF 4.0
WCF 4.0 provides us a feature to eanable Help page on WCF REST Service.
Walkthrough
In this walkthrough we will see:
-
How to create a REST based service?
-
How to host a REST based service in Console application?
-
How to enable Help page for REST Service?
Follow the steps as below.
Step 1
Create a New project. Select Console application as project type.
![WCF14.gif]()
Step 2
Add a new project to the same solution. Choose Class Library as the project type.
![WCF15.gif]()
Step 3
Add below references in both projects console and service library:
System.ServiceModel;
System.ServiceModel.Description;
System.ServiceModel.Web;
![WCF16.gif]()
If you are not able to get System.ServiceModel.Web dll by default, when you are adding as Add Reference in your console application project and class library project, then follow the below steps.
-
Right click on your console application project or class library project
-
Select properties from context menu
-
From the Application tab, if you see by default .NET Framework 4 Client profile is selected. Change that to .NET Framework 4.0. So your target framework should be .NET Framework 4.0.
![WCF17.gif]()
Now you should able to see all the dll when you add service reference in project.
Step 4
In this step, I will create contract of service.
-
Open the Contract (Class Library project).
-
Delete Class1.
-
Right click and add a new item then select Interface from Code tab.
-
Make Interface as public and put ServiceContract attribute.
-
Declare two operation contracts. Make one attributed with WebGet and another attributed with Web Invoke.
IService.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Web;
namespace Contracts
{
[ServiceContract]
public interface IService
{
[OperationContract] [WebGet]
string GetMessage(string inputMessage);
[OperationContract]
[WebInvoke]
string PostMessage(string inputMessage);
}
}
Step 5
In this step, I will implement the contract in Service file. To do so,
-
Right click and add a class in Console application.
![WCF19.gif]()
-
Give any name; I am giving name here Service of the class.
-
Implement the interface (Contract IService) in this class.
Service.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Contracts;
namespace SelfHostedRESTService
{
public class Service :IService
{
public string GetMessage(string inputMessage)
{
return "Calling Get for you " + inputMessage;
}
public string PostMessage(string inputMessage)
{
return "Calling Post for you " + inputMessage;
}
}
}
Step 6
In this step, I will host the service in a console application. So to do so
-
Open Program.cs
-
Create instanced of WebServieceHostFactory
![WCF20.gif]()
-
Add a service end point
![WCF21.gif]()
-
Add service host behavior with help page enabled
![WCF22.gif]()
As we know, REST service used webHttpBindding. And we are enabling Help page here.
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Web;
using Contracts;
namespace SelfHostedRESTService
{
class Program
{
static void Main(string[] args)
{
WebServiceHost host = new WebServiceHost(typeof(Service), new Uri("http://localhost:8000"));
ServiceEndpoint ep = host.AddServiceEndpoint(typeof(IService), new WebHttpBinding(), "");
host.Description.Endpoints[0].Behaviors.Add(new WebHttpBehavior { HelpEnabled = true });
host.Open();
Console.WriteLine("Service is up and running");
Console.WriteLine("Press enter to quit ");
Console.ReadLine();
host.Close();
}
}
}
Step 7
Just press F5 to run the service.
![WCF23.gif]()
Now once the service is up and running, I can test it.
To test the Help page, just type:
![WCF24.gif]()
When you click on Get or Post link you will get below detail help.
![WCF25.gif]()
In the next article we will see other features of WCF 4.0