用WSE 2.0在XML Web Services里面实现Callback

本文介绍如何使用WSE2.0在XML Web Services中实现客户端的实时回调功能,通过示例代码展示了服务器端与客户端的具体实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

XML Web Services原先的一个问题是不能实现真正的Callback。比如用ASP.NET实现的时候,每一个[WebMethod]都是一个远程方法调用,但只支持方法效用而不支持事件(Event),不能像本地调用可以传一个Delegate来实现Callback(Callback、函数指针、Listener模式、中断等其实都是一回事,都是一种事件响应)。
Web Services里面不能支持事件是很不方便的,很多应用就受限制,或者因此就放弃了Web Services技术。当然,也有一些Workaround,比如可以轮询——Outlook Web Access就是轮询的,所以能做到有email来就在屏幕右下角出一个小窗口,效果和MSN Messenger一样,这很酷;或者也可以在客户端起一个Remoting的服务器,把Remote Object的URI传给Web Services,等事件来了以后服务器再去Call客户端,这当然也是也可以。
不过这些Workaround要么有些缺点(性能问题),要么不够直接(Remoting太“重”了)。这就好像你可以在JavaScript里面实现全部的OO,但这会非常非常繁琐。这又好像通过Attribute可以在.NET里面实现 AOP,但总感觉不直接。
WSE 2.0 ( Web Services Enhancements 2.0)提供了一些TCP Messaging的功能,很好地解决了这个问题(在Web Services架构里面实现原生的Callback)。我写了一个简单的例子来演示Web Services如何支持事件回调:
1. 服务器端的主要代码(片断):
using Microsoft.Web.Services;
using Microsoft.Web.Services.Messaging;
using Microsoft.Web.Services.Addressing;
 
private ArrayList Listeners
{
     get
     {
         return (ArrayList)Application["Listeners"];
     }
}
 
[WebMethod]
public void AddListener(string listener)
{
     this.Listeners.Add(listener);   
}
 
[WebMethod]
public void RemoveListener(string listener)
{
     for(int i=0;i<this.Listeners.Count;i++)
     {
         if(((string)this.Listeners[i]).Equals(listener))
         {
              this.Listeners.RemoveAt( i );
              return;
         }
     }
}
 
[WebMethod]
public void FireEvent()
{
     for(int i=0;i<this.Listeners.Count;i++)
     {
         SoapEnvelope envelope = new SoapEnvelope();
         envelope.SetBodyObject("blah blah");
         envelope.Context.Action = new Action((string)(this.Listeners[i]));
         envelope.Context.ReplyTo = new ReplyTo(new System.Uri((string)(this.Listeners[i])));
         SoapSender peerProxy = new SoapSender(new System.Uri((string)(this.Listeners[i])));
         try
         {
              peerProxy.Send(envelope);
         }
         catch(Exception e)
         {
              this.Listeners.RemoveAt( i );
         }
     }
}
 
[WebMethod]
public string GetListeners()
{
     string listeners="";
     foreach(string item in this.Listeners)
     {
         listeners+=item+";";
     }
     return listeners;
}
一些说明:
a) Application["Listeners"]是在Application_Start里面创建的;
b) Microsoft.Web.Services.*就是WSE的Namespace,需要到微软网站下载安装了才会有;
c) AddListener、RemoveListener、FireEvent都是很好懂的代码,典型的Subscriber模式,其中主要就是靠SoapSender.Send()来最终完成回调,call客户端的事件处理代码。
2. 客户端的主要代码(片断):
public class Form1 : System.Windows.Forms.Form
{
     private void buttonAdd_Click(object sender, System.EventArgs e)
     {
         WSEClient.sha_zheng_0a.Service1 server=new sha_zheng_0a.Service1();
         server.AddListener(this.myUri.ToString());    
         this.textBoxOutput.Text+="/r/n/r/n"+server.GetListeners();
     }
 
     private void buttonRemove_Click(object sender, System.EventArgs e)
     {
         WSEClient.sha_zheng_0a.Service1 server=new sha_zheng_0a.Service1();
         server.RemoveListener(this.myUri.ToString());
         this.textBoxOutput.Text+="/r/n/r/n"+server.GetListeners();
     }
 
     private void buttonFire_Click(object sender, System.EventArgs e)
     {
         WSEClient.sha_zheng_0a.Service1 server=new sha_zheng_0a.Service1();
         server.FireEvent();
     }
 
     private void buttonList_Click(object sender, System.EventArgs e)
     {
         WSEClient.sha_zheng_0a.Service1 server=new sha_zheng_0a.Service1();
         this .textBoxOutput.Text+="/r/n/r/n"+server.GetListeners();
     }
 
     private void Form1_Load(object sender, System.EventArgs e)
     {
         int port=(new System.Random()).Next(3000,7000);
         this .Text="Client Port: "+ port;
         MyReceiver.mainform=this;
         myUri = new Uri("soap.tcp://" + System.Net.Dns.GetHostName() + ":"+port+"/MyEventListner");
         SoapReceivers.Add(myUri, typeof(MyReceiver));
     }
 
     System.Uri myUri;
}
 
public class MyReceiver : SoapReceiver
{
     protected override void Receive(SoapEnvelope envelope)
     {
         mainform.textBoxOutput.Text+="/r/n/r/nEvent Fired";
     }
     public static Form1 mainform;
}
一些说明:
a) WSEClient.sha_zheng_0a.Service1就是Web Services客户端的Proxy;
b) MyReceiver类继承了SoapReceiver类,并重载了Receive()函数,这就是客户端的Callback函数了;
c) 在此之前,先要用SoapReceivers.Add()把MyReceiver类型作为一个接收器绑定到一个端口上进行侦听,然后,把完整的URI注册到服务器端(相当于订阅这个事件)。
3. 效果:
同时可以运行三份客户端程序(分别绑定在不同端口上)并注册到服务器。然后,只要服务器端有事件被触发(FireEvent),所有注册的客户端都能做出响应(在输出框中打印“Event Fired”)。
下面是一个截屏:
 
4. 好在哪里:
客户端很“轻”,而且这套事件响应机制已经是Web Services的一部分,是原生支持的。
“轻”,原生支持,这是最好的两点。
其实,很多技术之间并没有很明显的革命性提高。往往就是变得方便了一些、简洁了一些、容易了一些、快了一些,就已经是很大的提高了。
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值