在WCF中客户端与服务端都是靠消息进行传输的,消息格式和SOAP一样,具有消息标头和正文。客户端和服务端之间的所有通讯最终都会产生System.ServiceModel.Channels. Message
实例。在平时操作中,很少直接操作Message类型,而是通过WCF服务模型构造(如数据契约、消息契约和操作契约)来描述传入消息和传出消息。所以,要想透彻的理解WCF有必要对Message多些了解。下面看一个简单的类,来了解一下Message用到的类。
using System;
using System.ServiceModel;
using System.Runtime.Serialization;
using System.IO;
using System.Xml;
using System.Text;
using System.ServiceModel.Channels;
namespace WcfMessage
{
[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;
}
}
class Program
{
static void Main(string[] args)
{
Fruit fruit = new Fruit("banana", "6.00");
//把Fruit类型序列化为xml文件
using (FileStream fs = new FileStream("Fruit.xml", FileMode.Create))
{
DataContractSerializer dataSer = new DataContractSerializer(typeof(Fruit));
dataSer.WriteObject(fs, fruit);
}
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("Fruit.xml");
//用二进制编码的xml文档
using (FileStream binStream = new FileStream("Fruit.bin", FileMode.Create))
{
using (XmlWriter xw = XmlDictionaryWriter.CreateBinaryWriter(binStream))
{
xmlDoc.WriteContentTo(xw);
}
}
//用mtom编码的xml文档
using (FileStream mtomStream = new FileStream("Fruit.mtom", FileMode.Create))
{
using (XmlWriter xw = XmlDictionaryWriter.CreateMtomWriter(mtomStream, Encoding.UTF8, 1024, "text/xml"))
{
xmlDoc.WriteTo(xw);
}
}
//创建一消息,并用文本编码的消息
Message message1 = Message.CreateMessage(MessageVersion.Soap11WSAddressingAugust2004, "*", fruit);
MessageHeader mHeader = MessageHeader.CreateHeader("FruitHeader", "http://www.cnblogs.com/qiuwuyu",
new FruitHeader("password"));
message1.Headers.Add(mHeader);
using (FileStream stream = new FileStream("FruitMessageHeader.xml", FileMode.Create))
{
using (XmlWriter xw = XmlDictionaryWriter.CreateTextWriter(stream))
{
message1.WriteMessage(xw);
}
}
//创建一个没有消息版本,并用文本编码的消息
Message message = Message.CreateMessage(MessageVersion.None, "*", new XmlNodeReader(xmlDoc));
using (FileStream stream = new FileStream("FruitMessageNone.xml", FileMode.Create))
{
using (XmlWriter xw = XmlDictionaryWriter.CreateTextWriter(stream))
{
message.WriteMessage(xw);
}
}
}
}
}
XmlDictionary是定义了一个私有的可以表示SOAP消息中元素名字、属性和XML namespace声明的key-value列表的字典结构。字典在常见文本字符串和整数之间建立映射,并为压缩和解压缩XML提供一种有效机制。XmlDictionaryWriter是WCF中一个优化的读取XML编写器。
执行上述代码后,查看生成文件。
Fruit.xml文件:
二进制编码的Fruit.xml文件:
MTOM编码的Fruit.xml文件:
文本编码的消息:
无消息版本信息本文本编码的消息:
下面看一个直接用Message写的小实例,从整体上感觉下。
服务契约:
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);
}
}
Action指定为“*”表示可以处理服务端接收到的任何消息。如果没有指定Action值,则默认为服务约定命名空间/约定名称(默认为接口名称)/操作名称(默认为方法名称)。
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)
{
if ( OperationContext.Current.IncomingMessageHeaders.GetHeader<FruitHeader>(0).HeaderKey!="password" )
{
FaultCode faultCode = new FaultCode("Invalid Key");
return Message.CreateMessage(m.Version, faultCode, "Invalid Key", "*");
}
return Message.CreateMessage(m.Version, "*", new Fruit("banana", "6.00"));
}
}
}