Microsoft.NET 4.0 and Visual Studio.NET 2010 ships a lot of new features in their underlying technologies. In this series of articles, I want to talk about the new features in the area of Windows Communication Foundation (WCF) in order to improve the development experience, enable more communication scenario, support new WS-* standards and provide a good integration with Windows Workflow Foundation (WF).
The new features are essentially the following: simplified configuration, standard endpoints, IIS hosting without a SVC file, support for WS-Discovery, routing service, REST improvements, enhancements for the integration with WF to support workflow services, simple byte stream encoding and ETW tracing.
In this series of article, I will illustrate each feature explaining the principles and showing some examples.
Support for WS-Discovery
This is the major feature that WCF 4.0 ships. The context of the scenario covered by this features is an organization whose business approach is service-oriented and the services are constantly joining and leaving the network. The problem in this context is that the runtime location of these services is constantly changing and the clients need to dynamically discover the new locations.
In order to cover this common scenario, the WS-Discovery specification was defined to extend the SOAP protocol for dynamically discovery of services location. The approach enables a client to probe for service endpoints matching certain criteria to get a list of candidates. Then this client can choose one service from the list of candidates.
WS-Discovery defines two modes of operation: managed and ad-hoc mode.
In the managed mode there is a central server called discovery proxy that services used to publish their underlying endpoints. Then, clients talk directly to the discovery proxy to locate services based on different criteria. WCF 4.0 provides classes to implement your own discovery proxy.
In the ad-hoc mode, there is no central server. Service announcement and client requests are sent in a multicast fashion. Clients discover the services by sending multicast messages, then services that match the probe respond directly to the client. In order to minimize the need of the client discovering new services, then the client can listen to the network for new service announcements. The limitation of this operation mode is that the service discovery operation is limited by the protocol used for multicast messages. In the case of using UDP protocol, the multicast is limited to the local network.
Let's add support for WS-Discovery to our EchoService service defined in the first part of the series.
The service contract is shown in the Listing 1
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
namespace WCF_NewFeatures
{
[ServiceContract]
public interface IEchoService
{
[OperationContract]
string Echo(String message);
}
}
Listing 1
And the service implementation is shown in the Listing 2.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
namespace WCF_NewFeatures
{
public class EchoService : IEchoService
{
public string Echo(String message)
{
return "Called the Echo Service with message " + message;
}
}
}
Listing 2
Now let's add WS-Discovery in the configuration file (see highlighted in yellow in the Listing 3).
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name="WCF_NewFeatures.EchoService" behaviorConfiguration="WCF_NewFeatures.EchoServiceBehavior">
<endpoint address="" binding="wsHttpBinding" contract="WCF_NewFeatures.IEchoService">
</endpoint>
<endpoint name ="udpDiscovery" kind ="udpDiscoveryEndpoint" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="WCF_NewFeatures.EchoServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
<serviceDiscovery />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
Listing 3
And the service host is defined as shown in the
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Description;
namespace WCF_NewFeatures
{
class Program
{
static void Main(string[] args)
{
ServiceHost serviceHost = new ServiceHost(typeof(WCF_NewFeatures.EchoService),new Uri("http://localhost:8080/Services/EchoService"));
serviceHost.Open();
System.Console.WriteLine("The EchoService has started");
foreach (ServiceEndpoint se in serviceHost.Description.Endpoints)
{
System.Console.WriteLine("Address:{0}, Binding:{1}, Contract:{2}", se.Address, se.Binding.Name, se.Contract.Name);
}
System.Console.WriteLine("Please, press any key to finish ...");
System.Console.ReadLine();
serviceHost.Close();
}
}
}
Listing 4
When you run the application, you can see the WSDL at http://localhost:8080/Services/EchoService as shown in the Figure 1.
Figure 1
Next step is to consume this service. Let's add a new console project as the client-side and add a reference to the System.ServiceModel.dll and System.ServiceModel.Discovery.dll assemblies (see Figure 2).
Figure 2
Next step is to move to the project directory and run the command svcutil.exe http://localhost:8080/Services/EchoService?wsdl to generate the service proxy and the underlying configuration. Let's include only the service proxy definition because the service location (in the configuration file) will be discovered dynamically.
Now let's write the discovery code for the client application (see Listing 5).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Discovery;
namespace WCFClientConsApp
{
class Program
{
static void Main(string[] args)
{
DiscoveryClient discoveryClient = new DiscoveryClient(new UdpDiscoveryEndpoint());
FindResponse findResponse = discoveryClient.Find(new FindCriteria(typeof(IEchoService)));
EndpointAddress endpointAddress = findResponse.Endpoints[0].Address;
EchoServiceClient echoServiceClient = new EchoServiceClient(new WSHttpBinding(), endpointAddress);
string strEcho = echoServiceClient.Echo("Hello world!");
System.Console.WriteLine("The service result is "+strEcho);
System.Console.WriteLine("Please, press any key to finish ...");
System.Console.ReadLine();
}
}
}
Listing 5
After you run the client solution and wait for a while, you will receive the output shown in the Figure 3.
Figure 3
Conclusion