服务站
WCF 消息传递基础
代码下载位置: ServiceStation2007_04.exe (161KB)
XML 表示形式
Message 类
消息版本
读写消息
键入的消息正文
消息生存期
消息标头和属性
将消息映射到方法
端点和绑定
综述
开
始分离 Windows® Communication Foundation 的各层时,您会发现一种复杂的基于 XML 的消息传递框架,它在使用各种协议和格式连接系统时提供了大量的可能性。在本月的专栏中,我将着重介绍一些主要的消息传递功能,它们提供了这样的灵活性。
本专栏假定您对 Windows Communication Foundation 编程模型具有基本的了解。如果您不熟悉它,那么在继续之前,您应该阅读 2006 年 2 月份的《MSDN® 杂志》中我的文章。
Windows Communication Foundation 消息传递体系结构的主要目的之一是,在提供统一编程模型的同时,还允许灵活地表示数据和传递消息。这是基于将 XML 作为数据模型以及将 SOAP 和 WS-Addressing 作为消息传递框架而实现的。但是,Windows Communication Foundation 构建在这些模型基础上这一事实,并不意味着在传递消息时必须使用 XML 1.0、SOAP 或 WS-Addressing。您将会看到 Windows Communication Foundation 提供了很大的灵活性。
从早期的 XML 开始,软件行业就依赖于为在 XML 文档中找到的数据提供标准定义的鲜为人知的规范。此规范称为 XML 信息集 (InfoSet),它根据元素和属性所包含的信息来定义它们,在某种意义上这完全与字节表示形式无关。(有关详细信息,请参阅 www.w3.org/TR/xml-infoset。)
InfoSet 规范使得其他 XML 规范和 API 为在 XML 文档中找到的数据提供一致的视图成为可能(尽管它们可能以完全不同的方式表示该数据)。最终,InfoSet 为使用 XML 数据的应用程序提供了共同的集合点,如图 1 所示。最后要说的是,XML 处理器负责在字节表示形式和编程模型体验之间的转换。
图 1 XML InfoSet 的角色 (单击该图像获得较小视图)
图 1 XML InfoSet 的角色 (单击该图像获得较大视图)
Windows Communication Foundation 为 System.Xml 命名空间引入了一些基本增强,这使得在读写 XML 文档时利用替代的字节表示形式(而不是仅限文本的 XML 1.0)成为可能。此处关注的主要类 System.Xml.XmlDictionaryReader 和 System.Xml.XmlDictionaryWriter 位于 Microsoft® .NET Framework 3.0 附带的新 System.Runtime.Serialization 程序集中。
XmlDictionaryReader 和 XmlDictionaryWriter 类都提供了静态工厂方法,用于创建使用文本、二进制和 MTOM(消息传输优化机制)表示形式的读取器和编写器。例如,XmlDictionaryReader 提供了 CreateTextReader、CreateBinaryReader 和 CreateMtomReader 方法,而 XmlDictionaryWriter 提供了对应的 CreateTextWriter、CreateBinaryWriter 和 CreateMtomWriter 方法。
让我们看一些示例。试考虑某个客户的以下文本 XML 1.0 表示形式:
<!-- customer.xml --> <Customer xmlns="http://example.org/customer"> <Email>bob@contoso.com</Email> <Name>Bob</Name> </Customer>
以下代码说明如何将 customer.xml 读入 XmlDocument 对象,以及如何使用 XmlDictionaryWriter 以二进制表示形式重新将同一 XmlDocument 对象保存在磁盘上:
// read from XML 1.0 text representation XmlDocument doc = new XmlDocument(); doc.Load("customer.xml"); // write to binary representation FileStream custBinStream = new FileStream( "customer.bin", FileMode.Create); using (XmlWriter xw = XmlDictionaryWriter.CreateBinaryWriter( custBinStream)) { doc.WriteContentTo(xw); }
运行此代码后,您就将二进制表示形式保存在 customer.bin 中,如图 2 所示。即使图 2 所示的二进制编辑器碰巧显示字符序列,这实际上也是二进制文件,显然不像 XML 1.0 文件。不过,它确实表示 XML 文档 (InfoSet)。尽管如此,此二进制格式是 3.0 版 System.Xml 专有的,它与其他 .NET 版本或 Web 服务框架不兼容。
图 2 客户 XML 文档的二进制表示形式 (单击该图像获得较小视图)
图 2 客户 XML 文档的二进制表示形式 (单击该图像获得较大视图)
图 3 中的代码示例演示如何将二进制表示形式读回到 XmlDocument 对象中,以及如何以 MTOM 表示形式将它重新保存到磁盘上。MTOM 表示形式看起来与文本或二进制表示形式差别很大,如图 4 所示。不过,它表示同一 XML 文档,并可以使用相同的 System.Xml API 进行处理。MTOM 表示形式也与该 MTOM 中的二进制表示形式不同,因为 MTOM 是基于 InfoSet 的 W3C 推荐标准,在 Web 服务框架之间得到广泛的支持。通过利用多部分 MIME 组帧,MTOM 使得优化 XML 文档中二进制元素的传输成为可能。
图 4 客户 XML 文档的 MTOM 表示形式 (单击该图像获得较小视图)
图 4 客户 XML 文档的 MTOM 表示形式 (单击该图像获得较大视图)
现在,通过将 MTOM 表示形式再读入 XmlDocument 并以文本表示形式将其保存在磁盘上,我们可以执行一个完整循环,如下所示:
// read from MTOM representation XmlDocument doc = new XmlDocument(); FileStream custMtomStream = new FileStream( "customer.mtom", FileMode.Open); using (XmlReader xr = XmlDictionaryReader.CreateMtomReader( custMtomStream, Encoding.UTF8, XmlDictionaryReaderQuotas.Max)) { doc.Load(xr); } // write to text (XML 1.0) representation doc.Save("customer.xml");
生成的 custom.xml 文件应该与原始的文本表示形式完全相同。正如您所看到的,通过提供三种方法来表示 XML 以实现持久性和传输,这些 System.Xml 增强功能提供了很大的灵活性。当然,将来可能会添加其他表示形式。此外,虽然是 Windows Communication Foundation 为表带来了这些增强,但是可以在任何 .NET Framework 3.0 应用程序中利用它们。
您可以选择在传递消息时使用的 XML 表示形式,Windows Communication Foundation 即基于此而构建。如果需要互操作性,则应该选择 XML 1.0 文本表示形式。如果需要互操作性以及对二进制负载的高效支持,则应该选择 MTOM 表示形式。在只有 .NET 的方案中,二进制表示形式可能会提供更佳的性能。此处的关键是您确实可以进行选择了。
任何消息传递框架的另一个主要功能是,通过任意标头扩展消息负载。标头不过是随消息传递的额外信息,用于实现其他的消息处理功能(如安全性、可靠的消息传递和事务)。对于 XML 消息,这意味着用 XML 标头扩展 XML 负载(两者都表示为在容器元素中分帧的 XML 元素)。此功能与 SOAP 提供的完全相同。
SOAP 框架使得定义基于 XML 的协议(可通过任何传输使用,而不依赖于任何传输特定的功能)成为可能。WS-Addressing 是一种规范,用于扩展 SOAP 以提供与传输无关的机制来寻址/路由 SOAP 消息。SOAP 和 WS-Addressing 都基于 InfoSet,且允许(但不要求)在传递消息时使用 XML 1.0 语法。
Windows Communication Foundation 支持使用上一部分中讨论的任何 XmlDictionaryReader/Writer 表示形式,这样应用程序就可以无缝地满足各种范围和性能要求。Windows Communication Foundation 使用图 5 所示的 Message 类模拟所有消息。正如您可以看到的,Message 类在本质上模拟消息正文以及消息标头和属性的集合。可用方法主要用于创建消息、读写消息正文以及操作标头和属性的集合。
通过调用各种静态 CreateMessage 重载之一创建 Message 对象,并使用 IDisposable 或通过显式调用 Close 处理 Message 对象。可以从头开始创建新的 Message 对象,在发送消息时通常这样做。也可以从消息流创建新的 Message 对象,在接收消息时通常这样做。
如果从头开始创建消息,则必须指定操作、消息版本以及要在消息中使用的正文。操作唯一地标识消息的目的或语义。Windows Communication Foundation 服务依赖于将传入消息分派给相应方法的操作。消息版本标识传输时使用的 SOAP 和 WS-Addressing 版本(如果有)。指定消息版本时可以选择各种不同的选项。让我们了解一下这些选项。
如上所述,通过 MessageVersion 类,可以指定要使用的 SOAP 和 WS-Addressing 版本。通过调用 CreateVersion 并提供 EnvelopeVersion 对象(用于标识 SOAP 版本)和 AddressingVersion 对象(用于标识 WS-Addressing 版本),可以创建 MessageVersion 对象。如下所示:
MessageVersion version = MessageVersion.CreateVersion( EnvelopeVersion.Soap12, AddressingVersion.WSAddressing10);
如果查看一下 EnvelopeVersion 类,则将看到 Windows Communication Foundation 当前支持三个选项(即 SOAP-None、Soap11 和 Soap12),如下所示:
public sealed class EnvelopeVersion { public static EnvelopeVersion None { get; } public static EnvelopeVersion Soap11 { get; } public static EnvelopeVersion Soap12 { get; } ... }
同样,如果查看一下 AddressingVersion,则将看到 Windows Communication Foundation 当前也支持三个选项(即 WS-Addressing-None、WSAddressing10 和 WSAddressingAugust2004),如下所示:
public sealed class AddressingVersion { public static AddressingVersion None { get; } public static AddressingVersion WSAddressing10 { get; } public static AddressingVersion WSAddressingAugust2004 { get;} ... }
EnvelopeVersion.None 指定在传输过程中您不希望使用 SOAP,它还要求您使用 AddressingVersion.None。这是希望在传统的 XML 消息传递方案中利用 Windows Communication Foundation 时的常见设置。Soap11 表示 SOAP 1.1 规范,该规范目前得到广泛使用,而 Soap12 表示 SOAP 1.2 W3C 推荐标准(有关指向这两种规范的链接,请参阅 www.w3.org/TR/soap)。
WSAddressingAugust2004 表示 2004 年 8 月开始提交的 WS-Addressing W3C 提案(请参阅 www.w3.org/Submission/ws-addressing),目前得到广泛支持。而 WSAddressing10 表示最终的 WS-Addressing 1.0 W3C 推荐标准(请参阅 www.w3.org/2002/ws/addr)。
因此,根据进行通信的另一方支持的 SOAP 和 WS-Addressing 版本,可以仔细挑选合适的版本以便利互操作性。此外,为了使您操作起来更轻松一点,MessageVersion 类提供了几个公共属性,这些属性返回表示这两种规范的最常见组合的已缓存 MessageVersion 对象(参见图 6)。因此,只需指定 MessageVersion.Soap12WSAddressing10(其作用与 MessageVersion.Default 相同),而不是显式调用 CreateVersion。
从头开始创建消息时,可以使用许多重载来指定消息的正文。可以将正文作为 XmlDictionaryReader、XmlReader 或可序列化的对象提供。还可以为正文提供 MessageFault 对象以便创建故障消息。创建消息后,可以通过调用返回 XmlReader 的 GetReaderAtBodyContents 或调用 GetBody<T> 将正文反序列化为 .NET 对象来访问正文。
在希望写入消息时,可以通过分别调用 WriteMessage 或 WriteBody 方法写入整个消息或仅写入正文。这两种方法都具有允许提供 XmlDictionaryWriter 或 XmlWriter 对象的重载。以下示例说明如何创建随后写入到名为 message.xml 的文件中的新消息:
// load body from customer.xml file XmlDocument doc = new XmlDocument(); doc.Load("customer.xml"); Message m = Message.CreateMessage( MessageVersion.Soap11WSAddressingAugust2004, "urn:add-customer", new XmlNodeReader(doc)); FileStream fs = new FileStream("message.xml", FileMode.Create); using (XmlWriter xw = XmlDictionaryWriter.CreateTextWriter(fs)) { m.WriteMessage(xw); }
在这种情况下,为操作指定了“urn:add-customer”,为消息版本指定了 Soap11WSAddressing2004。正文是通过 XmlReader 提供的。然后调用 WriteMessage 将消息写出到基于文本的 XmlDictionaryWriter 对象。生成的 message.xml 如下所示:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing"> <s:Header> <a:Action s:mustUnderstand="1">urn:add-customer</a:Action> </s:Header> <s:Body> <Customer xmlns="http://example.org/customer"> <Email>bob@contoso.com</Email> <Name>Bob</Name> </Customer> </s:Body> </s:Envelope>
请注意,XML 命名空间指示 SOAP 1.1 和 2004 年 8 月的 WS-Addressing。指出可以使用不同的 XmlDictionaryWriter 对象将消息轻松地写出到二进制或 MTOM 表示形式是很重要的。
现在,如果希望,则可以将版本更改为 MessageVersion.Soap12WSAddressing10,而生成的文件则将如下所示:
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing"> <s:Header> <a:Action s:mustUnderstand="1">urn:add-customer</a:Action> </s:Header> <s:Body> <Customer xmlns="http://example.org/customer"> <Email>bob@contoso.com</Email> <Name>Bob</Name> </Customer> </s:Body> </s:Envelope>
请注意 SOAP 和 WS-Addressing 的较新版本。
如果将版本更改为 MessageVersion.None,则生成的消息将不再包含 SOAP 信封。相反,它将仅包含正文:
<Customer xmlns="http://example.org/customer"> <Email>bob@contoso.com</Email> <Name>Bob</Name> </Customer>
为了读回消息,需要使用允许您提供用于读取消息流的 XmlDictionaryReader 的不同 CreateMessage 重载。您还需要指定正确的消息版本。接下来的代码说明一个读取上面无信封的最后一条消息的示例(版本为 MessageVersion.None):
FileStream fs = new FileStream("message.xml", FileMode.Open); using (XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader( fs, XmlDictionaryReaderQuotas.Max)) { Message m = Message.CreateMessage(reader, 1024, MessageVersion.None); XmlDocument doc = new XmlDocument(); doc.Load(m.GetReaderAtBodyContents()); Console.WriteLine(doc.InnerXml); }
正如您可以看到的,Message 类为使用不同版本的 SOAP 和 WS-Addressing(如果使用了它们中的任一个)读写消息提供了很大的灵活性。此外,它基于 XmlDictionaryReader 执行读写操作的这一事实意味着,在传递消息时可以使用所有支持的 XML 表示形式。
到目前为止,我介绍了直接使用 XML 的示例。如果要将 XML 反序列化为 .NET 对象,则可以使用支持的序列化程序之一,如 DataContractSerializer、NetDataContractSerializer 或 XmlSerializer。在与 DataContractSerializer 一起使用时,以下类能够表示在 customer.xml 中找到的 XML:
[DataContract(Namespace="http://example.org/customer")] public class Customer { public Customer() { } public Customer(string name, string email) { this.Name = name; this.Email = email; } [DataMember] public string Name; [DataMember] public string Email; }
现在,可以通过为正文提供 Customer 对象创建消息,如下所示:
Customer cust = new Customer("Bob", "bob@contoso.com"); Message msg = Message.CreateMessage( MessageVersion.Soap11WSAddressingAugust2004, "urn:add-customer", cust);
尽管使用一个对象来表示正文,但是生成的消息将与前面的示例完全相同。
现在,读取正文时,可以使用 GetBody<Customer> 生成新的 Customer 对象,如下所示:
Customer c = msg.GetBody<Customer>(); Console.WriteLine("Name: {0}, Email: {1}", c.Name, c.Email);
这些版本的 CreateMessage 和 GetBody<T> 在后台使用 DataContractSerializer。每个方法还有一个版本,允许您显式指定要使用的序列化程序。
有关详细信息,请参阅我在 2006 年 8 月撰写的题为“在 Windows Communication Foundation 中进行序列化”专栏(可以从 msdn.microsoft.com/msdnmag/issues/06/08/ServiceStation 下载)。
经过仔细地设计,Message 类已支持流处理。因此,在 Message 对象的生存期内只能处理一次正文。为了确保这一点,Message 类提供了描述对象当前状态的 State 属性。MessageState 定义以下五种可能的消息状态:
public enum MessageState { Created, Read, Written, Copied, Closed }
Message 对象在开始时处于 Created 状态,该状态是处理正文的唯一有效状态。处理正文有以下几种不同的方式:可以对其进行读取、写入或复制。调用 GetReaderAtBodyContents 或 GetBody<T> 可将状态更改为 Read。调用 WriteMessage 或 WriteBody 可将状态更改为 Written。调用 CreateBufferedCopy 可将状态更改为 Copied。例如,试考虑以下使消息在几种状态之间切换的示例:
Customer cust = new Customer("Bob", "bob@contoso.com"); Message m = Message.CreateMessage( MessageVersion.Soap11WSAddressingAugust2004, "urn:add-customer", cust); Console.WriteLine("State: {0}", m.State); Customer c = m.GetBody<Customer>(); // cannot access body from here on Console.WriteLine("State: {0}", m.State); m.Close(); Console.WriteLine("State: {0}", m.State);
执行代码时,会将此文本打印到控制台:
State: Created State: Read State: Closed
在 Message 对象不再处于 Created 状态后,需要访问正文的任何方法都将引发异常。例如,首次调用 GetBody<T> 后再次调用它将导致异常。在需要多次处理正文的情况下,可以创建缓冲副本(通过调用 CreateBufferedCopy)或者将正文加载到 XmlDocument 中或将它反序列化为 .NET 对象以便在内存中使用。
不用说,通过 State 属性可以在运行时确定是否已使用特定消息的正文(它不再处于 Created 状态时)以及如何使用它(它是被读取、写入还是复制)。
Message 类提供了 Headers 属性,以模拟与正文关联的标头集合。以下示例说明如何将名为“ContextId”的自定义标头添加到消息中:
Customer cust = new Customer("Bob", "bob@contoso.com"); Message m = Message.CreateMessage( MessageVersion.Default, "urn:add-customer", cust); m.Headers.Add( MessageHeader.CreateHeader( "ContextId", "http://example.org/customHeaders", Guid.NewGuid()));
在写入时,此消息将如下所示:
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing"> <s:Header> <a:Action s:mustUnderstand="1">urn:add-customer</a:Action> <ContextId xmlns="http://example.org/customHeaders" >a200f76d-5b83-4496-a035-4f9e70a07959</ContextId> </s:Header> ... </s:Envelope>
通常由中介来处理在消息中找到的标头。这样的中介通常需要在某处存储其处理结果,供将来在处理管道时使用。为达到此目的,Message 类还提供了 Properties 集合来存储任意的名称/对象对。
与标头(它始终在消息中传输)不同,消息属性通常仅在本地处理期间使用(它们可能不对通信时发生的情况产生影响,尽管有时它们会产生影响)。例如,使用 HTTP 时,Windows Communication Foundation 在传入 Message 对象的 Properties 集合中存储 HTTP 请求详细信息。详细信息存储在 HttpRequestMessageProperty 类型的对象(可以使用属性名的 httpRequest 访问它)中。还可以通过用 HttpReponseMessageProperty 类型的对象填充名为 httpResponse 的属性,影响 HTTP 响应详细信息。
Windows Communication Foundation 通道(尤其是实现各种 WS-* 规范的内置协议通道)层中的组件频繁使用标头和属性是很常见的。
必须首先定义将传入消息映射到方法的服务约定,才能开始使用 Windows Communication Foundation 发送或接收消息。通过使操作值与方法签名关联,可以做到这一点。例如,以下接口为单向操作定义可能的最通用服务约定:
[ServiceContract] public interface IUniversalOneWay { [OperationContract(Action="*")] void ProcessMessage(Message msg); }
此定义使 ProcessMessage 与所有传入消息关联,而不管其操作值如何(由于使用了 Action= "*" 子句)。也可以使用相同方法定义一般的请求-答复操作:
[ServiceContract] public interface IUniversalRequestReply { [OperationContract(Action="*", ReplyAction="*")] Message ProcessMessage(Message msg); }
还可以通过将 Action 属性设置为特定值(如 urn:add-customer)使方法与特定操作值关联,如下所示:
[ServiceContract] public interface ICustomer { [OperationContract(Action="urn:add-customer")] void AddCustomer(Message msg); }
在 Windows Communication Foundation 收到传入消息时,它将查看操作以确定要调度的方法,然后它再执行任何必要的序列化。对请求/响应类型使用消息时,Windows Communication Foundation 不执行任何序列化,而是由您决定如何处理消息。但是,使用键入的签名时,Windows Communication Foundation 使用序列化方法在后台自动执行读写消息正文的过程。例如,试考虑以下服务约定:
[ServiceContract] public interface ICustomer { [OperationContract(Action="urn:add-customer")] void AddCustomer(Customer cust); }
在这种情况下,Windows Communication Foundation 负责在调用 AddCustomer 之前将传入消息的正文反序列化为 Customer 对象。
还存在一种称为消息约定的序列化快捷方式,用于自动将标头添加到 Message 对象。消息约定允许您为类添加注释,指定哪些字段映射到标头(与正文相对):
[MessageContract(IsWrapped=false)] public class AddCustomerRequest { [MessageHeader(Name="ContextId", Namespace="http://example.org/customHeaders"] public Guid ContextId; [MessageBodyMember] public Customer customer; }
如果此消息约定类已就绪,则可以定义一个将它用作请求类型的操作,如下所示:
[ServiceContract] public interface ICustomer { [OperationContract(Action = "urn:add-customer")] void AddCustomer(AddCustomerRequest request); }
这样会通知 Windows Communication Foundation 在对象中的 ContextId 字段和 SOAP 消息中的 ContextId 标头之间自动映射,您就不必手动处理 Headers 集合了。
为了布置 Windows Communication Foundation 服务,您需要提供几则信息。首先,必须通知它要使用的传输和地址。第二,必须指定所需的 XML 表示形式和消息版本。第三,必须配置采用哪些 WS-* 协议。最后,必须提供传入消息和服务方法之间的映射。在 Windows Communication Foundation 中,通过端点指定所有这些详细信息。
端点配置仅仅是地址、绑定和约定的组合。如上所述,约定定义消息和方法之间的映射。绑定指定剩余的消息传递详细信息。它指定在传递期间要使用的传输、XML 表示形式和消息版本。它还确定生成通道堆栈时应该包括的 WS-* 协议。
绑定还指定消息编码器;它实际上控制 XML 表示形式和消息版本详细信息。在运行时,消息编码器是传输通道从数据流读取和向其写入消息所用的组件。Windows Communication Foundation 提供了三个内置的消息编码器实现:TextMessageEncoder、BinaryMessageEncoder 和 MtomMessageEncoder。所有这些类都基于在前面讨论的新增 XmlDictionaryReader 和 XmlDictionaryWriter 类支持给定的 XML 表示形式。每个类还配置为使用特定的消息版本。
正如您可能知道的,Windows Communication Foundation 附带有内置绑定以便于处理常见方案。每个绑定都配置为使用特定的消息编码器。例如,BasicHttpBinding 和 WSHttpBinding 都配置为使用 TextMessageEncoder。但是,对于消息版本,前者使用 MessageVersion.Soap11,而后者使用 MessageVersion.Soap12WSAddressing10。NetTcpBinding、NetNamedPipeBinding 和 NetMsmqBinding 都配置为使用 BinaryMessageEncoder 和 MessageVersion.Soap12WSAddressing10。
可以选择在特定的绑定上使用不同的消息编码器(通过其属性或绑定配置)。例如,以下代码说明如何将 BasicHttpBinding 的消息编码器更改为 MtomMessageEncoder:
BasicHttpBinding basic = new BasicHttpBinding(); basic.MessageEncoding = WSMessageEncoding.Mtom; ... // use binding
在需要对绑定配置进行更多控制时,可以使用 CustomBinding 类定义自定义绑定:
MtomMessageEncodingBindingElement mtom = new MtomMessageEncodingBindingElement( MessageVersion.Soap12, Encoding.UTF8); CustomBinding binding = new CustomBinding(); binding.Elements.Add(mtom); binding.Elements.Add(new HttpTransportBindingElement()); ... // use binding
使用此方法可以配置消息编码器使用的精确消息版本和文本编码详细信息。除了此灵活性外,Windows Communication Foundation 体系结构还允许您编写和使用自定义消息编码器 - SDK 附带有一个说明如何执行此操作的示例。通常,使用 Windows Communication Foundation 可以轻松地将端点配置为使用不同的 XML 表示形式和消息版本,而不会对服务代码产生任何影响。
让我们看一下最后一个示例,该示例综合了其中的大多数消息传递概念。图 7 说明如何实现、承载和配置使用 IUniversalOneWay 约定以及自定义的绑定和编码器的通用服务。图 8 说明如何实现能够将消息发送到所承载的服务的客户端。服务实现使用 System.Xml 处理传入消息,而客户端使用 Customer 对象生成消息。
Windows Communication Foundation 消息传递体系结构提供了统一的编程模型,从而为消息传递提供了很大的灵活性。这样就可以无缝地实现不使用 SOAP、WS-Addressing 或任何其他 WS-* 协议的传统的 XML 服务。还可以配置更复杂的绑定以满足在需要不同的协议和版本时特定集成方案的精确要求。
将您想向 Aaron 提出的问题和意见发送至:sstation@microsoft.com sstation@microsoft.com.
NEW: Explore the sample code online! - or - 代码下载位置: ServiceStation2007_04.exe (161KB)
Aaron Skonnard 是 Microsoft .NET 培训提供商 Pluralsight 的创始人之一。Aaron 是 Pluralsight 推出的“Web Services 2.0 应用”(Applied Web Services 2.0)、“BizTalk Server 2006 应用”(Applied BizTalk Server 2006) 和“Windows Communication Foundation 入门”(Introducing Windows Communication Foundation) 等众多课程的作者。多年来,Aaron 一直致力于编写课程、会议演讲以及面向专业开发人员传授知识。您可以通过 pluralsight.com/aaron 与他联系。