WSE 2.0 寻址
WSE 1.0 与 WSE 2.0 之间的区别之一是对 WS-Addressing 的支持。WS-Addressing 替换了 WSE 1.0 中支持的 WS-Routing 规范的大部分功能。从功能方面来说,WS-Addressing 不是将重点放在路由路径上,而是提供一种机制将 To 和 From 标头添加到 SOAP 信封中。WS-Addressing 也支持 Action、ReplyTo 和 FaultTo 标头。Action 标头类似于通过 HTTP 发送 SOAP 消息时通常使用的 SOAPAction HTTP 标头。对于 .asmx Web 服务,HTTP SOAPAction 标头用于确定接收传入消息时应调用服务的哪种 Web 方法。与此类似,Action SOAP 标头用于确定通过非 HTTP 传输接收消息时要调用的函数。
在 Rock Paper Scissors 应用程序中,我们还将利用 ReplyTo 标头来确定接收下一消息的地址。当对等应用程序之一向 RPSService 发送单向 RegisterPlayer 消息时,将指定一个 ReplyTo 终结点,指示对等通信开始时用来接收对方发送的消息的地址。与此类似,当第二个对等应用程序将 FindPlayer 消息发送到 RPSServer 时,RPSServer 将返回一个带有 ReplyTo 标头的消息,该标头指示第一个对等应用程序的终结点。这就告诉第二个对等应用程序应该将自己的下一消息发送到第一个对等应用程序的终结点。在余下的对等消息中,继续指定 ReplyTo 标头来不断指示接收下一消息的地址。
下面是对等应用程序使用的部分代码,在代码中,首先侦听对等通信,然后在调用 RPSServer RegisterPlayer Web 方法之前通过 ReplyTo 标头指示 URI。
myPeerUri
= new Uri("soap.tcp://"
+ System.Net.Dns.GetHostName()
+ ":3131/RPSPeer1");
SoapReceivers.Add(myPeerUri, typeof(PeerService));
RPSServ.RPSServerWse proxy = new RPSServ.RPSServerWse();
proxy.RequestSoapContext.ReplyTo = myPeerUri;
TCP 消息处理 在 WSE 2.0 中,消息处理是新增功能的主要部分。WSE 2.0 通过异步 TCP 或请求/响应方式 TCP 为进程中的通信提供支持。在本示例的 Rock Paper Scissors 应用程序中,我们将发送消息来指示玩家对于特定游戏实例是否选择了石头、布或剪刀。由于我们依靠用户交互来确定发送消息的内容,我们不可能无限地等待需要发送响应的请求,因此,我们使用异步 TCP 消息来实现特定游戏的通信。一个人发送其动作后应用程序耐心的等待,直到对方玩家发送其动作。您可以将这看作类似于向仓库发送发货单,必须等待,直到有人手动包装材料,才能发送一个指示请求完成的响应。
在上面显示的 ReplyTo 代码中,给出了建立 TCP 终结点需要的部分代码。通过 SoapReceiver 类中的 Add 方法,可以注册侦听代码。在本示例中,我们创建了一个名为 PeerService 的类,它是侦听传入的 Rock Paper Scissors 游戏的 SoapReceiver 类的子类。PeerService 类只是重载了处理传入消息的 Receive 方法。该类的代码如下所示:
public class PeerService : SoapReceiver { public static Form1 Form;
protected override void Receive(SoapEnvelope envelope) { Form.opponentPlay = (char)envelope.GetBodyObject(typeof(char)); foreach (SecurityToken tok in envelope.Context.Security.Tokens) { if (tok is KerberosToken) { Form.opponent = (KerberosToken)tok; break; } } Form.OpponentUri = envelope.Context.ReplyTo; if (Form.peerToken == null) Form.peerToken = new KerberosToken("host/" + Form.OpponentUri.Host); Form.opposingNameLabel.Invoke( new Form1.ReceivePlayDelegate(Form.ReceivePlay)); } } |
Receive 方法采用 SoapEnvelope 对象作为参数。SoapEnvelope 类是从 XmlDocument 类派生得到的,这样,您可以通过标准的 XML DOM 接口来访问 SOAP 正文和标头。我们没有使用 DOM 接口,而是利用 GetBodyObject 方法基于 SOAP 消息正文中的 XML 来创建一个类,该方法在功能上使用了 XmlSerializer。我们将动作信息保存在 Form 类的一个公有属性中。
我们还从请求中获取 Kerberos 令牌并将它保存。它将用于以后获取对手的名称。然后,保存对手的 ReplyTo URI,以便我们了解接收响应的地址。我们亦可基于 URI 中显示的主机先行建立 Kerberos 令牌,它将用于加密返回的消息。
SoapReceivers 支持将侦听传入的连接,并在收到消息时调用指示的类的 Receive 方法。进程的线程池中的某个线程将调用 Receive 方法,大多数情况下,该线程不是处理应用程序主窗口消息泵的线程。因此,在 Receive 方法的末尾,我通过 Windows 窗体中的一个控件调用 Invoke 方法。这就启动了主窗口线程中指定的委托功能,以使窗体中各种控件的常规交互正确进行。在本示例中,委托确定两次动作后的赢家并相应地更新用户界面。
当调用 SoapReceivers.Add 方法(下面再次显示了该方法)时,我们传递两个参数:一个 URI 和侦听类的类别类型。URI 指示了多项内容。首先,URI 类型为 soap.tcp。这表示它是一个通过 TCP 发送的 SOAP 消息的 URI。URI 的主机名称指示要侦听的计算机,其后是用来侦听传入连接的 TCP 端口号。在本示例中,我们使用端口 3131。最好不要使用 1000 以下的端口号,因为它们是为特定类型的应用程序而保留的(例如,端口 80 用于 HTTP 服务器)。
myPeerUri
= new Uri("soap.tcp://"
+ System.Net.Dns.GetHostName()
+ ":3131/RPSPeer1");
SoapReceivers.Add(myPeerUri, typeof(PeerService));
向异步 TCP 侦听器发送消息也同样简单。我们只要创建一个 SoapEnvelope 对象,并使用 SetBodyObject 方法将对象序列化到正文的 XML 中。SoapEnvelope 包含一个 Context 属性,该属性的使用类似于常规 HTTP 绑定的 SOAP 交互时使用的 SoapRequestContext 和 SoapResponseContext 属性。我们用它来建立需要的 Action SOAP 标头和可选的 ReplyTo 标头。我们还要添加前面创建的 Kerberos 令牌并用它来加密消息。对于发送消息,我们使用 SoapSender 类,该类与我们用于侦听传入消息的 SoapReceiver 类相对应。SoapSender 类获取其构造函数中的终结点 URI,然后将传递的 SoapEnvelope 发送到 Send 方法。发送对等消息的代码如下所示。
// Send Message
SoapEnvelope envelope = new SoapEnvelope();
envelope.SetBodyObject(myPlay);
envelope.Context.Action = new Action(OpponentUri.ToString());
envelope.Context.Security.Tokens.Add(peerToken);
envelope.Context.Security.Elements.Add(
new EncryptedData(peerToken));
envelope.Context.ReplyTo = myPeerUri;
SoapSender peerProxy = new SoapSender(this.OpponentUri);
peerProxy.Send(envelope);
您可以从 Microsoft Download Center 获取 Rock Paper Scissors 应用程序的完整源代码(英文)。
WSE 2.0 的其他功能 通过 Rock Paper Scissors 应用程序,我们研究了 WSE 2.0 的许多功能,但是还有许多其他功能。用户名令牌还可以与 Windows 安全性集成,如 Kerberos 令牌。由于支持安全上下文令牌,您可以建立有效的对称密钥,用于对两个终结点之间的多个消息进行加密,而无需为每个消息生成一个新的密钥。除了安全上下文令牌以外,还支持创建安全性令牌服务 (Security Token Service),该服务为两个终结点之间的通信颁发上下文令牌。
对于消息处理,我们仅讨论了对发送异步 TCP 消息的支持,其实对同步请求/响应的支持也是同样出色。该支持使用 SoapMethod 属性,类似用于 .asmx Web 服务的 WebMethod 属性,而且操作也相似。此外还支持在单独的应用程序空间中调用服务,这似乎不是很好,但 Windows 消息泵(创建窗式应用程序的基础)同样基于在单独的应用程序空间中发送消息。
WSE 2.0 更为吸引人的地方之一是具有许多可扩展点。您可以做任何事情,包括从创建自己的自定义令牌处理程序到添加自己的策略支持。像 WSE 1.0 一样,您仍然可以扩大处理范围,但更重要的是如何在更高的层次上前进并利用已有的工作。
查看本文来源