[WSE]Web Service与Windows Service通过WSE2.0建立订阅/发布关系[更新版]
[WSE]Web Service与Windows Service通过WSE2.0建立订阅/发布关系
编写者:郑昀@UltraPower
编写日期:
修改日期:2005-05
目的:
我们建立这种交互关系的目的是,在Web Service和Windows Service(或者其他Windows应用)之间建立起一种稳固的可扩展的不受地域限制的交互关系。
优点:
这种交互关系的优点是:
完全异步:
Web service和Windows service/windows form都可以实现交互的异步性,也就说,二者的交互完全是通过delegate和WSE2.0消息机制实现的,彼此依赖性降低,web service可以像一个二传手,不断地将用户发起的请求路由到后台服务,web service不用和windows service之间保持长连接;windows service处理请求完毕,就发送soap消息给web service的http endpoint。
你甚至可以在使用wse2.0的MSMQ transport来替代http/tcp channel作为底层通信。
可扩展:
这种SOAP消息很容易定制和扩展新的包头定义。
可分布:
由于webservice的http endpoint地址可以随着web service发消息给后台服务,所以webservice部署在哪里无关紧要,都可以和windows service保持交互。Webservice是通过wse2.0中的WS_Addressing机制把消息路由给Windows service的,所以二者可以部署到不同的机器上,只需要改变webservice的配置文件即可,后台服务能够根据传过来的SOAP包中的ReplyTo字段获知应该如何给哪里的http终结点回传消息。
为什么Webservice要采用HTTP EndPoint来接收SOAP消息?
由于Web Service的执行身份受限,所以我们无法直接让Web Service申请作为一个SoapReceiver,而是通过下面的web.config定义来制定本虚拟目录的.ashx终结点,从而通过WS_Addressing和WS_Messaging机制来完成Web Service与Windows Service之间的订阅/发布机制。
HttpHandlers映射原理介绍:
在 ASP.NET 中,可以通过IHttpHandler,将 SoapReceiver 与 HTTP 信道进行集成。如果查看一下 SoapReceiver 的定义,您会注意到它实现了 IHttpHandler:
public abstract class SoapReceiver : SoapPort, IHttpHandler
{
。。。
}
由于这一点,任何 SoapReceiver 或 SendService 类现在都能够在 ASP.NET 中配置为 HTTP 处理程序。通过在 web.config 文件的 httpHandlers 部分添加一个新的映射,用户能够配置 http 处理程序。web.config 项将把 verb/path 组合映射到 SoapReceiver 类型:
首先,我们通过在web service的配置文件web.config中,加入如下示范片断:
<configuration>
<configSections>
<section name="microsoft.web.services"
type="Microsoft.Web.Services.Configuration.WebServicesConfiguration,
Microsoft.Web.Services, Version=
PublicKeyToken=31bf3856ad364e35" />
</configSections>
<system.web>
<httpHandlers>
<!-- 为了让我们的WebService能够接收到来自于后台侦听服务的SOAP消息
我们让WebService继承自SoapReceiver,并实现了void Receive(SoapEnvelope envelope),
这样exe通过向
new Uri("http://"+ System.Net.Dns.GetHostName() + "/MyService/GetReceiver.ashx")
发送SOAP消息,那么SoapReceiver的Receive回调函数将被调用
-->
<add type="MyWebService.MyInterface" path="GetReceiver.ashx" verb="*" />
</httpHandlers>
把这组代码放到适当的位置,将针对每条输入此虚拟目录并指向 GetReceiver.ashx 的消息而调用 MyService。现在我们不必担心通过调用 SoapReceiver.Add 来配置 SoapReceiver/SoapService,因为 ASP.NET 本质上代替您完成了此任务。
如果Windows Service通过SoapSender,就可以把消息发送到我们定义的 HTTP 终结点 (http://localhost/MyService/GetReceiver.ashx),它与使用 TCP 信道接收SOAP消息的工作方式相同,只是现在它通过 HTTP 进行通讯。
静态的哈希表和HTTP终结点
我们在webservice中加上几个静态的哈希表,存储了客户端的回调函数以及其他信息,还有对应的查询请求等,相当于保存了会话状态,从而能够在这些哈希表的帮助下完成与Windows服务之间的异步交互,以及与客户端调用者之间的异步交互。
Web Service异步实现模式
实现异步 XML Web services 方法应遵循 .NET Framework 异步设计模式。
第一步,将我们的异步 XML Web services 方法GetReceive拆分成两个方法。
每个方法都有相同的基名称,即一个以 Begin 开始,另一个以 End 开始;
第二步,实现异步Web Service的BeginGetReceive方法:
BeginGetReceive 方法的参数列表包含方法功能的所有 in 和 by reference 参数,以及追加到结尾的两个参数。
By reference 参数作为 in 参数列出。
倒数第二个参数必须为 AsyncCallback。AsyncCallback 参数允许客户端提供委托,在方法完成时将调用该委托。
当一个异步 XML Web services 方法调用另一个异步方法时,此参数可被传递到该方法的倒数第二个参数。
最后一个参数是 Object。Object 参数允许调用方为方法提供状态信息。当一个异步 XML Web services 方法调用另一个异步方法时,此参数将被传递到该方法的最后一个参数。
返回值必须为 IAsyncResult 类型。
第三步,实现异步Web Service的EndGetReceive方法:
EndGetReceive 方法的参数列表包含 IAsyncResult 参数,此参数后面带有特定于该方法功能的任意 out 和 by reference 参数。
返回值类型与异步 XML Web services 方法的返回值类型相同。
By reference 参数作为 out 参数列出。
我们与一般的异步Web Service不同之处在于,BeginGetReceive 方法中又调用的
IAsyncResult arr = prcDelegate.BeginInvoke(null, callback, asyncState);
方法是类内部定义的“ProcessReceive”函数,它实际上还是一个异步处理消息过程,它只是把要处理的查询请求用SoapSender发送给后台服务,之后就返回,不再等待。
第四步,等到后台服务把结果发送给本Web Service的HTTP终结点,我们再把结果都存储在哈希表中,然后回调调用者。
第五步,调用者收到回调后,就调用我们Web Service的EndGetReceive方法,从而从哈希表中拿到结果集。
上面描述的流程如下一节的图片所示。
Web Service—Windows Service/Form的订阅/发布关系
由于Web Service运行的身份是ASP.NET用户,而SoapReceiver.Add方法对执行权限要求较高,所以我们采用HTTP终结点的方式,再加上几个静态的哈希表,从而完成了与后台侦听服务之间的异步交互,以及与客户端调用者之间的异步交互。
图1 交互流程步骤说明
下面我们具体讲解一下:
首先,调用者请求Web Serviced的BeginGetReceive方法,这个方法再异步调用ProcessReceive方法它负责组装出一个SoapEnvelope,并向Uri为
soap.tcp://hostname:port/yourreceivername
的目标EndPoint,用SoapSender.Send发送这个SoapEnvelope。一方面用于通知订阅关系,另一方面传递了各项参数,以及预先生成的GUID。之后就将处理权返回调用者。
这里包含了图中的1,2,3三步:
其次,正在监听的侦听服务收到了消息,进行处理:
添加这个订阅者的各种信息到静态哈希表;
利用I/O完成端口异步执行各种任务;
把结果集或者错误信息通过Web Service HTTP终结点通知订阅者。
这里包含了图中的4,5,6三步:
最后,订阅者Web Service收到通知后,通知客户端调用者的回调函数来取回结果集,从而将结果集或者错误原因返回给客户端。
编写者:郑昀@UltraPower