如何:以编程方式向 WCF 服务和客户端添加可发现性
本主题说明如何使 Windows Communication Foundation (WCF) 服务可发现。 本主题基于自承载示例。
针对 Discovery 配置现有自承载服务示例
在 Visual Studio 2012 中打开自承载解决方案。 示例位于 TechnologySamples\Basic\Service\Hosting\SelfHost 目录中。
将对
System.ServiceModel.Discovery.dll
的引用添加到服务项目中。 你可能会看到一条错误消息:“System. ServiceModel.Discovery.dll 或其依赖项之一需要的 .NET Framework 版本比项目中指定的版本高…”。如果看到此消息,请在解决方案资源管理器中右键单击相应项目并选择“属性”。 在“项目属性”窗口中,确保“目标框架”为 .NET Framework 4.6.1。打开 Service.cs 文件并添加下面的
using
指令。using System.ServiceModel.Discovery;
在
Main()
方法的using
语句内部,将一个 ServiceDiscoveryBehavior 实例添加到服务主机中。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()); // ... } }
ServiceDiscoveryBehavior 指定自身应用到的服务可供检测。
将 UdpDiscoveryEndpoint 添加到服务主机中,位置紧随添加 ServiceDiscoveryBehavior 的代码之后。
// Add ServiceDiscoveryBehavior serviceHost.Description.Behaviors.Add(new ServiceDiscoveryBehavior()); // Add a UdpDiscoveryEndpoint serviceHost.AddServiceEndpoint(new UdpDiscoveryEndpoint());
此代码指定应将发现消息发送到标准 UDP 发现终结点。
创建使用发现功能调用服务的客户端应用程序
向名为
DiscoveryClientApp
的解决方案添加一个新控制台应用程序。添加对
System.ServiceModel.dll
和System.ServiceModel.Discovery.dll
的引用将 GeneratedClient.cs 和 App.config 文件从现有客户端项目复制到新的 DiscoveryClientApp 项目。 为此,请在“解决方案资源管理器”中右键单击文件,选择“复制”,然后选择“DiscoveryClientApp”项目,接着右键单击并选择“粘贴”。
打开 Program.cs。
添加以下
using
指令。using System.ServiceModel; using System.ServiceModel.Discovery; using Microsoft.ServiceModel.Samples;
将一个名为
FindCalculatorServiceAddress()
的静态方法添加到Program
类。static EndpointAddress FindCalculatorServiceAddress() { }
此方法使用发现功能搜索
CalculatorService
服务。在
FindCalculatorServiceAddress
方法内部,创建新 DiscoveryClient 实例,以将 UdpDiscoveryEndpoint 传递给构造函数。static EndpointAddress FindCalculatorServiceAddress() { // Create DiscoveryClient DiscoveryClient discoveryClient = new DiscoveryClient(new UdpDiscoveryEndpoint()); }
此代码指示 WCF:DiscoveryClient 类应使用标准 UDP 发现终结点来发送和接收发现消息。
在下一行,调用 Find 方法并指定包含要搜索的服务协定的 FindCriteria 实例。 在本示例中,指定的是
ICalculator
。// Find ICalculatorService endpoints FindResponse findResponse = discoveryClient.Find(new FindCriteria(typeof(ICalculator)));
调用 Find 之后,查看是否至少有一个匹配服务,然后返回第一个匹配服务的 EndpointAddress。 如果找不到匹配服务,则返回
null
。if (findResponse.Endpoints.Count > 0) { return findResponse.Endpoints[0].Address; } else { return null; }
将名为
InvokeCalculatorService
的静态方法添加到Program
类。static void InvokeCalculatorService(EndpointAddress endpointAddress) { }
此方法使用从
FindCalculatorServiceAddress
返回的终结点地址调用计算器服务。在
InvokeCalculatorService
方法的内部,创建CalculatorServiceClient
类的实例。 此类由自承载示例定义, 并且是使用 Svcutil.exe 生成的。// Create a client CalculatorClient client = new CalculatorClient();
在下一行,将客户端的终结点地址设置为从
FindCalculatorServiceAddress()
返回的终结点地址。// 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();
将以下代码添加到
Main()
类中的Program
方法以调用FindCalculatorServiceAddress
。public static void Main() { EndpointAddress endpointAddress = FindCalculatorServiceAddress(); }
在下一行,调用
InvokeCalculatorService()
,并传递由FindCalculatorServiceAddress()
返回的终结点地址。if (endpointAddress != null) { InvokeCalculatorService(endpointAddress); } Console.WriteLine("Press <ENTER> to exit."); Console.ReadLine();
测试应用程序
打开具有特权的命令提示符并运行 Service.exe。
打开命令提示符并运行 Discoveryclientapp.exe。
service.exe 的输出应类似于以下输出。
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
Discoveryclientapp.exe 的输出应类似于以下输出。
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.
示例
下面是此示例的代码清单。 由于此代码基于自承载示例,因此只列出更改过的那些文件。
// 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();
}
}
}