WCF之消息

在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文件:

WCF之消息

二进制编码的Fruit.xml文件:

WCF之消息

MTOM编码的Fruit.xml文件:

WCF之消息

文本编码的消息:

WCF之消息

无消息版本信息本文本编码的消息:

下面看一个直接用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值,则默认为服务约定命名空间/约定名称(默认为接口名称)/操作名称(默认为方法名称)。
ReplyAction为“*”表示不向消息中添加答复操作。如果没有指定Action值,则默认为服务约定命名空间/约定名称(默认为接口名称)/操作名称(默认为方法名称)Response。
在客户端应用程序中指定星号可指示 不验证答复操作。

服务实现:

   
     
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 " ));
}
}
}

寄存服务:

   
     
using System;
using System.ServiceModel;
using IFruitService;

namespace WcfMessageHost
{
class Program
{
static void Main( string [] args)
{
using (ServiceHost host = new ServiceHost( typeof (FruitPriceService.FruitPriceService),
new Uri( " http://localhost:8000/Fruit " )))
{
host.AddServiceEndpoint(
typeof (IFruitPriceService), new BasicHttpBinding(), " 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 IFruitService;
using FruitModel;

namespace WcfMessageClient
{
class Program
{
static void Main( string [] args)
{
EndpointAddress epAddr
= new EndpointAddress( " http://localhost:8000/Fruit/FruitService " );
IFruitPriceService proxy
= ChannelFactory < IFruitPriceService > .CreateChannel( new BasicHttpBinding(), epAddr);

MessageHeader mHeader
= MessageHeader.CreateHeader( " FruitHeader " , " http://www.cnblogs.com/qiuwuyu " ,
 
new FruitHeader( " password " ));
Message message
= Message.CreateMessage(MessageVersion.Soap11, " * " , string .Empty);
message.Headers.Add(mHeader);
Message m
= proxy.GetFruit(message);
if (m.IsFault)
{
Console.WriteLine(m.ToString());
}
else
{
Fruit fruit
= m.GetBody < Fruit > ();
Console.WriteLine(
" Name: " + fruit.Name + " Price: " + fruit.Price);
}
Console.WriteLine(
" Fruit Client Is Running... " );
Console.ReadLine();
}
}
}
传入正确的HeaderKey的执行结果:

WCF之消息 传入错误的HeaderKey的执行结果:

WCF之消息 如果HeaderKey不正确可以返回一个FaultMessage,如下 FaultCode faultCode = new FaultCode("InvalidKey"); return Message.CreateMessage(m.Version,faultCode, "Invalid Key", "*"); 在客户端可以用IsFault判断是否是FaultMessage并进行一些相应的逻辑处理。

你可能感兴趣的:(WCF)