How to: Programmatically Add Discoverability to a WCF Service and Client
This topic explains how to make a Windows Communication Foundation (WCF) service discoverable. It is based on the Self-Host sample.
To configure the existing Self-Host service sample for Discovery
Open the Self-Host solution in Visual Studio 2012. The sample is located in the TechnologySamples\Basic\Service\Hosting\SelfHost directory.
Add a reference to
System.ServiceModel.Discovery.dll
to the service project. You may see an error message saying "System. ServiceModel.Discovery.dll or one of its dependencies requires a later version of the .NET Framework than the one specified in the project …" If you see this message, right-click the project in the Solution Explorer and choose Properties. In the Project Properties window, make sure that the Target Framework is .NET Framework 4.6.1.Open the Service.cs file and add the following
using
directive.using System.ServiceModel.Discovery;
In the
Main()
method, inside theusing
statement, add a ServiceDiscoveryBehavior instance to the service host.public static void Main() { // Create a ServiceHost for the CalculatorService type. using (ServiceHost serviceHost = new ServiceHost(typeof(CalculatorService))) { // Add a ServiceDiscoveryBehavior serviceHost.Description.Behaviors.Add(new ServiceDiscoveryBehavior()); // ... } }
The ServiceDiscoveryBehavior specifies that the service it is applied to is discoverable.
Add a UdpDiscoveryEndpoint to the service host right after the code that adds the ServiceDiscoveryBehavior.
// Add ServiceDiscoveryBehavior serviceHost.Description.Behaviors.Add(new ServiceDiscoveryBehavior()); // Add a UdpDiscoveryEndpoint serviceHost.AddServiceEndpoint(new UdpDiscoveryEndpoint());
This code specifies that discovery messages should be sent to the standard UDP discovery endpoint.
To create a client application that uses discovery to call the service
Add a new console application to the solution called
DiscoveryClientApp
.Add a reference to
System.ServiceModel.dll
andSystem.ServiceModel.Discovery.dll
Copy the GeneratedClient.cs and App.config files from the existing client project to the new DiscoveryClientApp project. To do this, right-click the files in the Solution Explorer, select Copy, and then select the DiscoveryClientApp project, right-click and select Paste.
Open Program.cs.
Add the following
using
directives.using System.ServiceModel; using System.ServiceModel.Discovery; using Microsoft.ServiceModel.Samples;
Add a static method called
FindCalculatorServiceAddress()
to theProgram
class.static EndpointAddress FindCalculatorServiceAddress() { }
This method uses discovery to search for the
CalculatorService
service.Inside the
FindCalculatorServiceAddress
method, create a new DiscoveryClient instance, passing in a UdpDiscoveryEndpoint to the constructor.static EndpointAddress FindCalculatorServiceAddress() { // Create DiscoveryClient DiscoveryClient discoveryClient = new DiscoveryClient(new UdpDiscoveryEndpoint()); }
This tells WCF that the DiscoveryClient class should use the standard UDP discovery endpoint to send and receive discovery messages.
On the next line, call the Find method and specify a FindCriteria instance that contains the service contract you want to search for. In this case, specify
ICalculator
.// Find ICalculatorService endpoints FindResponse findResponse = discoveryClient.Find(new FindCriteria(typeof(ICalculator)));
After the call to Find, check to see if there is at least one matching service and return the EndpointAddress of the first matching service. Otherwise return
null
.if (findResponse.Endpoints.Count > 0) { return findResponse.Endpoints[0].Address; } else { return null; }
Add a static method named
InvokeCalculatorService
to theProgram
class.static void InvokeCalculatorService(EndpointAddress endpointAddress) { }
This method uses the endpoint address returned from
FindCalculatorServiceAddress
to call the calculator service.Inside the
InvokeCalculatorService
method, create an instance of theCalculatorServiceClient
class. This class is defined by the Self-Host sample. It was generated using Svcutil.exe.// Create a client CalculatorClient client = new CalculatorClient();
On the next line, set the endpoint address of the client to the endpoint address returned from
FindCalculatorServiceAddress()
.// Connect to the discovered service endpoint client.Endpoint.Address = endpointAddress;
Immediately after the code for the previous step, call the methods exposed by the calculator service.
Console.WriteLine("Invoking CalculatorService at {0}", endpointAddress); double value1 = 100.00D; double value2 = 15.99D; // Call the Add service operation. double result = client.Add(value1, value2); Console.WriteLine("Add({0},{1}) = {2}", value1, value2, result); // Call the Subtract service operation. result = client.Subtract(value1, value2); Console.WriteLine("Subtract({0},{1}) = {2}", value1, value2, result); // Call the Multiply service operation. result = client.Multiply(value1, value2); Console.WriteLine("Multiply({0},{1}) = {2}", value1, value2, result); // Call the Divide service operation. result = client.Divide(value1, value2); Console.WriteLine("Divide({0},{1}) = {2}", value1, value2, result); Console.WriteLine(); //Closing the client gracefully closes the connection and cleans up resources client.Close();
Add code to the
Main()
method in theProgram
class to callFindCalculatorServiceAddress
.public static void Main() { EndpointAddress endpointAddress = FindCalculatorServiceAddress(); }
On the next line, call the
InvokeCalculatorService()
and pass in the endpoint address returned fromFindCalculatorServiceAddress()
.if (endpointAddress != null) { InvokeCalculatorService(endpointAddress); } Console.WriteLine("Press <ENTER> to exit."); Console.ReadLine();
To test the application
Open an elevated command prompt and run Service.exe.
Open a command prompt and run Discoveryclientapp.exe.
The output from service.exe should look like the following output.
Received Add(100,15.99) Return: 115.99 Received Subtract(100,15.99) Return: 84.01 Received Multiply(100,15.99) Return: 1599 Received Divide(100,15.99) Return: 6.25390869293308
The output from Discoveryclientapp.exe should look like the following output.
Invoking CalculatorService at http://localhost:8000/ServiceModelSamples/service Add(100,15.99) = 115.99 Subtract(100,15.99) = 84.01 Multiply(100,15.99) = 1599 Divide(100,15.99) = 6.25390869293308 Press <ENTER> to exit.
Example
The following is a listing of the code for this sample. Because this code is based on the Self-Host sample, only those files that are changed are listed.
// Service.cs
using System;
using System.Configuration;
using System.ServiceModel;
using System.ServiceModel.Discovery;
namespace Microsoft.ServiceModel.Samples
{
// See SelfHost sample for service contract and implementation
// ...
// Host the service within this EXE console application.
public static void Main()
{
// Create a ServiceHost for the CalculatorService type.
using (ServiceHost serviceHost = new ServiceHost(typeof(CalculatorService)))
{
// Add the ServiceDiscoveryBehavior to make the service discoverable
serviceHost.Description.Behaviors.Add(new ServiceDiscoveryBehavior());
serviceHost.AddServiceEndpoint(new UdpDiscoveryEndpoint());
// Open the ServiceHost to create listeners and start listening for messages.
serviceHost.Open();
// The service can now be accessed.
Console.WriteLine("The service is ready.");
Console.WriteLine("Press <ENTER> to terminate service.");
Console.WriteLine();
Console.ReadLine();
}
}
}
}
// Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Discovery;
using Microsoft.ServiceModel.Samples;
using System.Text;
namespace DiscoveryClientApp
{
class Program
{
static EndpointAddress FindCalculatorServiceAddress()
{
// Create DiscoveryClient
DiscoveryClient discoveryClient = new DiscoveryClient(new UdpDiscoveryEndpoint());
// Find ICalculatorService endpoints
FindResponse findResponse = discoveryClient.Find(new FindCriteria(typeof(ICalculator)));
if (findResponse.Endpoints.Count > 0)
{
return findResponse.Endpoints[0].Address;
}
else
{
return null;
}
}
static void InvokeCalculatorService(EndpointAddress endpointAddress)
{
// Create a client
CalculatorClient client = new CalculatorClient();
// Connect to the discovered service endpoint
client.Endpoint.Address = endpointAddress;
Console.WriteLine("Invoking CalculatorService at {0}", endpointAddress);
double value1 = 100.00D;
double value2 = 15.99D;
// Call the Add service operation.
double result = client.Add(value1, value2);
Console.WriteLine("Add({0},{1}) = {2}", value1, value2, result);
// Call the Subtract service operation.
result = client.Subtract(value1, value2);
Console.WriteLine("Subtract({0},{1}) = {2}", value1, value2, result);
// Call the Multiply service operation.
result = client.Multiply(value1, value2);
Console.WriteLine("Multiply({0},{1}) = {2}", value1, value2, result);
// Call the Divide service operation.
result = client.Divide(value1, value2);
Console.WriteLine("Divide({0},{1}) = {2}", value1, value2, result);
Console.WriteLine();
//Closing the client gracefully closes the connection and cleans up resources
client.Close();
}
static void Main(string[] args)
{
EndpointAddress endpointAddress = FindCalculatorServiceAddress();
if (endpointAddress != null)
{
InvokeCalculatorService(endpointAddress);
}
Console.WriteLine("Press <ENTER> to exit.");
Console.ReadLine();
}
}
}