WCF开发之消息契约(MessageContract)

对于SOAP来说主要由两部分构成Header和Body,他们两个共同构成了SOAP的信封,通常来说Body保存具体的数据内容,Header保存一些上下文信息或关键信息。比如:在一些情况下,具有这样的要求:当序列化一个对象并生成消息的时候,希望将部分数据成员作为SOAP的报头,部分作为消息的主体。比如说,我们有一个服务操作采用流的方式进行文件的上载,除了以流的方式传输以二进制表示的文件内容外,还需要传输一个额外的基于文件属性的信息,比如文件格式、文件大小等。一般的做法是将传输文件内容的流作为SOAP的主体,将其属性内容作为SOAP的报头进行传递。这样的功能,可以通过定义消息契约来实现。由此可见,MessageContract的主要作用就是给我们提供了自己来操作SOAP的一种方式。

MessageContractAttribute
– 对控制消息头和消息体元素提供了强力支持
所支持的属性:
– MessageHeaderAttribute
– MessageBodyMemberAttribute
用于:
– 添加自定义头(custom headers)
– 控制消息是否被包装
– 控制签名与加密

[MessageContract]:

• 将一个类型转换为SOAP消息
– 类型可以包含消息头和消息体的元素
• 能够设置IsWrapped, ProtectionLevel
• 可以设置显式Name, Namespace

如下面的代码:

[MessageContract(IsWrapped=true, ProtectionLevel=ProtectionLevel.Sign)]
public class SaveLinkRequest
{…}
[MessageContract]
public class SaveLinkResponse
{…}

[MessageHeader]:

• 应用到消息契约的域(fields)或者(
properties)
– 为创建自定义头提供了简单的方法
• 能够提供Name, Namespace, ProtectionLevel
• 可以设置SOAP协议的设置:Relay, Actor,MustUnderstand

[MessageBody]:

• 应用到消息契约的域(fields)或者属性(
properties)
• 能够拥有多个body元素
– 等价于在操作中拥有多个参数
– 返回多个复杂类型数据的唯一方法
• 总是提供顺序(Order)
• 可以设置Name, Namespace, ProtectionLevel

代码
[MessageContract(IsWrapped = true, ProtectionLevel = ProtectionLevel.Sign)]
public class SaveEventRequest
{
    
private string m_licenseKey;
    
private LinkItem m_linkItem;
    [MessageHeader(ProtectionLevel 
= ProtectionLevel.EncryptAndSign)]
    
public string LicenseKey
    {
        
get { return m_licenseKey; }
        
set { m_licenseKey = value; }
    }
    [MessageBodyMember]
    
public LinkItem LinkItem
    {
        
get { return m_linkItem; }
        
set { m_linkItem = value; }
    }
}
[MessageContract]
public class SaveEventResponse
{
}

 

那么如何应用消息契约那?不要急,下面来介绍,还是来看代码吧:

 

LinkItem 代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;

namespace ContentTypes
{
    [DataContract]
    
public class LinkItem
    {
        
private long m_id;
        
private string m_title;
        
private string m_description;
        
private DateTime m_dateStart;
        
private DateTime m_dateEnd;
        
private string m_url;

        [DataMember]
        
public long Id
        {
            
get { return m_id; }
            
set { m_id = value; }
        }

        [DataMember]
        
public string Title
        {
            
get { return m_title; }
            
set { m_title = value; }
        }
        [DataMember]
        
public string Description
        {
            
get { return m_description; }
            
set { m_description = value; }
        }
        [DataMember]
        
public DateTime DateStart
        {
            
get { return m_dateStart; }
            
set { m_dateStart = value; }
        }
        [DataMember]
        
public DateTime DateEnd
        {
            
get { return m_dateEnd; }
            
set { m_dateEnd = value; }
        }
        [DataMember]
        
public string Url
        {
            
get { return m_url; }
            
set { m_url = value; }
        }
    }
}

 

重点看Message和Service代码:

Message代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using ContentTypes;

namespace WcfServiceLibraryDemo
{
    [MessageContract(IsWrapped 
= false)]
    
public class SaveGigRequest
    {
        
private LinkItem m_linkItem;

        [MessageBodyMember]
        
public LinkItem Item
        {
            
get { return m_linkItem; }
            
set { m_linkItem = value; }
        }
    }

    [MessageContract(IsWrapped 
= false)]
    
public class SaveGigResponse
    {
    }

    [MessageContract(IsWrapped 
= false)]
    
public class GetGigRequest
    {
        
private string m_licenseKey;

        [MessageHeader]
        
public string LicenseKey
        {
            
get { return m_licenseKey; }
            
set { m_licenseKey = value; }
        }
    }

    [MessageContract(IsWrapped 
= false)]
    
public class GetGigResponse
    {
        
private LinkItem m_linkItem;

        
public GetGigResponse()
        {
        }

        
public GetGigResponse(LinkItem item)
        {
            
this.m_linkItem = item;
        }

        [MessageBodyMember]
        
public LinkItem Item
        {
            
get { return m_linkItem; }
            
set { m_linkItem = value; }
        }
    }
}

 

只要记住一条就行了,凡是有[MessageHeader]或[MessageBody]的那些属性,它们就是在客户端调用服务相应方法的参数。

 

IGigManagerService代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using ContentTypes;

namespace WcfServiceLibraryDemo
{
    [ServiceContract(Name 
= "GigManagerServiceContract", Namespace = "http://www.cnblogs.com/Charlesliu", SessionMode = SessionMode.Required)]
    
public interface IGigManagerService
    {
        [OperationContract]
        SaveGigResponse SaveGig(SaveGigRequest requestMessage);

        [OperationContract]
        GetGigResponse GetGig(GetGigRequest requestMessage);
    }
}

 

 

GigManagerService代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using ContentTypes;

namespace WcfServiceLibraryDemo
{
    [ServiceBehavior(InstanceContextMode 
= InstanceContextMode.PerSession)]
    
public class GigManagerService : IGigManagerService
    {

        
private LinkItem m_linkItem;

        
#region IGigManager Members

        
public SaveGigResponse SaveGig(SaveGigRequest requestMessage)
        {
            m_linkItem 
= requestMessage.Item;
            
return new SaveGigResponse();
        }

        
public GetGigResponse GetGig(GetGigRequest requestMessage)
        {
            
if (requestMessage.LicenseKey != "XXX")
                
throw new FaultException("Invalid license key.");

            
return new GetGigResponse(m_linkItem);
        }

        
#endregion
    }
}

 

客户端代码:

 

Form1代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using WinTest.MyServiceReference;

namespace WinTest
{
    
public partial class Form1 : Form
    {
        MyServiceReference.GigManagerServiceContractClient m_proxy 
= new WinTest.MyServiceReference.GigManagerServiceContractClient();

        
public Form1()
        {
            InitializeComponent();
        }

        
private void cmdSave_Click(object sender, EventArgs e)
        {
            LinkItem item 
= new LinkItem();

            item.Id 
= int.Parse(this.txtId.Text);
            item.Title 
= this.txtTitle.Text;
            item.Description 
= this.txtDescription.Text;
            item.DateStart 
= this.dtpStart.Value;
            item.DateEnd 
= this.dtpEnd.Value;
            item.Url 
= this.txtUrl.Text;

            m_proxy.SaveGig(item);
        }

        
private void cmdGet_Click(object sender, EventArgs e)
        {
            LinkItem item 
= m_proxy.GetGig("XXX");
            
if (item != null)
            {
                
this.txtId.Text = item.Id.ToString();
                
this.txtTitle.Text = item.Title;
                
this.txtDescription.Text = item.Description;

                
if (item.DateStart != DateTime.MinValue)
                    
this.dtpStart.Value = item.DateStart;
                
if (item.DateEnd != DateTime.MinValue)
                    
this.dtpEnd.Value = (DateTime)item.DateEnd;

                
this.txtUrl.Text = item.Url;
            }
        }
    }
}

 

IsWrapped、WrapperName、WrapperNamespace:IsWrapped表述的含义是是否为定义的主体成员(一个或者多个)添加一个额外的根节点。WrapperName和WrapperNamespace则表述该根节点的名称和命名空间。IsWrapped、WrapperName、WrapperNamespace的默认是分别为true、类型名称和http://tempuri.org/。如果我们将IsWrapped的属性设为false,那么套在Address节点外的Customer节点将会从SOAP消息中去除。

我们在使用中发现一个特点,用这种方式序列化的实体类不能当作参数直接传递,客户端会把对象的一个参数拆分为多个属性作为参数。(完)

posted @ 2010-02-08 16:41  烟鬼  阅读(3328)  评论(0编辑  收藏  举报