zoukankan      html  css  js  c++  java
  • WCF 之 消息契约(MessageContract)

      对于SOAP来说主要由两部分构成Header和Body,他们两个共同构成了SOAP的信封,通常来说Body保存具体的数据内容,Header保存一些上下文信息或关键信息。

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

      由此可见,MessageContract的主要作用就是给我们提供了自己来操作SOAP的一种方式。

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

    一、[MessageContract]:

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

      如下面的代码:

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

    二、[MessageHeader]:

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

    三、[MessageBody]:

      [1] 应用到消息契约的域(fields)或者属性(properties)
      [2] 能够拥有多个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
    {
    }

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

    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; }
            }
        }
    }
    LinkItem

      重点看Message和Service代码:

    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; }
            }
        }
    }
    Message

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

    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);
        }
    }
    IService
    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
        }
    }
    Service

      客户端代码:

    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消息中去除。

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

  • 相关阅读:
    菜根谭#308
    菜根谭#307
    菜根谭#306
    菜根谭#305
    菜根谭#304
    菜根谭#303
    菜根谭#302
    菜根谭#301
    菜根谭#300
    菜根谭#299
  • 原文地址:https://www.cnblogs.com/xinaixia/p/5780329.html
Copyright © 2011-2022 走看看