绑定提供了必要的元素来为客户端和服务端构建通讯信道。绑定描述了传输协议、消息编码格式以及其它用于通信信道的通信协议。通过绑定,WCF封装了各种不同通信场景下所使用的配置。每一个绑定配置都必须提供一个传输协议、一个消息编码格式和一个相关消息版本信息。
传输协议:可以是http、https、tcp、命名管道或msmq等。
消息编码:描述消息如何格式化。可以是binary、text、mtom。
消息版本:可以是soap1.1、soap1.2。消息版本还可以设置是否支持ws-addressing协议。在与非.net平台进行互操作时,应该注意消息版本的选择。
每个绑定都有若干个绑定元素组成,可以用以下代码查看默认绑定元素以及绑定所用的消息版本。
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Channels;
namespace WcfBinding
{
class Program
{
static void Main( string [] args)
{
OutPutBindingElements( new BasicHttpBinding());
OutPutBindingElements( new WSHttpBinding());
OutPutBindingElements( new NetTcpBinding());
OutPutBindingElements( new NetNamedPipeBinding());
OutPutBindingElements( new NetMsmqBinding());
Console.ReadLine();
}
static void OutPutBindingElements(Binding binding)
{
Console.WriteLine( " Binding:{0} " , binding.GetType().Name);
Console.WriteLine( " MessageVersion:{0} " , binding.MessageVersion);
BindingElementCollection elements = binding.CreateBindingElements();
foreach (BindingElement element in elements)
{
Console.WriteLine( " {0} " , element.GetType().FullName);
}
Console.WriteLine();
}
}
}
执行的结果如下:
从结果可以看出,只有BasicHttpBinding使用SOAP1.1而且是AddressingNone。其他绑定使用的都是SOAP1.2,Addressing10的消息版本。下面就写一些代码,查看下这两种消息格式格式化后的消息。为了方便的更换消息版本,使用CustomBinding类定义自定义绑定:
实体类:
using System.Runtime.Serialization;
namespace FruitModel
{
[DataContract(Namespace = " http://www.cnblogs.com/qiuwuyu " )]
public class Fruit
{
private string m_Name = string .Empty;
private string m_Price = string .Empty;
public Fruit( string name, string price)
{
m_Name = name;
m_Price = price;
}
[DataMember]
public string Name
{
get { return m_Name; }
set { m_Name = value; }
}
[DataMember]
public string Price
{
get { return m_Price;}
set { m_Price = value;}
}
}
[DataContract(Namespace = " http://www.cnblogs.com/qiuwuyu " )]
public class FruitHeader
{
private string m_HeaderKey = string .Empty;
[DataMember]
public string HeaderKey
{
get { return m_HeaderKey;}
set { m_HeaderKey = value;}
}
public FruitHeader( string key)
{
m_HeaderKey = key;
}
}
}
服务契约:
using System.ServiceModel;
using System.ServiceModel.Channels;
using FruitModel;
namespace IFruitService
{
[ServiceContract(Namespace = " http://www.cnblogs.com/qiuwuyu " )]
public interface IFruitPriceService
{
[OperationContract(Action = " * " ,ReplyAction = " * " )]
Message GetFruit(Message m);
}
}
服务实现:
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Channels;
using IFruitService;
using FruitModel;
namespace FruitPriceService
{
public class FruitPriceService : IFruitPriceService
{
public Message GetFruit(Message m)
{
Console.WriteLine(m.ToString());
Message message = Message.CreateMessage(m.Version, " * " , new Fruit( " banana " , " 6.00 " ));
MessageHeader mHeader = MessageHeader.CreateHeader( " FruitResponseHeader " ,
" http://www.cnblogs.com/qiuwuyu " , new FruitHeader( " Response " ));
message.Headers.Add(mHeader);
return message;
}
}
}
寄存服务:
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Text;
using IFruitService;
namespace WcfMessageHost
{
class Program
{
static void Main( string [] args)
{
using (ServiceHost host = new ServiceHost( typeof (FruitPriceService.FruitPriceService),
new Uri( " http://localhost:8000/ " )))
{
TextMessageEncodingBindingElement textElement = new TextMessageEncodingBindingElement(
MessageVersion.Soap12WSAddressing10, Encoding.UTF8);
CustomBinding customBind = new CustomBinding();
customBind.Elements.Add(textElement);
customBind.Elements.Add( new HttpTransportBindingElement());
host.AddServiceEndpoint( typeof (IFruitPriceService), customBind, " FruitService " );
host.Open();
Console.WriteLine( " Fruit Service Is Running... " );
Console.ReadLine();
}
}
}
}
客户端调用:
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Runtime.Serialization;
using System.Text;
using IFruitService;
using FruitModel;
namespace WcfMessageClient
{
class Program
{
static void Main( string [] args)
{
Console.WriteLine( " Fruit Client Is Running... " );
EndpointAddress epAddr = new EndpointAddress( " http://localhost:8000/FruitService " );
TextMessageEncodingBindingElement textElement = new TextMessageEncodingBindingElement(
MessageVersion.Soap12WSAddressing10, Encoding.UTF8);
CustomBinding customBind = new CustomBinding();
customBind.Elements.Add(textElement);
customBind.Elements.Add( new HttpTransportBindingElement());
IFruitPriceService proxy = ChannelFactory < IFruitPriceService > .CreateChannel(customBind, epAddr);
MessageHeader mHeader = MessageHeader.CreateHeader( " FruitHeader " , " http://www.cnblogs.com/qiuwuyu " ,
new FruitHeader( " password " ));
Message message = Message.CreateMessage(MessageVersion.Soap12WSAddressing10, " * " ,
new Fruit( " apple " , " 4.00 " ));
message.Headers.Add(mHeader);
Message m = proxy.GetFruit(message);
Console.WriteLine(m.ToString());
Console.ReadLine();
}
}
}
下面是MessageVersion.Soap11的请求消息:
MessageVersion.Soap11的返回消息:
把程序中相应的MessageVersion都更改MessageVersion.Soap12WSAddressing10后的请求消息:
MessageVersion.Soap12WSAddressing10后的返回消息:
从结果对比可以看出,两个版本的消息差别还是很大的。可以用BasicHttpBinding取代早期的asp.net web services服务而不会产生兼容问题,因为它采用的soap1.1以及早期安全标准。