Tuesday, April 12, 2011

What’s New in WCF 4.0

Windows Communication Foundation i.e WCF 4.0 comes with wide range of new features on top of WCF 3.5. Following table highlights few of the main features.
Feature Description
Service Discovery Discovery of WCF Service hosted within network using ad-hoc and managed service discovery behaviors, which conform to the standard WS-Discovery protocol.
Simplified Configuration Simplification of the WCF configuration section through support for default endpoints, binding and behavior configurations.
Routing Service Provides features for content-based routing, protocol bridging, and error handling.
REST Improvements Enhancements to the WCF 3.5 Web programming model with some additional features that simplify REST service development.
Workflow Services Provides integration of WCF with WF to implement declarative long-running workflow services.
First we will focus on Service Discovery feature in WCF 4.0 -
In some of the typical SOA environments, there are services whose runtime location is dynamic and constantly changing. Consider environments where different types of service-enabled devices are constantly joining and leaving the network as part of the overall application solution. In this situation you need a client/s to dynamically discover the runtime location of service endpoints.
WS-Discovery is a specification that defines a SOAP-based protocol for dynamically discovering the location of service endpoints at runtime. The client/s probe for service endpoint that match certain criteria. Once the client discovers the service, it continues to invoke it as with regular WCF calls.
Discovery relies on UDP (User Datagram Protocol). Unlike TCP, UDP is a connectionless protocol, and no direct connection is required between the packet’s sender and the receiver. The client uses UDP to broadcast discovery requests for any endpoint supporting a specified contract type. UDP discovery endpoints that the services support will receive these requests and provide response back to client.
To understand Service Discovery concept, let’s start a step by step walk-through to create, host, discover and consume a WCF Service.
1. Open Visual Studio 2010 click File > New > Project. Select .NET Framework 4. Select Visual C# > Windows > Class Library. Name the project as DiscoverableServiceContract and click Add.
2. Delete Class1.cs file, as we don’t need this.
3. Right-click on References node, select Add Reference… Click .NET tab and select System.ServiceModel and click Add to add this assembly into your project.
We have added this assembly to create a WCF contract.
4. Right-click on project name Add > New Item > Code > Interface. Name this interface as IDiscoverableService.cs and click Add.
5. Add following code to this interface -
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
namespace DiscoverableServiceContract
{
    [ServiceContract]
    public interface IDiscoverableService
    {
        [OperationContract]
        string SayHello(string uName);
    }
}
6. Save your work and build the project.
This way our Discoverable Service Contract is ready to be used by Service provider and Service Consumer.
7. For the simplicity, we will add three more projects to the same solution as DiscoverableService, DiscoverableServiceHost and ServiceClient.
8. So right-click on the solution name Add > New Project. Click Visual C# > Windows > Class Library and name it DiscoverableService, click Add.
9. Delete Class1.cs and right click on References node, click Recent tab select System.ServiceModel and click Ok.
10. Again right-click on References node, click Projects tab and select DiscoverableServiceContract, click Ok.
11. Right-click on DiscoverableService project Add > Class. Name this class as DiscoverableService.cs. Add the following code to this newly added class -
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DiscoverableServiceContract;

namespace DiscoverableService
{
    public class DiscoverableService : IDiscoverableService
    {
        public string SayHello(string uName)
        {
            return string.Format("Hello {0}. Message received at {1}", uName, DateTime.Now.ToString());
        }
    }
}
12. Build the DiscoverableService project. Now your service is ready to host. So let’s create a host project. we will host this service using Console Application.
13. Right-click on the solution name Add > New Project, select Visual C# > Windows > Console Application. Name it as DiscoverableServiceHost click Ok.
14. Right-click References node, click Projects tab and select DiscoverableServiceContract and DiscoverableService projects, click Add.
15. Again right-click References node, click Recent tab and select System.ServiceModel, click Add.
16.To add a configuration file to this host project, right-click on the project name Add > New Item > General > Application Configuration File and click Add.
17. Add the following xml code to this App.config file -
<configuration>
  <system.serviceModel>
    <services>
      <service name="DiscoverableService.DiscoverableService">
        <endpoint address="discoverableService" binding="netTcpBinding" contract="DiscoverableServiceContract.IDiscoverableService"/>
        <endpoint name="udpDiscovery" kind="udpDiscoveryEndpoint"/>
        <host>
          <baseAddresses>
            <add baseAddress="net.tcp://localhost:9001"/>
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <serviceDiscovery/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>
18. Make DiscoverableServiceHost project as Start up Project and add the following code to Program.cs class.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using DiscoverableService;
using DiscoverableServiceContract;
namespace DiscoverableServiceHost
{
    class Program
    {
        static void Main(string[] args)
        {
            using (ServiceHost host = new ServiceHost(typeof(DiscoverableService.DiscoverableService)))
            {
                host.Open();
                Console.WriteLine("Discoverable Service Hosted...");
                Console.WriteLine("Press a key to stop service");
                Console.ReadLine();
                host.Close();
            }
        }
    }
}
19. Save all your work, build the project and press ctrl+f5 to run the host. If every thing is OK and in place you should get out pout as follows -
image
20. Press a key to stop the service.
Now it’s time to create a Client.
21. Right-click on the solution Add > New Project > Visual C# > Windows > Console Application and name it ServiceClient.
22. Right-click on this project’s References node Add Reference > Projects, select DiscoverableServiceContract and click Add. Again add System.ServiceModel and System.ServiceModel.Discovery assembly to your client project.
We are using same contract because of couple of things -
1. Our client will be in the same network where the service is hosted.
2. We want to discover service without adding service reference to our client project.
23. To add configuration file, right-click on client project name Add > New Item > General > Application Configuration File, click Ok.
24. Add the following xml code to this App.config file -
<configuration>
  <system.serviceModel>
    <client>
      <endpoint binding="netTcpBinding" contract="DiscoverableServiceContract.IDiscoverableService" name="DiscoverableService" />
      <endpoint name="udpDiscoveryEndpoint" kind="udpDiscoveryEndpoint" />
    </client>
  </system.serviceModel>
</configuration>
25. Now to create proxy of service without adding service reference to out client project, we have to add a class named DiscoverableService.cs to client project.
26. Right-click on client project name Add > Class, name it DiscoverableService.cs and click Ok.
27. Add the following code to this DiscoverableService.cs class -
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using DiscoverableServiceContract;
namespace ServiceClient
{
    public class DiscoverableService : ClientBase<IDiscoverableService>, IDiscoverableService
    {
        public DiscoverableService(string endpointConfigurationName) : base(endpointConfigurationName)
        {
        }
        public string SayHello(string uName)
        {
            return base.Channel.SayHello(uName);
        }
    }
}
28. Now add following code to Program.cs class of client project -
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Discovery;
using System.ServiceModel;
using DiscoverableServiceContract;
namespace ServiceClient
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Finding IDiscoverableService Service...");
            DiscoveryClient discoveryClient = new DiscoveryClient("udpDiscoveryEndpoint");
            FindCriteria findCriteria = new FindCriteria(typeof(IDiscoverableService));
            FindResponse findResponse = discoveryClient.Find(findCriteria);
            if (findResponse.Endpoints.Count > 0)
            {
                Console.WriteLine("Found IDiscoverableService service at {0}", findResponse.Endpoints[0].Address);
            }
            EndpointAddress address = findResponse.Endpoints[0].Address;
            DiscoverableService proxy = new DiscoverableService("DiscoverableService");
            proxy.Endpoint.Address = address;
            Console.WriteLine("Invoking ICalculator service at {0}", address);
            string result = proxy.SayHello("UserNameOne");
            Console.WriteLine("Result :{0}", result);
            Console.ReadLine();
        }
    }
}
30. Now it’s time to discover service dynamically. Make sure your service is running, if not press ctrl+f5 to start it. Then go to solution explorer right-click on client project name Debug > Start New Instance.
31. If every thing is gone right, you should get an out put as follows -
image
32. Bingo we have done it.
Key Concepts of Service Discovery -
1. works with UDP protocol only.
2. service config should have
<endpoint name="udpDiscovery" kind="udpDiscoveryEndpoint"/>
and
<behavior>
<serviceDiscovery/>
</behavior>
3. client config should have
<endpoint name="udpDiscoveryEndpoint" kind="udpDiscoveryEndpoint"/>
4. DiscoveryClient class –> udpDiscoveryEndpoint
5. FindCriteria class –> contract type
6. FindResponse findResponse = discoveryClient.Find(findCriteria)
Note:- You can find service asynchronously using FindAsync() method of discoveryClient object. Try it!!!
All the best.
In the next episode I will talk about Service Announcements.