从外部剖析WCF
尽管WCF是一个相当复杂的平台,但对于偶然的一个学习者来说它看起来还是相当简单的。正如你在Hello WC例子里看到的一样,构建一个接受程序可以简化为使用地址、绑定和契约配置一个或者多个终结点。构建一个发送程序可以简单理解为使用一个地址、绑定和契约向接收终结点发送消息。如果我们要修改发送者或者接收者的处理过程,我们可以随便这么做,使用我们自己的行为配置或者使用WCF的自带行为(比如增加元数据支持)。图4-1展示了
Endpoints、 addresses、bindings、contracts和behaviors之间的关系。
地址
所有发送或者接收消息的程序必须在终结点上使用某个地址。例如,接收程序在某个地址上侦听请求消息,而发送程序发送消息到目标地址。
WCF接收基础结构依赖System.Uri类型去构建接收终结点。WCF发送基础结构,换句话说,依赖System.ServiceModel.EndpointAddress类型发送消息给最终接收者。System.ServiceModel.EndpointAddress类型是对WS-Addressing 中终结点参考规范的CLR抽象,发送者使用这个类型去为请求消息添加终结点信息,并与接收终结点建立连接(如果存在接收终结点)第5章包含了EndpointAddress类型的详细介绍。
在
WCF里,地址在某些形式上,是一个URI(EndpointAddress对象包装了一个System.Uri对象)。一个关键部分就是URI里的scheme名。Scheme是URI表示的标识符的抽象,scheme名是一种标识scheme的方式。在许多情况下,scheme名匹配可以定位资源的协议,因此使用URI作为URL。例如,URI
http://localhost:5000/IHelloWCF标识
http为scheme名,并且如此偶然的是http(超文本传输协议)也是一个传输模式。在内部看,WCF基础结构必须能够使用URInate去构建发送或者接收基础结构。
绑定
绑定是我们表示消息应用如何处理、发送和接收消息的主要方式。更确切地说,它表示传输、
WS-*协议、安全需求、事务需求和终结点的主要方式。WCF包含9种覆盖传输、WS-*协议、安全需求、事务需求的绑定。如果这些绑定不能满足我们的需求,我们还可以定义符合我们特定需求的绑定。
通常来说,
绑定是定义消息基础结构的一个类型;它是我们程序支持传输和协议的一个抽象层。对于开发人员,这个抽象意味着通过
TCP/IP传输发送消息的代码和通过MSMQ发送消息的代码看起来非常相似,因此把我们的程序从特定的传输或者协议里解耦。此种方式的松耦合意味着开发人员可以开发、改变和定制一个应用比以前更快地满足客户要求。
所有的绑定类型都是
System.ServiceModel.Channels.Binding的子类型,于是它们都有相同的属性。一个共同的属性就是他们维护者一个私有System.ServiceModel.Channels.BindingElement对象的列表。一个BindingElement是消息交换一个特定方面的抽象,像传输或者WS-*协议。所有的绑定暴露了一个名为CreateBindingElements的方法,这个方法可以构建和返回特定绑定元素的列表。下面展示的是一个简单程序,它包含WCF里的9种绑定,并迭代显示它们的BindingElement列表:
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Reflection;
using System.Collections.Generic;
using System.ServiceModel.MsmqIntegration;
sealed class BindingElementsShow
{
static void Main(){
List<Binding> bindings = new List<Binding>();
bindings.Add(new BasicHttpBinding());
bindings.Add(new NetNamedPipeBinding());
bindings.Add(new NetTcpBinding());
bindings.Add(new WSDualHttpBinding());
bindings.Add(new WSHttpBinding());
bindings.Add(new NetMsmqBinding());
bindings.Add(new MsmqIntegrationBinding());
bindings.Add(new WSFederationHttpBinding());
// throws if Peer Networking not installed
bindings.Add(new NetPeerTcpBinding());
ShowBindingElements(bindings);
}
private static void ShowBindingElements(List<Binding> bindings){
foreach (Binding binding in bindings){
Console.WriteLine("Showing Binding Elements for {0}",
binding.GetType().Name);
foreach (BindingElement element in binding.CreateBindingElements()){
Console.WriteLine("\t{0}", element.GetType().Name);
}
}
}
}
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Reflection;
using System.Collections.Generic;
using System.ServiceModel.MsmqIntegration;
sealed class BindingElementsShow
{
static void Main(){
List<Binding> bindings = new List<Binding>();
bindings.Add(new BasicHttpBinding());
bindings.Add(new NetNamedPipeBinding());
bindings.Add(new NetTcpBinding());
bindings.Add(new WSDualHttpBinding());
bindings.Add(new WSHttpBinding());
bindings.Add(new NetMsmqBinding());
bindings.Add(new MsmqIntegrationBinding());
bindings.Add(new WSFederationHttpBinding());
// throws if Peer Networking not installed
bindings.Add(new NetPeerTcpBinding());
ShowBindingElements(bindings);
}
private static void ShowBindingElements(List<Binding> bindings){
foreach (Binding binding in bindings){
Console.WriteLine("Showing Binding Elements for {0}",
binding.GetType().Name);
foreach (BindingElement element in binding.CreateBindingElements()){
Console.WriteLine("\t{0}", element.GetType().Name);
}
}
}
}
程序输入如下:
Showing Binding Elements for BasicHttpBinding
TextMessageEncodingBindingElement
HttpTransportBindingElement
Showing Binding Elements for NetNamedPipeBinding
TransactionFlowBindingElement
BinaryMessageEncodingBindingElement
WindowsStreamSecurityBindingElement
NamedPipeTransportBindingElement
Showing Binding Elements for NetTcpBinding
TransactionFlowBindingElement
BinaryMessageEncodingBindingElement
WindowsStreamSecurityBindingElement
TcpTransportBindingElement
Showing Binding Elements for WSDualHttpBinding
TransactionFlowBindingElement
ReliableSessionBindingElement
SymmetricSecurityBindingElement
CompositeDuplexBindingElement
OneWayBindingElement
TextMessageEncodingBindingElement
HttpTransportBindingElement
Showing Binding Elements for WSHttpBinding
TransactionFlowBindingElement
SymmetricSecurityBindingElement
TextMessageEncodingBindingElement
HttpTransportBindingElement
Showing Binding Elements for NetMsmqBinding
BinaryMessageEncodingBindingElement
MsmqTransportBindingElement
Showing Binding Elements for MsmqIntegrationBinding
MsmqIntegrationBindingElement
Showing Binding Elements for WSFederationHttpBinding
TransactionFlowBindingElement
SymmetricSecurityBindingElement
TextMessageEncodingBindingElement
HttpTransportBindingElement
Showing Binding Elements for NetPeerTcpBinding
PnrpPeerResolverBindingElement
BinaryMessageEncodingBindingElement
PeerTransportBindingElement
TextMessageEncodingBindingElement
HttpTransportBindingElement
Showing Binding Elements for NetNamedPipeBinding
TransactionFlowBindingElement
BinaryMessageEncodingBindingElement
WindowsStreamSecurityBindingElement
NamedPipeTransportBindingElement
Showing Binding Elements for NetTcpBinding
TransactionFlowBindingElement
BinaryMessageEncodingBindingElement
WindowsStreamSecurityBindingElement
TcpTransportBindingElement
Showing Binding Elements for WSDualHttpBinding
TransactionFlowBindingElement
ReliableSessionBindingElement
SymmetricSecurityBindingElement
CompositeDuplexBindingElement
OneWayBindingElement
TextMessageEncodingBindingElement
HttpTransportBindingElement
Showing Binding Elements for WSHttpBinding
TransactionFlowBindingElement
SymmetricSecurityBindingElement
TextMessageEncodingBindingElement
HttpTransportBindingElement
Showing Binding Elements for NetMsmqBinding
BinaryMessageEncodingBindingElement
MsmqTransportBindingElement
Showing Binding Elements for MsmqIntegrationBinding
MsmqIntegrationBindingElement
Showing Binding Elements for WSFederationHttpBinding
TransactionFlowBindingElement
SymmetricSecurityBindingElement
TextMessageEncodingBindingElement
HttpTransportBindingElement
Showing Binding Elements for NetPeerTcpBinding
PnrpPeerResolverBindingElement
BinaryMessageEncodingBindingElement
PeerTransportBindingElement
在我们的输出力,你同样可以看到每个继承自Binding的绑定类型都表示一个消息属性的集合。在运行时,绑定元素列表的内容会决定我们程序里的终结点的消息属性。换句话说,我们选择的终结点绑定会对我们应用发送和接收的消息产生直接影响。因此,了解特定绑定的消息属性对于成功实现WCF系统至关重要。表4-1展示了每个WCF绑定的重要属性。
表4-1:
默认的Binding
属性
|
|||||||
|
Interop
|
Security
|
Session
|
Transactions
|
Duplex
|
Streaming
|
Encoder
|
BasicHttpBinding
|
BP 1.1
|
T
|
|
|
|
|
TX
|
WSHttpBinding
|
WS-*
|
M
|
|
|
|
|
TX/MT
|
WSDualHttpBinding
|
WS-*
|
TM
|
|
|
|
|
TX/MT
|
NetTcpBinding
|
WCF
|
TM
|
|
|
|
|
B
|
NetMsmqBInding
|
WCF
|
TM
|
|
|
|
|
B
|
MsmqIntegrationBinding
|
MSMQ
|
T
|
|
|
|
|
TX
|
NetNamedPipeBinding
|
WCF
|
TM
|
|
|
|
|
B
|
NetPeerTcpBinding
|
WCF
|
T
|
|
|
|
|
B
|
WSFederationHttpBinding
|
WS-*
|
M
|
|
|
|
|
TX
|
BP 1.1 = Basic Profile 1.1, T = Transport, M =Message, TX = Text, MT = MTOM, B = Binary
|
当一个人第一次接触这些
WCF默认的绑定时,很容易被选择绑定和选择绑定合适的消息选项而迷惑。记住当选择的时候,它可以托管多个终结点。如果我们构建和部署一个通过HTTP接收Text编码的消息应用的时候,我们也能够增加通过TCP接收二进制编码的消息的终结点.很大程度上,绑定是我们表示终结点消息基础结构的主要方式。第8章介绍了绑定的详细内容。
契约
契约把面向对象的结构映射为消息结构。更确切地说,契约定义了程序里的终结点、终结点使用的MEP和终结点处理的消息结构。例如,契约可以帮助我们把消息体的schema映射为.NET Framework类型定义,因此,可以简化那些产生匹配schema的消息的代码。WCF里定义了三种契约类型:服务契约、数据契约和消息契约。服务契约描述了终结点的操作。描述包含名称、MEP、会话规范信息、请求和响应的消息头和每个操作的安全信息。数据契约,换句话说,映射消息体到一个或者多个操作。消息契约映射消息体和消息头到一个或者多个操作。
注释:所有的契约都是有注释的类型或者类型定义,注释中使用的属性决定了这个类型定义是服务、数据或者消息契约。重要的是要记住注释一个类型或者成员定义只是简单地在类型的元数据增加一些信息。因此属性定义都是惰性的。要想确定特定属性的存在必须要求代码通过反射API查询元数据。在WCF契约里,WCF基础结构查询元数据的契约定义并基于元数据的内容执行操作。也可以手动完成这些工作,契约是可选择的。实际上说,WCF基础结构根据契约定义干的是有些无聊的工作,所以实际上你编写的WCF程序应该使用契约。我在第9章里详细介绍了这些内容。
通过类型注释构建一个契约本质上是晚绑定【老徐注释1】。虽然这是WCF提供给开发者扩展性和适应性的主要方式之一,它也意味着不一致性或者不兼容性或许只有在运行时才能捕获。
通过类型注释构建一个契约本质上是晚绑定【老徐注释1】。虽然这是WCF提供给开发者扩展性和适应性的主要方式之一,它也意味着不一致性或者不兼容性或许只有在运行时才能捕获。
服务契约
服务契约表示终结点暴露的操作,并且这些操作也被消息交换中的发送者和接受者使用。接受程序可以使用服务契约去构建侦听请求消息的基础结构。发送程序可以使用服务契约构建发送到消息接受终结点的消息结构。服务契约里的信息都包含每个操作的名字,操作的参数,
action头与操作、操作会话规范信息关联起来。
在元素级别,服务契约式一个被
ServiceContractAttribute或者OperationContractAttribute属性标记的类或者接口。ServiceContractAttribute可以使用在类和接口上,而OperationContractAttribute只能用在方法上。绝大部分标记了OperationContractAttribute的类型成员都会被ServiceContractAttribute标记,一个例外就是双工服务契约。重新提示一下,我会再第9章里详细说明契约问题。
数据契约
数据契约映射
.NET Framework类型到消息体。如果SOAP是选择的消息结构,数据契约就可以映射.NET Framework类型到SOAP消息体的schema。像任何WCF契约,数据契约也是一个标记类型定义,使用的属性就是DataContractAttribute 和DataMemberAttribute。大部分时间,服务契约使用数据契约,如下所示:
[ServiceContract]
interface ISomeServiceContract {
[OperationContract]
void SomeOperation(SomeDataContract info); // notice the argument type注意参数类型
}
[DataContract()]
sealed class SomeDataContract {
[DataMember]
Int32? number;
String status;
[DataMember] // must have getter and setter
internal String Status {
get { return status; }
set { status = value; }
}
internal Int32? Number {
get { return number; }
}
internal SomeDataContract(Int32? number) : this(number, null)
{
}
internal SomeDataContract(Int32? number, String status) {
this.number = number;
this.status = status; // consider the null case
}
}
interface ISomeServiceContract {
[OperationContract]
void SomeOperation(SomeDataContract info); // notice the argument type注意参数类型
}
[DataContract()]
sealed class SomeDataContract {
[DataMember]
Int32? number;
String status;
[DataMember] // must have getter and setter
internal String Status {
get { return status; }
set { status = value; }
}
internal Int32? Number {
get { return number; }
}
internal SomeDataContract(Int32? number) : this(number, null)
{
}
internal SomeDataContract(Int32? number, String status) {
this.number = number;
this.status = status; // consider the null case
}
}
在这个例子里,
ISomeServiceContract接口定义了一个可以接受SomeDataContract类型的方法。因为SomeDataContract被标记了DataContractAttribute,发送到SomeOperation操作的消息体将会包含一个符合SomeDataContract类型的schema.
消息契约
消息契约映射.NET Framework类型到消息结构上。如果XML是消息的结构,那么消息契约会映射.NET Framework类型到消息的schema上。这包含消息头和消息体,如下所示:
[ServiceContract]
interface ISomeServiceContract {
[OperationContract]
void SomeOperation(SomeDataContract info); // notice the argument type
[OperationContract]
void SomeOtherOperation(SomeMessageContract info); // notice the argument type
}
[DataContract()]
sealed class SomeDataContract {
[DataMember]
Int32? number;
String status;
[DataMember] // must have getter and setter
internal String Status {
get { return status; }
set { status = value; }
}
internal Int32? Number {
get { return number; }
}
internal SomeDataContract(Int32 number) : this(number, null)
{
}
internal SomeDataContract(Int32 number, String status) {
this.number = number;
this.status = status; // consider the null case
}
}
[MessageContract]
sealed class SomeMessageContract {
SomeMessageContract() { } // must have default constructor必须包含默认的构造函数
[MessageHeader]
Int32? SomeNumber;
[MessageBodyMember]
SomeDataContract messageBody;
internal SomeMessageContract(Int32? someNumber) {
SomeNumber = someNumber;
messageBody = new SomeDataContract(someNumber);
}
}
interface ISomeServiceContract {
[OperationContract]
void SomeOperation(SomeDataContract info); // notice the argument type
[OperationContract]
void SomeOtherOperation(SomeMessageContract info); // notice the argument type
}
[DataContract()]
sealed class SomeDataContract {
[DataMember]
Int32? number;
String status;
[DataMember] // must have getter and setter
internal String Status {
get { return status; }
set { status = value; }
}
internal Int32? Number {
get { return number; }
}
internal SomeDataContract(Int32 number) : this(number, null)
{
}
internal SomeDataContract(Int32 number, String status) {
this.number = number;
this.status = status; // consider the null case
}
}
[MessageContract]
sealed class SomeMessageContract {
SomeMessageContract() { } // must have default constructor必须包含默认的构造函数
[MessageHeader]
Int32? SomeNumber;
[MessageBodyMember]
SomeDataContract messageBody;
internal SomeMessageContract(Int32? someNumber) {
SomeNumber = someNumber;
messageBody = new SomeDataContract(someNumber);
}
}
注意到ISomeServiceContract接口的包含一个接受SomeMessageContract 类型参数的SomeOtherOperation的方法。这很正常因为SomeMessageContract 包含MessageContractAttribute的属性定义。这里是一些简单的介绍契约的内容,我们会再第9章里详细讨论这些主题。
【老徐注释】
1.早绑定指在对象申明的时候就和他的类型建立了关联,晚绑定是指我们的代码在运行时再检查对象是否提供了我们所需要的方法和属性。
早绑定的优点是:
- 编译效率
- 代码提示(代码智能感知)
- 编译时类型检查
晚绑定的优点是:
- 不用申明类型
- 对象类型可以随时更改
参考:http://space.baidu.com/onlyafar/blog/item/4d5171893ea995ba0e2444fa.html
本文转自 frankxulei 51CTO博客,原文链接:
http://blog.51cto.com/frankxulei/318603
,如需转载请自行联系原作者