第十四章 检测服务和路由消息(第一部分)

前言

如果客户端程序向WCF服务发送一条请求消息,那么客户端通过端点发送该请求。如果你回想一下,端点由三部分组成:地址,绑定和合约。地址指明消息发送的目的地;绑定指明传输、格式、以及于与服务进行通讯所使用的协议;合约决定客户端可以发现的消息以及客户端期望的响应消息。多个服务可以实现同一个服务合约,或一个服务也有可能更改地址。如果客户端将服务特定的地址硬编码在客户端的配置文件中,那么如果服务发生变动、或者临时不可访问、或者服务由于太忙而不能处理请求,那么客户端将不再能继续与该服务通讯。WCF提供了检测服务和路由消息来解决上述问题。
在本章的第一部分,你将看到如何在一个通过Ad Hoc模式和服务声明方式在WCF解决方案中实现检测服务。

实现检测服务

WCF检测服务实现了OASIS WS-Discovery 协议。该特性允许客户端程序基于查询条件(比如服务实现的合约)动态地查找一个服务。服务的位置可能会改变,但只要服务是可检测的,那么客户端程序就可以发现服务并连接至该服务。
在WS-Discovery协议中最简单的模式是:如果一个客户端程序希望连接至一个服务,那么该客户端在网络上发送包含特定条件(如服务协定类型、关键字和范围)的 Probe 请求。如果服务支持可检测性,那么该服务的端点使用由WS-Discovery规范定义的既定地址,并在该地址侦听Probe请求。服务接收到客户端发送的Probe 请求,然后确定它们是否匹配该条件。如果某一服务匹配该条件,那么该服务做出响应,向客户端响应一条包含与该服务联系所需信息的 ProbeMatch 消息。这种模式就是ad hoc模式(MSDN翻译为临时模式)
使用WCF,在服务端你只需要激活检测行为并添加一个预先配置的可检测端点至该服务,那么该服务就可以支持检测性。预先配置的端点是udpDiscoveryEndpoint,该端点是WCF实现的多个标准端点之一。标准端点实现一组预先定义好的功能并包含一些内建的配置信息;你需要做的仅仅是把服务所使用端点的名字指向标准端点。udpDiscoveryEndpoint端点使用固定的合约,固定的HTTP绑定,以及一个由WS-Discovery规范指定的默认地址。
让我们来看一下使用Ad hoc模式实现发现服务所需的一些类以及它们之间的关系图:
我们来分析一下的UdpDiscoveryEndpoint构造函数的执行过程:
1. new UdpDiscoveryEndpoint(),访问UdpDiscoveryEndpoint默认的不带参数的构造函数。
2. this.UdpDiscoveryEndpoint(UdpDiscoveryEndpoint.DefaultIPv4MulticastAddress) ,访问UdpDiscoveryEndpoint的参数为Url的构造函数,参数的值为new Uri("soap.udp://239.255.255.250:3702")。
3. this.UpdDiscovery(DiscoveryVersion.DefaultDiscoveryVersion, multicastAddress),访问UdpDiscoveryEndpoint的参数为DiscoveryVersion和Uri的构造函数,参数的值分别为WSDiscovery11和new Uri("soap.udp://239.255.255.250:3702")。
DiscoveryVersion.DefaultDiscoveryVerion访问DiscoveryVersion类的静态属性DefaultDiscoveryVersion,该属性通过方法FromName("WSDiscovery11")返回一个DiscoveryVersion对象。在FromName方法中,调用了DiscoveryVersion的静态属性WSDiscovery11;该属性通过DiscoveryVersion的构造函数new DiscoveryVersion("WSDiscovery11", "http://docs.oasis-open.org/ws-dd/ns/discovery/2009/01", new DiscoveryVersion11Implementation())返回DiscoveryVersion对象。请注意最后一个参数new DiscoveryVersion11Implementation()。该对象包含一个方法GetDiscoveryContract,它将根据ServiceDiscoveryMode返回一个对于的ContractDescription对象。
4. base(discoveryVersion, ServiceDiscoveryModel.Adhoc),访问UdpDiscoveryEndpoint的基类DiscoveryEndpoint的构造函数。
5. 该函数为访问自身的另外一个构造函数DiscoveryEndpoint(DiscoveryVersion discoveryVersion, ServiceDiscoveryMode discoveryMode, Binding binding, EndpointAddress endpointAddress);前面的两个参数由子类传入,另外两个参数的值为null。该函数将访其父类Endpoint的构造函数。但是先需要通过自身的GetDiscoveryContract方法获取ContractDescription实例:
5.1 GetDiscoveryContract方法的代码如下图所示:
请注意discovery的类包含一个接口IDiscoveryVersionImplementtation;其属性DefaultDiscoveryVersion为该接口提供了一个具体的实现,该实现就是DiscoveryVersion11Implementation类。上诉方法通过访问该实现类的GetDiscoveryContract获取服务合约。
6. 现在,访问Endpoint类的的构造函数ServiceEndpoint(ContractDescription contract),该构造函数的参数由DiscoveryEndpoint的静态方法GetDiscoveryContract方法传入
7. 执行完ServiceEndpoint类的的ServiceEndpoint(ContractDescription contract)后;回到DiscoveryEndpoint类的DiscoveryEndpoint(DiscoveryVersion discoveryVersion, ServiceDiscoveryMode discoveryMode, Binding binding, EndpointAddress endpointAddress)方法。该方法为服务添加可检测特性行为;最后设置端点的地址和绑定。
8. 然后,回到UdpDiscoveryEndpoint类的UpdDiscovery(DiscoveryVersion.DefaultDiscoveryVersion, multicastAddress)方法。该方法调用自身的Initializer方法。
9. 最后,我们来看UdpDiscoveryEndpoint的Initializer方法。该方法指定编码模式,消息版本,并添加自定义的绑定,最后为绑定添加一些行为。其方法的代码如下图所示:
 

配置WCF服务支持Ad Hoc模式的可检测服务

在下面的练习中,你将配置ProductsService服务支持Ad Hoc模式的可检测服务;并为客户端程序添加代码以发现ProductsService服务然后与其建立连接。
练习:配置ProductsService服务支持Ad Hoc模式的可检测服务
1. 使用管理员身份启动Visual Studio,然后打开*\WCF\Step.by.Step\Solutions\Chapter14\ProductsService文件夹下的ProductsService.sln解决方案。
该解决方案包含ProductsService服务,它寄宿在ASP.NET开发Web服务器上,该服务在8090端口侦听请求。该方案还包含一个客户端程序,其使用端点WS2007HttpBinding_IProductsService连接至服务,并调用该服务的各种操作。
2. 在非调适模式下运行解决方案。ASP.NET开发Web服务器将启动,并在8090端口侦听请求。在客户端控制台窗口中,确认显示了http://localhost:8090/ProductService/ProductsService.svc。然后按ENTER键。客户端程序将执行整套任务;显示AdventureWorks数据库中所有产品的产品编码,显示产品WB-H098的产品信息和库存信息,最后并为当前库存增加100.
当客户端程序完成后在客户端控制台窗口中按ENTER键以关闭客户端,然后回到Visual Studio。
目前,客户端程序没有使用检测服务的方式查找ProductsService服务,而且服务本身也不支持可检测性。在下面的步骤中,你将首先配置服务为可检测服务,然后将注意力转移到客户端程序。
3. 使用WCF服务配置管理器打开C\...\ProductsService项目下的web.config文件。
4. 在配置面板中,展开高级文件夹,然后展开服务行为文件夹,最后点击未命名行为。
5. 在行为面板,点击添加按钮,在添加服务元素扩展对话框中,选择serviceDiscovery行为元素,然后点击添加按钮。
serviceDiscovery行为元素使可检测服务对外暴露所有端点。但是,你仍然需要添加一个可检测的端点以侦听来自客户端的Probe请求。通过添加udpDiscoveryEndpoint标准端点可以完成对Probe请求的侦听任务。
6. 在配置面板,展开服务文件夹,然后展开ProductsService.ProductsServiceImpl服务,在端点文件夹上点击右键,然后选择创建新的服务端点。
7. 在服务端点面板,选择端点Kind属性的值为udpDiscoveryEndpoint。其他的属性均使用其默认值。
8. 在配置面板,点击标准端点文件夹。在标准端点面板,点击创建新的标准端点配置。在创建标准端点对话框中,点击udpDiscoveryEndpoint端点类型,然后点击确认按钮。
9. 在右边面板,更改新创建的标准端点名字为AdHocDiscoveryEndpoint。在常见区域中,设置DiscoveryMode属性为Adhoc,DiscoveryVersion属性为WSDiscovery11。
实际上,有两个版本的常规WS-Discovery规范;较早的版本诞生于2005年4月,最新的版本为1.1。udpDiscoveryEndpoint标准端点支持两个规范。但是默认情况下使用更新的1.1版本。如果你希望启动对老版本的支持,更改DiscoveryVersion属性为WSDiscoveryApril2005。
MaxResponseDelay属性的目的是阻止服务试图在同一时刻发送大量ProbeMatch消息时引起网络"风暴"。如果该属性设置一个不为零的值,那么服务在发送每条ProbeMatch响应之前都会等待一段时间。
请注意,你可以修改端点侦听的多播地址(默认情况值来自WS-Discovery规范设定的值)。但是,你不应该修改它除非在你的客户端程序中Probe请求的地址也做了同样的修改。
10. 在配置面板,点击服务文件夹下的端点文件夹,然后选择最后一个未命名端点,这将选中updDiscoveryEndpoint端点。设置该端点的EndpointConfiguration属性为AdHocDiscoveryEndpoint。
尽管你没有更改该端点的默认属性,上述配置将允许你方便地更改端点的值,特别是当你需要更改端点的值的时候。
11. 保存配置文件,然后退出WCF服务配置编辑器。
 
在进行配置客户端联系前,我们先开一下配置客户端见车Ad hoc模式的服务所需要使用的类
而最重要的对象是DiscoveryClient,其初始化的过程大致如下:该过程创建一个innerClient,其类型为IDiscoveryClient接口,该接口提供了ProbeOperation(FindCriteria criteria)方法以处理客户端的Probe请求;该方法的具体实现是在System.ServiceModel.Discovery.Version11.DiscoveryInnerCLientAdhoc11中实现。而IDiscoveryInnerClientResponse提供了ProbeMatchOperation(*)方法处理匹配的Probe;该方法在DiscoveryClient提供了具体的实现。
 
在下面的练习中,你将修改客户端程序以启用检测服务。客户端程序将创建一个DiscoveryClient对象以发送一条Probe消息以识别实现ProductService服务的合约。ProductService服务的udpDiscoveryEndpoint端点将接收到该请求,然后检测服务是否实现了请求的合约,并返回一条包含服务端点信息的ProbeMatch消息。客户端程序从ProbeMatch消息中获取服务的地址,然后使用该地址连接至ProductsService服务。
练习:修改客户端程序以实现检测ProductService服务
1. 在解决方案浏览器中,引用System.ServiceModel.Discovery组件至PorductsClient项目。该组件包含了客户端程序执行检测服务所需的类型。
2. 开发ProductsClient项目下的Programm.cs文件,在文件头部添加声明using System.ServiceModel.Discovery;
3. 完成Main方法如下:
第一行代码创建一个DiscoveryClinet实例,该实例打开一个本地的UdpDiscoveryEndpoint实例端点以发送和接受检测消息。DiscoveryClient类位于System.ServiceModel.Discovery命名空间下。它提供发布Probe请求并等待ProbeMatch响应。
第二回声明创建一个System.ServiceModel.Discovery.FindCriteria对象。该对象的信息作为Probe请求将发送。其构造函数指定了在Probe请求中发送的服务合约。
第三行代码中,DiscoveryClient的Find方法使用本地UdpDiscoveryEndpoint端点广播一条Proble消息,该方法的参数执行了查找的服务。Find方法返回一个FindResponse对象,其EndpointAddress集合包含了每个响应服务的地址。
Find方法的运行可能会耗费一段时间。在WS-Discovery协议中,当客户端发送一条Probe消息,零个或多个服务将响应该消息。如果没有指定的时间内接收到任何ProbeMatch消息,客户端可以选择超时。同样地,可能没有任何一个响应的服务是客户端可接受服务。因此,客户端可能会继续等待一段时间,然后检查接收到的所有ProbeMatch响应以确定哪一个服务最适合客户端的需求(比如,客户端可能检查每个响应的URLs然后决定连接到一个地理上与客户端最接近的服务)。
DiscoveryClient类的Find方法隐藏了其实现的复杂性。当创建FindCriteria对象,你可以设置该对象的持续Duration和MaxResults属性。正如它们的名字所指示的那样,Duration属性设定Find方法等待结果的时间是多长(默认值是20秒),MaxResults属性指定结果所能接收的最大值(默认值为Int32.MaxInt)。Find方法的等待要么发生超时要么结果超出最大数。然后,Find方法然后从各个ProbeMatch消息中收集数据然后将这些信息存贮在FindResponse对象的Endpoints集合中,最后返回FindResponse对象。如果你希望客户端程序不因为执行检测服务而被阻塞,你可以调用FindAysnc方法;该方法立即返回,但每次客户端接收到一条响应消息都会触发DIscoveryClient对象的FindProgressChanged事件。当DiscoveryClient对象确定话费了足够的时间等待结果后会触发FindCompleted事件。
当DiscoveryClient对象结束检测服务,调用Close方法关闭UdpDiscoveryEndpoint端点。
创建一个新的端点地址实例,然后将FindResponse对象的属性Endpoints集合中第一个匹配服务的地址赋值给该实例。然后,创建一个新的ProductsServcieClient代理对象实例,并将从端点实例的值赋值给代理对象实例。后面的代码与之前的练习的代码一样。
4. 重新生成解决方案。
 
在你开始测试客户端程序之前,你必须部署服务至一个支持检测的宿主环境。不幸的是,ASP.NET开发Web服务器不吃之该特性,因此你必须将服务发布在IIS上。该练习还可以证明:即使你移动了服务,而且你并未做客户端做任何修改,客户端还是可以连接至服务。
练习:部署ProductsService至IIS并测试客户端程序
1. 在解决方案浏览器窗口,在C:\...\ProductsServcie\projec项目上点击右键,然后选择发布Web站点
2. 在发布站点对话框窗口中,在目标位置框内输入http://localhost/DiscoverableProductsService,然后点击确认按钮。等待"发布成功"出现在Visual Studi的状态栏中。
3. 发开IIS,并确认DiscoverableProductsService站点已经建立。
4. 在该站点上点击右键,选择管理程序,然后点击高级设置。在高级设置对话框中,设置应用程序缓冲池为ASP.NET V4.0;然后点击确认按钮
5. 在中间面板点击查看内容标签。如果ProductsService已经成功部署,那么你应看看如下入所示的文件:
6. 在ProductsService.svc上点击右键,然后选择"在浏览器中浏览"。确认IE自动启动并显示ProductsServiceImpl服务页面。这步操作确认了你的服务已正确部署。
7. 返回到Visual Studio,在非调适模式下运行解决方案。大约20秒(传递至DiscoveryClient实例的FindCriteria对象的属性Duration的值为20秒)之后,你将看到客户端程序已经发现了ProductsService服务的地址,并显示在客户端控制台窗口中,而且该地址与上一个练习的服务的地址是不一样的。
8. 按下ENTER键,客户端程序将连接至上述地址,然后得到和上一个练习一样的结果。
9. 当客户端程序结束,按下ENTER键以关闭客户端程序窗口,然后回到Visual Studio。

处理服务声明

检测服务无疑是一项非常强大技术,但是使用Ad Hoc模式查找服务有点费时而且可能使客户端程序不能成功地发现服务;基本上,每次当你想连接至一个服务时,你都必须等待直到服务端点被发现。你可以调整用于检测服务的FindCriteria对象的Duration属性的值,但是如果你把该值修改的太小,那么你将会因为在既定的时间内没有接收到Probe请求的响应而面临服务不能被发现的风险。Ad Hoc模式对网络也是不友好的,特别是当你的组织拥有大量客户端的情况下;每次当客户端连接至一个服务,它必须在你的网络中广播一条Probe请求。为了应付这些问题,一种可行的解决方法是处理服务声明。
一个支持可检测的服务在启动时向已知的地址发送一条多播消息而"声明"自己的存在。客户端程序能侦听这些多播消息并在一个本地集合也称之为缓存(服务的地址和服务的元数据一起通过服务声明传输至客户端)中保存服务的详细信息。当客户端希望向服务发送消息时,客户端从本地缓存中查询服务的地址,然后使用该地址连接至服务并调用服务的操作。
相似地,当一个服务关闭时,该服务同样向网络中广播一条关闭消息。客户端程序能够捕获这些消息,并使用这些信息将服务的详细信息从本地的缓存中移除。
在这种情形下,检测服务的功能就从客户端转移到服务端。客户端不再向服务发送Probe消息,相应地,服务也不需要实现用于识别服务的端点。但是,你需要修改服务使之在启动和关闭时发送声明消息。WCF为该特性提供了便利;所有你需要做的仅仅是添加一个udpAnnouncementEndpoint标准端点到servcieDiscovery行为元素。WCF运行时将为你做其余的一切。
客户端程序可以使用AnnouncementServcie对象侦听声明。该类位于System.ServiceModel.Discovery命名空间下。在客户端程序中,你创建该类的一个实例,然后为它提供一个侦听的端点。当一条新的服务声明到达,将触发AnnouncementServcie对象的OnlineAnnouncementReceived事件,服务的详细信息传递至该事件。同样地,当服务关闭时OfflineAnnouncement事件也将发生。
在进行练习之前,我们来分析一下与服务声明有关的类及其执行过程。下图非常明显的显示了UdpAnnouncementEndpoint,AnnouncementEndpoint与ServiceEndpoint之间的关系。
我们再来看AnnounceEndpoint构造函数的执行过程:
1. AnnouncementEndpoint():this(DiscoveryVersion.DefaultDiscoveryVersion). 可见AnnouncementEndpoint方法调用了自身的另外一个接收参数DiscoveryVersion的构造器方法。而该方法为其子类UdpAnnouncementEndpoint所拥有。注意DefaultDiscoveryVersion的值为WSDiscovery11.
2. 而上面的方法在UdpAnnouncementEndpoint中是这样的定义的:UdpAnnouncementEndpoint(DiscoveryVersion discoveryVersion) : this(discoveryVersion, UdpAnnouncementEndpoint.DefaultIPv4MulticastAddress);可见其访问了另外一个构造方法。
3. 上述方法访问下面的方法
首先,因为该方法调用了基类的base(discoveryVersion)方法,因此我们先看基类的该方法。在基类中该方法是这样定义的:AnnouncementEndpoint(DiscoveryVersion discoveryVersion) : this(discoveryVersion, null, null)。它访问了另外一个构造方法:AnnouncementEndpoint(DiscoveryVersion discoveryVersion, Binding binding, EndpointAddress address) : base(AnnouncementEndpoint.GetAnnouncementContract(discoveryVersion))。
4. 因为DisCoveryVersion的值为WSDiscovery11,让我们继续查看DiscoveryVersion类,该类有一个共有名为WSDicovery11的属性,其类型为DiscoveryVersion。该属性是这样定义的:DiscoveryVersion.wsDiscovery11 = new DiscoveryVersion("WSDiscovery11", "http://docs.oasis-open.org/ws-dd/ns/discovery/2009/01", new DiscoveryVersion11Implementation());我们可以看到由DiscoveryVersion11Implementation类真正实现WSDiscovery11,它包含了上面所需的方法GetAnnounceContract方法
5. 获取完服务合约之后,继续访问ServiceEndpoint的构造方法ServiceEndpoint(ContractDescription contract)。
6. 随后,回到AnnouncementEndpoint的构造方法AnnouncementEndpoint(DiscoveryVersion discoveryVersion, Binding binding, EndpointAddress address)。该方法为服务添加可检测版本;并设置端点的地址和绑定。
7. 最后,我们再回到UdpAnnouncementEndpoint的Initialize方法。该方法指定编码模式,消息版本,并添加自定义的绑定,最后为绑定添加一些行为。其方法的内容如下图所示:
 
 
在接下来的一组练习中,你将修改ProductsService服务发送声明消息。然后你将更新客户端程序以捕获这些消息并在服务启动或者关闭时保存该服务的详细信息。
练习:配置ProductsService服务以发送声明
1. 在Visual Studio中,使用WCF服务配置编辑器打开C:\...\ProductsService项目下的web.config文件
2. 在配置面板,展开服务文件夹下的Products.ProductServiceImpl服务,展开端点文件夹,然后点击第二个未命名端点。确认该端点是udpDiscovery端点,在该端点上点击右键,然后选择删除端点以移除该端点。在显示"This item will be deleted"消息对话框中点击确认按钮。
服务现在需要发送声明而不是发送对Probe请求的响应消息,因此不再需要该端点。但是,服务可以同时实现这两种机制(发送声明消息和发送Probe的响应消息),因次你应该根据实际情况选择保留哪个端点。
3. 在配置面板,展开高级文件夹,展开服务行为文件夹,展开未命名行为,然后展开serviceDiscovery行为元素。
serviceDiscovery行为元素包含一个声明端点。你可以为服务添加该端点以发送声明消息。
4. 在声明端点上点击右键,然后点击创建新的客户端的端点。在端点面板中,设置Kind属性为udpAnnouncementEndpoint。
udpAnnouncementEndpoint是另外一个标准端点,它被事先配置并使用WS-Discovery规范指定的协议发送声明消息。如果你需要更改声明地址或者声明端点的配置,你需要为udpAnnouncementEndpoint类型创建一个标准的端点配置,然后通过该配置做相应的更改。
5. 保存配置文件并关闭WCF服务配置编辑器。
 
在修改客户端之前,我们浏览一下客户端捕获声明消息所需的类。
实际上,捕获服务声明时,在客户端建立了一个AnnouncementService服务,该服务负责与ProductsService服务通信,并获取ProductsService服务发送的Online和Offline消息,并将ProductsService服务的详细信息保存在本地的缓冲中。然后ProductsClient才访问本地缓存,并从缓存中或缺ProductsServcie服务的地址,然后与ProductsService服务进行通讯。整个流程的详细过程我不在赘述。
 
练习:修改客户端程序以捕获声明消息
1. 打开ProductsClient项目下的Program.cs文件
2. 在Program类中,添加下面的using语句
Using System.Collections.Concurrent
3. 在Programm类中,在main方法前添加如下的ConcurrencyDictionary集合
定义在System.Collection.Concurrent命名空间下的ConcurrentDictionary类是一个线程安全的字典集合。当客户端程序接收到声明消息,将会把发送声明服务的详细信息存储在该集合中。
4. 在main方法中,删除注释"Test the operations in the service"之前的所有代码和注释。
5. 在main方法中的开始处,添加下面的声明:
AnnouncementService announceService = new AnnouncementService();
该语句创建一个AnnounceService对象以侦听声明消息
6. 添加下面的代码到Main方法中
上述代码订阅OnlineAnnouncementReceived事件,该事件在服务启动并发送声明消息时被触发。该事件的eventArgs参数是AnnouncementEventArgs类型的一个实例。该类型最应关注的属性是EndpointDiscoveryMetadata,它包含了服务的详细信息,包括声明服务的地址和合约。事件处理器添加服务元数据到service字典集合中,并用服务的地址作为字典的key(当另外一个同样服务使用字典中已经存在的地址,那么事件处理器不能将该服务添加至字典,并将抛出异常。)。最后,事件处理器迭代服务实现的合约并将服务合约和服务的地址显示在客户端控制台窗口中。这样你可以清楚地看到当服务声明发生;但在产品环境中你不要这么做。
7. 添加下面的代码之Main方法中
上述代码订阅OfflineAnnouncementReceived事件,该事件在服务指明其正在关闭时发生。和第六步一样,AnnouncementEventArgs参数包含了服务的详细信息。事件处理器从service集合中移除服务元数据,捕获并报告发生的异常。
8. 在OfflineAnnouncementReceived事件后,添加如下代码:
上述代码为AnnouncementService对象创建一个宿主,该宿主程序用于侦听UdpAnnouncementEndpoint标准端点对上的声明。该端点使用默认配置的并且与服务广播放松声明的相同地址上进行侦听。当宿主启动后,客户端程序等待用户按ENTER键以继续。
9. 添加如下代码至Main方法
这些代码与之前向服务发送Probe消息类似,但上述代码从services集合中获取服务的详细信息,而为采用WS-Discovery协议。FindCriteria类的IsMatch方法比较服务的元数据和一个指定的服务合约然后返回匹配的结果。在上述代码中,LINQ查询在services集合搜索实现了IProductsService服务合约的服务最后返回第一个匹配服务的地址。
10. 添加下面的代码之main方法
上述代码创建ProductsServiceClient代理的实例并把从services集合中搜索的服务的地址复制给ProductsServiceClient实例。
客户端程序中剩下的代码与上一个练习时一样的。
11. 重新生成解决方案。
 
最后一步是部署更新后的服务至IIS。部署完之后,你就可以运行客户端程序验证它是否可以正确地接收到服务声明。
 
练习:测试ProductsService和客户端程序
1. 在解决方案浏览器窗口,在C:\...\ProductsService项目上点击右键,然后点击发布Web站点。发布更新后的Web站点至http://localhost/DiscoverableProductsService。
2. 在非调适模式下运行解决方案。在客户端程序控制台窗口中,先不要按ENTER键因为ProductsService服务还没有发送任何声明消息,因为客户端程序还不能发现ProductsService服务。
3. 返回IIS。在连接面板,点击DiscoverableProductsService站点,然后点击中间面板的查看内容标签,然后在ProductsService.svc文件上点击右键,选择在浏览器中查看。该行为将会启动ProductsService服务,导致服务发送声明消息。关闭IE浏览器然是不关闭IIS。
4. 返回到客户端控制台窗口。你会发现它现在显示了一条消息,该消息指明客户端已经接收到一条来自实现IProductsService接口服务的声明消息:
5. 在客户端程序中,按下ENTER键。客户端程序将像之前的练习一样的运行。当客户端程序结束,不要按下ENTER键关闭客户端程序。
6. 返回IIS中。在连接面板,点击应用程序池,然后选择DiscoverableProductsService站点所使用的应用程序池,然后关闭该应用程序池。
7. 返回到客户端控制台窗口,你将看到离线声明事件被触发。
8. 在客户端控制台窗口中按ENTER键盘关闭客户端程序,并回到Visual Studio。
 
参考
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux系统中有一个非常常用的路由检测工具,名为traceroute。它可以帮助我们检测信息从本地计算机到互联网另一端的主机所走的路径。traceroute通过发送小的数据包到目的设备直到其返回,来测量其需要多长时间。一条路径上的每个设备traceroute要测3次。输出结果中包括每次测试的时间(ms)和设备的名称(如有的话)及其IP地址。 使用traceroute命令非常简单,只需要在终端中输入traceroute加上目标主机的IP地址或域名即可。例如,我们可以使用以下命令来检测到百度服务器的路由路径: ``` traceroute www.baidu.com ``` 执行该命令后,我们将会看到类似以下的输出结果: ``` traceroute to www.a.shifen.com (14.215.177.38), 30 hops max, 60 byte packets 1 _gateway (192.168.1.1) 1.013 ms 1.012 ms 1.010 ms 2 10.10.10.1 (10.10.10.1) 1.009 ms 1.008 ms 1.006 ms 3 61.148.158.1 (61.148.158.1) 5.005 ms 5.003 ms 5.001 ms 4 61.148.158.9 (61.148.158.9) 5.000 ms 4.998 ms 4.996 ms 5 61.148.158.10 (61.148.158.10) 4.994 ms 4.992 ms 4.990 ms 6 202.97.33.221 (202.97.33.221) 5.986 ms 5.984 ms 5.982 ms 7 202.97.33.222 (202.97.33.222) 5.980 ms 5.978 ms 5.976 ms 8 202.97.58.238 (202.97.58.238) 5.972 ms 5.970 ms 5.968 ms 9 202.97.58.237 (202.97.58.237) 5.966 ms 5.964 ms 5.962 ms 10 202.97.94.54 (202.97.94.54) 5.956 ms 5.954 ms 5.952 ms 11 202.97.94.53 (202.97.94.53) 5.946 ms 5.944 ms 5.942 ms 12 202.97.94.50 (202.97.94.50) 5.936 ms 5.934 ms 5.932 ms 13 202.97.94.49 (202.97.94.49) 5.926 ms 5.924 ms 5.922 ms 14 202.97.94.46 (202.97.94.46) 5.912 ms 5.910 ms 5.908 ms 15 202.97.94.45 (202.97.94.45) 5.902 ms 5.900 ms 5.898 ms 16 202.97.94.42 (202.97.94.42) 5.888 ms 5.886 ms 5.884 ms 17 202.97.94.41 (202.97.94.41) 5.874 ms 5.872 ms 5.870 ms 18 202.97.94.38 (202.97.94.38) 5.860 ms 5.858 ms 5.856 ms 19 202.97.94.37 (202.97.94.37) 5.846 ms 5.844 ms 5.842 ms 20 202.97.94.34 (202.97.94.34) 5.828 ms 5.826 ms 5.824 ms 21 202.97.94.33 (202.97.94.33) 5.810 ms 5.808 ms 5.806 ms 22 202.97.94.30 (202.97.94.30) 5.792 ms 5.790 ms 5.788 ms 23 202.97.94.29 (202.97.94.29) 5.774 ms 5.772 ms 5.770 ms 24 202.97.94.26 (202.97.94.26) 5.752 ms 5.750 ms 5.748 ms 25 202.97.94.25 (202.97.94.25) 5.732 ms 5.730 ms 5.728 ms 26 202.97.94.22 (202.97.94.22) 5.710 ms 5.708 ms 5.706 ms 27 202.97.94.21 (202.97.94.21) 5.688 ms 5.686 ms 5.684 ms 28 202.97.94.18 (202.97.94.18) 5.662 ms 5.660 ms 5.658 ms 29 202.97.94.17 (202.97.94.17) 5.636 ms 5.634 ms 5.632 ms 30 * * * ``` 输出结果中,第一行显示了目标主机的IP地址和最大跳数,后面的每一行则显示了每个路由器的IP地址和名称,以及到达该路由器所需要的时间。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值