WCF绑定及不同消息版本的SOAP样式

绑定提供了必要的元素来为客户端和服务端构建通讯信道。绑定描述了传输协议、消息编码格式以及其它用于通信信道的通信协议。通过绑定,WCF封装了各种不同通信场景下所使用的配置。每一个绑定配置都必须提供一个传输协议、一个消息编码格式和一个相关消息版本信息。

传输协议:可以是http、https、tcp、命名管道或msmq等。

消息编码:描述消息如何格式化。可以是binary、text、mtom。

消息版本:可以是soap1.1、soap1.2。消息版本还可以设置是否支持ws-addressing协议。在与非.net平台进行互操作时,应该注意消息版本的选择。

每个绑定都有若干个绑定元素组成,可以用以下代码查看默认绑定元素以及绑定所用的消息版本。

using System;
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;
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;
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;
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;
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;
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以及早期安全标准。

posted @ 2011-04-18 08:10  秋无语  阅读(1693)  评论(0编辑  收藏  举报