发现 API 为使用 WS-Discovery 协议的 Web 服务的动态发布和发现提供统一的编程模型。 这些 API 允许服务自行发布,客户端可以查找已发布的服务。 一旦服务可发现,该服务就能够发送公告消息,并侦听和响应发现请求。 可发现的服务可以发送 Hello 消息,以宣布其抵达网络和 Bye 消息,以宣布其离开网络。 若要查找服务,客户端会发送包含 Probe 特定条件的请求,例如网络上的服务协定类型、关键字和范围。 服务接收 Probe 请求并确定它们是否与条件匹配。 如果服务匹配,它会通过向客户端发送消息 ProbeMatch 来响应,其中包含联系服务所需的信息。 客户端还可以发送 Resolve 请求,这些请求使他们能够查找可能已更改终结点地址的服务。 匹配服务通过向客户端发送Resolve消息来响应ResolveMatch请求。
临时和托管模式
发现 API 支持两种不同的模式:托管模式和即席模式。 在托管模式下,有一个名为发现代理的集中式服务器,用于维护有关可用服务的信息。 可以通过各种方式将关于服务的信息填充到发现代理服务器中。 例如,服务可以在启动期间向发现代理发送公告消息,或者代理可以从数据库或配置文件读取数据,以确定哪些服务可用。 发现代理的填充方式完全由开发人员决定。 客户端使用发现代理检索有关可用服务的信息。 当客户端搜索服务时,它会向发现代理发送消息 Probe ,代理确定它是否知道与客户端正在搜索的服务匹配的任何服务。 如果存在匹配项,发现代理会将响应发送 ProbeMatch 回客户端。 然后,客户端可以使用从代理返回的服务信息直接与服务联系。 托管模式所依据的关键原理是:以单播方式向一个机构(即发现代理)发送发现请求。 .NET Framework 包含可用于生成自己的代理的关键组件。 客户端和服务可以通过多种方法查找代理:
代理可以响应临时消息。
代理可以在启动期间发送公告消息。
可以编写客户端和服务来查找特定的已知终结点。
在即席模式下,没有集中式服务器。 所有发现消息(如服务公告和客户端请求)都以多播方式发送。 默认情况下,.NET Framework 包含对基于 UDP 协议的即席发现的支持。 例如,如果服务配置为在启动时发送 Hello 公告,则会使用 UDP 协议通过已知多播地址发送它。 客户必须积极听取这些公告,并相应地处理它们。 当客户端发送Probe消息以请求服务时,该消息会使用多播协议通过网络发送。 接收请求的每个服务都会检查它是否与消息中的Probe条件匹配。如果服务符合ProbeMatch消息中指定的条件,则直接以Probe消息响应客户端。
使用 WCF 发现的好处
由于 WCF 发现是使用 WS-Discovery 协议实现的,因此它与其他实现 WS-Discovery 的客户端、服务和代理互作。 WCF 发现是基于现有 WCF API 构建的,因此可以轻松地将发现功能添加到现有服务和客户端。 可以通过应用程序配置设置轻松添加服务可发现性。 此外,WCF 发现还支持在其他传输方法(如对等网络、命名覆盖和 HTTP)上使用发现协议。 WCF Discovery 支持采用发现代理的托管运行模式。 这可以减少网络流量,因为消息直接发送到发现代理,而不是将多播消息发送到整个网络。 WCF 发现还允许在处理 Web 服务时更具灵活性。 例如,可以更改服务的地址,而无需重新配置客户端或服务。 当客户端必须访问服务时,它可以通过Probe请求发出Find消息,并期望服务使用其当前地址做出响应。 WCF 发现允许客户端根据不同的条件(包括协定类型、绑定元素、命名空间、范围和关键字或版本号)搜索服务。 WCF Discovery 支持运行时和设计时发现功能。 可以将发现功能添加到应用程序中,这一特点可用于启用其他方案,如容错和自动配置。
服务发布
若要使服务可发现,必须将 ServiceDiscoveryBehavior 添加至服务主机,并且必须添加发现终结点以指定侦听发现消息的端点。 下面的代码示例演示如何修改自承载服务,使其可发现。
Uri baseAddress = new Uri($"http://{System.Net.Dns.GetHostName()}:8000/discovery/scenarios/calculatorservice/{Guid.NewGuid().ToString()}/");
// Create a ServiceHost for the CalculatorService type.
using (ServiceHost serviceHost = new ServiceHost(typeof(CalculatorService), baseAddress))
{
// Add calculator endpoint
serviceHost.AddServiceEndpoint(typeof(ICalculator), new WSHttpBinding(), string.Empty);
// ** DISCOVERY ** //
// Make the service discoverable by adding the discovery behavior
serviceHost.Description.Behaviors.Add(new ServiceDiscoveryBehavior());
// ** DISCOVERY ** //
// Add the discovery endpoint that specifies where to publish the services
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("Press <ENTER> to terminate service.");
Console.ReadLine();
}
ServiceDiscoveryBehavior必须将实例添加到服务说明中,才能发现该服务。 必须将DiscoveryEndpoint实例添加到服务主机,以指示服务应在何处侦听发现请求。 在本示例中,添加了 UdpDiscoveryEndpoint(派生自 DiscoveryEndpoint),用于指定服务应通过 UDP 多播传输侦听发现请求。 由于所有消息均以多播方式发送,因此,UdpDiscoveryEndpoint 用于临时发现。
公告
默认情况下,服务发布不会发送公告消息。 必须将服务配置为发送公告消息。 这就为服务编写器提供了额外的灵活性,因为它们可以分别通告服务和侦听发现消息。 服务公告还可用作向发现代理或其他服务注册表注册服务的机制。 以下代码演示如何将服务配置为通过 UDP 绑定发送公告消息。
Uri baseAddress = new Uri($"http://{System.Net.Dns.GetHostName()}:8000/discovery/scenarios/calculatorservice/{Guid.NewGuid().ToString()}/");
// Create a ServiceHost for the CalculatorService type.
using (ServiceHost serviceHost = new ServiceHost(typeof(CalculatorService), baseAddress))
{
// Add calculator endpoint
serviceHost.AddServiceEndpoint(typeof(ICalculator), new WSHttpBinding(), string.Empty);
// ** DISCOVERY ** //
// Make the service discoverable by adding the discovery behavior
ServiceDiscoveryBehavior discoveryBehavior = new ServiceDiscoveryBehavior();
serviceHost.Description.Behaviors.Add(discoveryBehavior);
// Send announcements on UDP multicast transport
discoveryBehavior.AnnouncementEndpoints.Add(
new UdpAnnouncementEndpoint());
// ** DISCOVERY ** //
// Add the discovery endpoint that specifies where to publish the services
serviceHost.Description.Endpoints.Add(new UdpDiscoveryEndpoint());
// Open the ServiceHost to create listeners and start listening for messages.
serviceHost.Open();
// The service can now be accessed.
Console.WriteLine("Press <ENTER> to terminate service.");
Console.ReadLine();
}
服务发现
客户端应用程序可以使用 DiscoveryClient 类查找服务。 开发人员创建一个 DiscoveryClient 类的实例并传入一个发现终结点,该终结点指定发送 Probe 或 Resolve 消息的位置。 然后,客户端调用 `Find`,该调用在 `FindCriteria` 实例中指定搜索条件。 如果找到匹配的服务, Find 则返回 的 EndpointDiscoveryMetadata集合。 以下代码演示如何调用 Find 该方法,然后连接到发现的服务。
class Client
{
static EndpointAddress serviceAddress;
static void Main()
{
if (FindService())
{
InvokeService();
}
}
// ** DISCOVERY ** //
static bool FindService()
{
Console.WriteLine("\nFinding Calculator Service ..");
DiscoveryClient discoveryClient =
new DiscoveryClient(new UdpDiscoveryEndpoint());
Collection<EndpointDiscoveryMetadata> calculatorServices =
(Collection<EndpointDiscoveryMetadata>)discoveryClient.Find(new FindCriteria(typeof(ICalculator))).Endpoints;
discoveryClient.Close();
if (calculatorServices.Count == 0)
{
Console.WriteLine("\nNo services are found.");
return false;
}
else
{
serviceAddress = calculatorServices[0].Address;
return true;
}
}
static void InvokeService()
{
Console.WriteLine("\nInvoking Calculator Service at {0}\n", serviceAddress);
// Create a client
CalculatorClient client = new CalculatorClient();
client.Endpoint.Address = serviceAddress;
client.Add(10,3);
}
}
发现和消息级别安全
使用消息级别安全性时,需要在服务发现终结点上指定一个 EndpointIdentity,并在客户端发现终结点上指定一个匹配的 EndpointIdentity。 有关消息级别安全性的详细信息,请参阅 消息安全性。
发现和 Web 托管服务
为了使 WCF 服务可被发现,WCF 服务必须在运行中。 在 IIS/WAS 下托管的 WCF 服务在收到为服务绑定的消息之前不会运行,因此默认情况下无法发现它们。 有两个选项可用于使 Web-Hosted 服务可发现:
使用 Windows Server AppFabric 自动启动功能
使用发现代理代表服务进行通信
Windows Server AppFabric 具有自动启动功能,允许在收到任何消息之前启动服务。 通过自动启动设置,可以将 IIS/WAS 托管服务配置为可被发现。 有关自动启动功能的详细信息,请参阅 Windows Server AppFabric 自动启动功能。 必须随打开自动启动功能一起,针对发现配置服务。 有关详细信息,请参阅 如何:以编程方式为 WCF 服务和客户端添加可发现性在配置文件中配置发现功能。
发现代理可用于在服务未运行时代表 WCF 服务进行通信。 代理可以为进行探测而侦听,或解析消息及对客户端的响应。 然后,客户端可以直接将消息发送到服务。 当客户端向服务发送消息时,它将实例化以响应消息。 有关实现发现代理的详细信息,请参阅 “实现发现代理”。
注释
若要使 WCF 发现正常工作,所有 NIC(网络接口控制器)应只有 1 个 IP 地址。