WCF服务要通过终结点来进行通信,终结点三大构成元素:ABC,其中的B,binding是重中之重,它解决了在消息交换过程中的编码,传输协议,安全等问题。
绑定是分层的,一个绑定对象对应一组有序的绑定元素的集合。每层的元素专门处理其中某领域内的事务,来负责终结点通信中的其中一方面。这里给出绑定对象的绑定元素的层表:
层 |
选项 |
是否必需 |
事务流 |
TransactionFlowBindingElement |
否 |
可靠性 |
ReliableSessionBindingElement |
否 |
安全性 |
对称、非对称、传输级 |
否 |
形状更改 |
CompositeDuplexBindingElement |
否 |
传输升级 |
SSL 流、Windows 流、对等解析程序 |
否 |
编码 |
文本、二进制、MTOM、自定义 |
是 |
传输 |
TCP、命名管道、HTTP、HTTPS、MSMQ、自定义 |
是 |
其中的编码层和传输层是必须的。系统提供了足够多的绑定类型:
绑定 |
互操作性 |
安全模式(默认) |
会话(默认) |
事务 |
双工 |
BasicHttpBinding |
Basic Profile 1.1 |
(无)、传输、消息、混合 |
无、(无) |
(无) |
n/a |
WSHttpBinding |
WS |
无、传输、(消息)、混合 |
(无)、传输、可靠会话 |
(无)、是 |
n/a |
WS2007HttpBinding |
WS-Security、WS-Trust、WS-SecureConversation、WS-SecurityPolicy |
无、传输、(消息)、混合 |
(无)、传输、可靠会话 |
(无)、是 |
n/a |
WSDualHttpBinding |
WS |
无、(消息) |
(可靠会话) |
(无)、是 |
是 |
WSFederationHttpBinding |
WS-Federation |
无、(消息)、混合 |
(无)、可靠会话 |
(无)、是 |
否 |
WS2007FederationHttpBinding |
WS-Federation |
无、(消息)、混合 |
(无)、可靠会话 |
(无)、是 |
否 |
NetTcpBinding |
.NET |
无、(传输)、消息、混合 |
可靠对话、(传输) |
(无)、是 |
是 |
NetNamedPipeBinding |
.NET |
无、(传输) |
无、(传输) |
(无)、是 |
是 |
NetMsmqBinding |
.NET |
无、消息、(传输)、两者 |
(无) |
(无)、是 |
否 |
NetPeerTcpBinding |
对等 |
无、消息、(传输)、混合 |
(无) |
(无) |
是 |
MsmqIntegrationBinding |
MSMQ |
无、(传输) |
(无) |
(无)、是 |
n/a |
从这个表中可知:BasicHttpBinding类型只有两层绑定元素。
验证一下:
public void TestBindingElements()
{
BasicHttpBinding _binding = new BasicHttpBinding();
BindingElementCollection eles=
_binding.CreateBindingElements();
foreach (BindingElement ele in eles)
Console.WriteLine(ele.ToString());
}
结果:
System.ServiceModel.Channels.TextMessageEncodingBindingElement
System.ServiceModel.Channels.HttpTransportBindingElement
因为每种绑定类型的绑定元素构成的不同,在应用中会有很大不同。例如基础绑定类型:它不支持双工通信,不支持事务和会话服务。
(一) 通过绑定对象的属性进行消息的控制
绑定对象有多个属性用于控制消息。例如基础绑定:
·EnvelopeVersio:获取此绑定处理的消息将要使用的 SOAP 版本。
·MessageEncoding:获取或设置是使用 MTOM 还是文本对 SOAP 消息进行编码。
·MessageVersion:获取由绑定所配置的客户端和服务使用的消息版本。
·Name:获取或设置绑定的名称。
·Namespace:获取或设置绑定的 XML 命名空间。
·Security:获取与此绑定一起使用的安全类型。
·TextEncoding:获取或设置用于消息文本的字符编码。
设置绑定的名字:Name。设置可以在配置文件中配置也可以在自托管宿主程序中通过程序设置。
(二) 契约
契约提供消息的标准,交换的消息的规则。在WCF中,契约分4类:
·服务契约
·数据契约
·异常契约
·消息契约
(1)服务契约
服务契约分2种,
一种是用在接口或类上的服务契约,
[ServiceContract(Namespace="www.self001.com")]
public interface IFirstService
例如:CallbackContract用于在支持双工交换的绑定里设置回调类型
SessionMode,用于设置或取得会话的状态
Name用于设置或取得wsdl上的<portType>元素的名称
另一种是用在方法上的操作契约:
[OperationContract(Action="selfAction")]
void DoWork(string strContent);
例如:设置
IsOneWay,用于设置或取得是否进行单向消息交换
Name,用于设置或取得操作的名称
通过对它们的属性修饰达到对服务的约束和设置。
在BasicHttpBinding中,默认的消息交换模式为RR。现在为DoWork添加单向交换标志:
[OperationContract(IsOneWay=true)]
void DoWork(string strContent);
那么在请求服务时,只有去的消息,而不返回消息。
(2)数据契约
主要用于数据的序列化。对于基元类型,wcf自动序列化并默认拥有数据契约。对复杂类型要进行序列化。(在WCF对复杂类型不用显示添加数据契约,但如果添加了,那么所有的数据契约都要添加)
数据的序列化为了传输和存储,可见:
http://www.cnblogs.com/jams742003/archive/2010/03/31/1701184.html
[DataContract]
public class Customer
{
[DataMember]
public int Unid { get; set; }
[DataMember]
public string UserName { get; set; }
[DataMember]
public DateTime CreateTime { get; set; }
}
同样的,数据契约也用于不同的地方:
[DataContract]
public class Customer
通过属性的设置来设置数据契约的细节,例如Namespace
在没设置之前:
<s:Body>
<GetCustomerResponse xmlns="www.self001.com">
<GetCustomerResult
xmlns:a="http://schemas.datacontract.org/2004/07/"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:CreateTime>2010-04-01T00:00:00</a:CreateTime>
<a:Unid>2</a:Unid>
<a:UserName>Songjiang</a:UserName>
</GetCustomerResult>
</GetCustomerResponse>
</s:Body>
设置:
[DataContract(Namespace="selfdata.com")]
public class Customer
之后的情况是:
<s:Body>
<GetCustomerResponse xmlns="www.self001.com">
<GetCustomerResult
xmlns:a="selfdata.com"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:CreateTime>2010-04-01T00:00:00</a:CreateTime>
<a:Unid>2</a:Unid>
<a:UserName>Songjiang</a:UserName>
</GetCustomerResult>
</GetCustomerResponse>
</s:Body>
可以看到其中的变化。
[DataMember]
public int Unid { get; set; }
通过添加DataMember标签,指定这个成员作为数据契约的一部分,且可以被序列化。它的属性例如:
Order:获取或设置成员的序列化和反序列化顺序
Name:获取或设置数据成员的名称
[DataMember(Name="SelfId")]
public int Unid { get; set; }
<s:Body>
<GetCustomerResponse xmlns="www.self001.com">
<GetCustomerResult
xmlns:a="selfdata.com"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:CreateTime>2010-04-01T00:00:00</a:CreateTime>
<a:SelfId>2</a:SelfId>
<a:UserName>Songjiang</a:UserName>
</GetCustomerResult>
</GetCustomerResponse>
</s:Body>
(3)异常契约
异常契约用于soap消息的异常。
[OperationContract]
[FaultContract(typeof(string))]
void SelfException();
public void SelfException()
{
throw new FaultException<string>
("error 007!","reason:Testing!");
}
客户端:
public void TestFault()
{
FirstInstance.FirstServiceClient client =
new FirstInstance.FirstServiceClient();
try
{
client.SelfException();
}
catch (FaultException<string> ex)
{
Console.WriteLine(ex.Reason+" "+
ex.Detail.ToString());
}
}
打印信息:reason:Testing! error 007!
包信息:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<s:Fault>
<faultcode>s:Client</faultcode>
<faultstring xml:lang="zh-CN">
reason:Testing!
</faultstring>
<detail>
<string
xmlns="http://schemas.microsoft.com/2003/10/Serialization/">
error 007!
</string>
</detail>
</s:Fault>
</s:Body>
</s:Envelope>
(4)消息契约
通过消息契约可以设置消息包体的多个选项,用于对包体中的类型进行强制设置。
[MessageContract(WrapperName="SelfCustomer")]
public class Customer
{
[MessageBodyMember]
public int Unid { get; set; }
[MessageBodyMember]
public string UserName { get; set; }
[MessageBodyMember]
public DateTime CreateTime { get; set; }
}
客户端的用法就不同了:
public void TestCustomer()
{
FirstInstance.Customer customer =
new FirstInstance.Customer();
FirstInstance.FirstServiceClient client =
new FirstInstance.FirstServiceClient();
int iUnid;
string strUserName;
client.GetCustomer(out iUnid,out strUserName);
}
看包:
<s:Body>
<SelfCustomer xmlns="www.self001.com">
<CreateTime>2010-04-01T00:00:00</CreateTime>
<Unid>2</Unid>
<UserName>Songjiang</UserName>
</SelfCustomer>
</s:Body>