• WCF契约之---服务契约 、数据契约、 消息契约


    本篇博文只是简单说下WCF中的契约的种类、作用以及一些简单的代码示例。在WCF中契约分为服务契约、数据契约和消息契约。下面对这几种契约进行简单的介绍。

    服务契约

    服务契约描述了暴露给外部的类型(接口或类)、服务所支持的操作、使用的消息交换模式和消息的格式。每个WCF服务必须实现至少一个服务契约。使用服务契约必须要引用命名空间System.ServiceModel 。服务契约中常用到的三个特性:

    ServiceContractAttribute

    该特性定义在类或接口上,用来描述一个相关操作的集合。ServiceContractAttribute特性还有如下的一些属性值可以设置:

    Name:给服务契约定义一个名称,而不是使用接口或是类的类型名,在客户端添加服务引用时会用到。

    Namespace:命名空间,默认值为http://tempuri.org。

    CallbackContract:将另一个服务契约定义为回调契约,使得客户端可以接收服务端的异步消息。

    ProtectionLevel:控制契约中发送给消息的保护方式是否需要被签名和加密。该属性为System.Net.Security.ProtectionLevel枚举类型。

    SessionMode:确定会话是否为公开服务契约的端点所支持。

    ConfigurationName:服务的配置名称。

    [ServiceContract(Name="HelloWorld",Namespace="http://oec2003.cnblogs.com"]
    public interface IHelloWorldService
    { 
    
    }
    OperationContractAttribute

    用OperationContractAttribute标记的方法即为一个服务操作,简单的使用该特性就可以让一个方法加入到服务契约的操作队列中,可以被客户端所调用。该特性也有一些设置消息交换方式的属性。如下

    Name:定义一个操作名称,而不是使用方法名称。

    Action:该操作消息的动作标题。

    ReplyAction:响应该操作消息的动作标题。

    IsOneWay:设置该操作是否单向和没有回复,如果操作是单向的,将不支持ReplyAction。

    ProtectionLevel:允许你控制特定的操作消息是否被保护,操作中的ProtectionLevel属性将覆盖服务契约中的ProtectionLevel。该属性为System.Net.Security.ProtectionLevel枚举类型。

    IsInitiating:操作是否可以用来初始化会话。

    IsTerminating:操作是否中止一个会话。

    AsyncPattern:将服务操作定义为异步实现模式。

    [ServiceContract(Namespace="http://oec2003.cnblogs.com",Name="oec2003",
        ConfigurationName="IHelloWorldService")]
    public interface IHelloWorldService
    {
        [OperationContract(Name="oec2003SayHello",
            Action = "http://oec2003.cnblogs.com/IHelloWorldService/Hello",
            ReplyAction = "http://oec2003.cnblogs.com/IHelloWorldService/HelloReply")]
        string SayHello();
    }
    MessageParameterAttribute

    使用 MessageParameterAttribute 可以控制参数或返回值的名称。此属性对于已用 MessageContractAttribute 特性标记的参数无效。该特性只有一个Name属性,看如下代码:

    [ServiceContract(Namespace="http://oec2003.cnblogs.com",Name="oec2003",
        ConfigurationName="IHelloWorldService")]
    public interface IHelloWorldService
    {
        [OperationContract]
        [return: MessageParameter(Name = "responseString")]
        string SayHello([MessageParameter(Name = "string")]string meg);
    }

     

    数据契约

    使用数据契约必须引用System.Runtime.Serialization命名空间,在类型上使用DataContractAttribute可以创建数据契约,类型中的成员使用DataMember标记。代码如下:

    [DataContract]
    public class User
    {
        [DataMember]
        public int Age { get; set; }
        [DataMember]
        public string Name { get; set; }
        [DataMember]
        public string Email { get; set; }
    }
    DataContractAttribute

    DataContractAttribute特性定义在类型之上,类型包括类、结构、枚举但不包括接口。DataContractAttribute特性不能被继承,即继承自有DataContractAttribute特性标记的类并不是数据契约,必须显示使用DataContractAttribute标记才能成为数据契约。DataContractAttribute特性有IsReference、Name和Namespace三个属性:

    IsReference:bool类型,表示在进行序列化的时候是否保持对象现有的引用结构。

    Name:名称。

    Namespace:命名空间。

    [DataContract(IsReference=true,Name="MyUser",Namespace="http://oec2003.cnblogs.com")]
    public class User
    {
        [DataMember]
        public int Age { get; set; }
        [DataMember]
        public string Name { get; set; }
        [DataMember]
        public string Email { get; set; }
    }
    DataMemberAttribute

    使用DataMemberAttribute标记的类型成员才能成为数据契约的数据成员。这个和服务契约中的OperationContractAttribute类似。DataMemberAttribute特性有如下四个属性:

    EmitDefaultValue:表明在数据成员的值等于默认值的情况下,是否还须要将其序列化到最终的XML中,默认值为true,表示默认值会参与序列化。

    IsRequired:bool类型,表明属性成员是否是必须的成员,默认值为false。

    Name:数据成员的别名。

    Order:相应的数据成员在最终序列化的XML中出现的位置,默认是按字母顺序排列的。

    [DataContract(IsReference=true,Name="MyUser",Namespace="http://oec2003.cnblogs.com")]
    public class User
    {
        [DataMember(EmitDefaultValue=true,IsRequired=true,
            Name="Oec2003_Age",Order=1)]
        public int Age { get; set; }
        [DataMember(EmitDefaultValue = true, IsRequired = true, 
            Name = "Oec2003_Name", Order = 2)]
        public string Name { get; set; }
        [DataMember(EmitDefaultValue = true, IsRequired = false, 
            Name = "Oec2003_Email", Order = 3)]
        public string Email { get; set; }

     

    消息契约

    使用消息契约必须引用System.ServiceModel命名空间,消息契约和数据契约一样都是定义在数据类型上。和数据契约不同的是消息契约更多的是关注数据成员在SOAP消息中的表示。定义一个消息契约需要用到MessageContractAttribute特性,另外还涉及到MessageHeaderAttribute和MessageBodyMemberAttribute这两个特性,MessageContractAttribute特性标记在类型上,MessageHeaderAttribute和MessageBodyMemberAttribute特性标记在数据成员上。

    [MessageContract]
    public class MessageTest
    {
        [MessageHeader]
        public int Age { get; set; }
        [MessageHeader]
        public string Name { get; set; }
        [MessageBodyMember]
        public string Email { get; set; }
    }
    MessageContractAttribute

    通过在一个类型上使用MessageContractAttribute标记可以使之成为一个消息契约。MessageContractAttribute特性含有如下几个属性:

    IsWrapped:是否为定义的主体成员(一个或者多个)添加一个额外的根节点。

    WrapperName:根节点的名称。

    WrapperNamespace:根节点的命名空间。

    ProtectionLevel:表示保护级别,WCF中通过System.Net.Security.ProtectionLevel枚举定义消息的保护级别。一般有3种可选的保护级别:None、Sign和EncryptAndSign。

    [MessageContract(IsWrapped=false,WrapperName="MyMessage",
        WrapperNamespace="http://oec2003.com")]
    public class MessageTest
    {
        //省略
    }
    MessageHeaderAttribute

     

    使用MessageHeaderAttribute标记的数据成员将会出现在SOAP消息的头部,该特性包含下面几个属性:

    Actor:为一个URI值,表示处理该报头的目标节点。

    MustUnderstand:bool类型,表明Actor定义的节点是否必须理解并处理该节点。

    Name:名称。

    Namespace:命名空间。

    ProtectionLevel:表示保护级别。

    Relay:表明该报头是否需要传递到下一个SOAP节点。

    [MessageContract]
    public class MessageTest
    {
        [MessageHeader(Actor="http://oec2003.com/Age",MustUnderstand=true,Name="MyAge",
            Namespace="http://oec2003.com",Relay=true)]
        public int Age { get; set; }
        [MessageHeader]
        public string Name { get; set; }
    }
    MessageBodyMemberAttribute

    使用MessageHeaderAttribute标记的数据成员将会出现在SOAP消息的主体部分,该特性包含下面的属性:

    Order:Order属性用来控制成员在SOAP主体部分中出现的位置,默认按字母顺序排列。

    Name:名称。

    Namespace:命名空间。

    ProtectionLevel:表示保护级别。

    [MessageContract(IsWrapped=false,WrapperName="MyMessage",
        WrapperNamespace="http://oec2003.com")]
    public class MessageTest
    {
        [MessageBodyMember(Order = 1)]
        public string Email { get; set; }
    }

    本文对WCF的服务契约、数据契约和消息契约进行了简单的介绍,并对使用这些契约所要用到的特性以及特性里的属性进行了说明,有关跟深入的应用将在以后的博文中介绍。




    附:

    (转载:http://www.cnblogs.com/zhangdong/archive/2010/01/13/1646463.html

    这里再附加一个实例(将消息契约讲的很详细)

    实例:

     

    定义一个类型化消息契约:

    image_thumb11

    PriceDetails类:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace DefiningATypedMessageContract
    {
        [Serializable]
        public class PriceDetails
        {
            public string Ticker;
            public double Amount;
        }
    }
    返回的查询结果StockPrice类:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    
    namespace DefiningATypedMessageContract
    {
        [MessageContract]
        public class StockPrice
        {
            [MessageHeader]
            public DateTime CurrentTime;
            [MessageBodyMember]
            public PriceDetails Price;
        }
    }
    传入的查询条件StockPriceReq类:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    
    namespace DefiningATypedMessageContract
    {
        [MessageContract]
        public class StockPriceReq
        {
            [MessageBodyMember]
            public string Ticker;
        }
    }
    服务契约的接口IStockService:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.Serialization;
    using System.ServiceModel;
    using System.Text;
    
    namespace DefiningATypedMessageContract
    {
        [ServiceContract]
        public interface IStockService
        {
            // TODO: Add your service operations here
            [OperationContract]
            StockPrice GetPrice(StockPriceReq req);
        }
    }

    服务契约接口的实现类StockService:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.Serialization;
    using System.ServiceModel;
    using System.Text;
    
    namespace DefiningATypedMessageContract
    {
        public class StockService : IStockService
        {
    
            #region IStockService Members
    
            public StockPrice GetPrice(StockPriceReq req)
            {
                StockPrice resp = new StockPrice();
                resp.Price = new PriceDetails();
                resp.Price.Ticker = req.Ticker;
                resp.Price.Amount = 94.85;
                return resp;
            }
    
            #endregion
        }
    }

    运行解决方案如下调用:

    image_thumb3

    下面代码展示了从服务端返回给客户端的SOAP消息的XML形式。注意,[MessageHeader]元素——CurrentTime出现在了SOAP头中;而[MessageBodyMember]元素——Price出现在了SOAP体中。

    <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
      <s:Header>
        <a:Action s:mustUnderstand="1" u:Id="_2">http://tempuri.org/IStockService/GetPriceResponse</a:Action>
        <h:CurrentTime u:Id="_3" xmlns:h="http://tempuri.org/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">0001-01-01T00:00:00</h:CurrentTime>
        <a:RelatesTo u:Id="_5">urn:uuid:20c2b591-56a2-401a-9ddf-f5cf2b9d3bcd</a:RelatesTo>
        <o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
          <u:Timestamp u:Id="uuid-828dfadf-95d0-497e-8996-5f84d037bae5-11">
            <u:Created>2009-11-02T07:53:57.857Z</u:Created>
            <u:Expires>2009-11-02T07:58:57.857Z</u:Expires>
          </u:Timestamp>
          <c:DerivedKeyToken u:Id="uuid-828dfadf-95d0-497e-8996-5f84d037bae5-7" xmlns:c="http://schemas.xmlsoap.org/ws/2005/02/sc">
            <o:SecurityTokenReference>
              <o:Reference URI="urn:uuid:facde5e3-64d3-4108-a35c-9ac518486273" ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/sct" />
            </o:SecurityTokenReference>
            <c:Offset>0</c:Offset>
            <c:Length>24</c:Length>
            <c:Nonce>p852F8YOk3onS1iWmr9ZfQ==</c:Nonce>
          </c:DerivedKeyToken>
          <c:DerivedKeyToken u:Id="uuid-828dfadf-95d0-497e-8996-5f84d037bae5-8" xmlns:c="http://schemas.xmlsoap.org/ws/2005/02/sc">
            <o:SecurityTokenReference>
              <o:Reference URI="urn:uuid:facde5e3-64d3-4108-a35c-9ac518486273" ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/sct" />
            </o:SecurityTokenReference>
            <c:Nonce>/aQ2tCk/IZKkgpF5NlWucg==</c:Nonce>
          </c:DerivedKeyToken>
          <e:ReferenceList xmlns:e="http://www.w3.org/2001/04/xmlenc#">
            <e:DataReference URI="#_1" />
            <e:DataReference URI="#_4" />
            <e:DataReference URI="#_6" />
          </e:ReferenceList>
          <e:EncryptedData Id="_6" Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns:e="http://www.w3.org/2001/04/xmlenc#">
            <e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc" />
            <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
              <o:SecurityTokenReference>
                <o:Reference ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/dk" URI="#uuid-828dfadf-95d0-497e-8996-5f84d037bae5-8" />
              </o:SecurityTokenReference>
            </KeyInfo>
            <e:CipherData>
              <e:CipherValue>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</e:CipherValue>
            </e:CipherData>
          </e:EncryptedData>
        </o:Security>
      </s:Header>
      <s:Body u:Id="_0">
        <StockPrice xmlns="http://tempuri.org/">
          <Price xmlns:a="http://schemas.datacontract.org/2004/07/DefiningATypedMessageContract" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
            <a:Amount>94.85</a:Amount>
            <a:Ticker>Chinasofti</a:Ticker>
          </Price>
        </StockPrice>
      </s:Body>
    </s:Envelope>

    版权声明:本文为博主原创文章,欢迎转载,转载请注明出处。

  • 相关阅读:
    水池问题的lua语言算法(面试题分析:我的Twitter技术面试失败了)
    grep
    hdu 4455 Substrings(计数)
    Concurrency Programming Guide 并发设计指引(二)
    ASP.NET 预编译命令(解决发布后第一次访问慢问题)
    将浏览页面变为可编辑状态
    windows系统上利用putty通过SSH连接亚马逊AWS服务器
    SQL Server2008 R2 数据库镜像实施手册(双机)SQL Server2014同样适用
    非域环境下使用证书部署数据库(SqlServer2008R2)镜像
    遇到问题---hosts不起作用问题的解决方法
  • 原文地址:https://www.cnblogs.com/Percy_Lee/p/4827017.html
Copyright © 2020-2023  润新知