• WCF入门(二)——终结点,契约(2)


    Contract

    契约,用于提供消息的标准,消息交换的规则。它分四类:

    ·服务契约 定义操作

    ·数据契约 定义数据

    ·异常契约 定义异常

    ·消息契约 定义消息格式

    (一)服务契约

    服务契约,可以用接口定义,也可以直接在类上定义。

    例如:

    [ServiceContract]

    public interface ICaculateService

    它有很多可选属性,例如:

    NameNamespaceCallbackContractSessionMode等等。这里来从包中来演示一下:

    契约:

    [ServiceContract]

    public interface ICaculateService

    {

    [OperationContract]

    int Devide(int a, int b);

    }

    上边的契约没有显示使用其它的属性

    现在的包的情况:

    <a:Action s:mustUnderstand="1"

    u:Id="_2">http://tempuri.org/ICaculateService/DevideResponse

    </a:Action>

    在应用namespace之后:

     

    [ServiceContract(Namespace="http://www.selftest.com/test1")]

    public interface ICaculateService

    情况为:

    <a:Action s:mustUnderstand="1" u:Id="_2">

    http://www.selftest.com/test1/ICaculateService/DevideResponse

    </a:Action>

     

    这个namespace的定义为:获取或设置 Web 服务描述语言 (WSDL) 中的 <portType> 元素的命名空间,它默认的为 http://tempuri.org

     

    OperationContractAttribute用于标注向远程调用公开的方法功能。只要公开了,即使访问性为私有,也可以被远程调用。

    (接口中定义默认公开的,也无法添加访问修饰符),这个标签也有很多可选属性,而且这些属性非常重要。例如:

    ActionIsInitiatingIsOneWayIsTerminatingName

    例如Action

    引用:

    使用 Action 属性控制方法的输入消息的操作。由于 WCF 使用该操作将传入消息调度至相应方法,因此在协定操作中使用的消息必须具有唯一的操作。默认操作值由以下几项组成:协定命名空间(默认值为“http://tempuri.org/”)、协定名称(如果没有使用显式服务接口,则为接口名称或类名)、操作名称,并且如果该消息是一个相关的响应,则还有一个附加字符串(“Response”)。您可以使用 Action 属性重写该默认值:

    <a:Action s:mustUnderstand="1"

    u:Id="_2">http://tempuri.org/ICaculateService/DevideResponse

    </a:Action>

    (二)数据契约

    DataContract

    对于系统的简单类型,已经有默认的规则(所有 .NET Framework 基元类型(如整型和字符串型)以及某些被视为基元的类型(如 DateTime XmlElement)无需做其他任何准备工作就可序列化并被视为拥有默认数据协定)。而对于复杂类型来说,如类对象,如果不进行处理,是不可以传输的。而如果要让复杂类型传输或存储,则要对其进行序列化。(若要使其类型可序列化,类型作者必须为其类型定义数据协定。)

     

    DataContract属性可用于类,结构,枚举,然后其中的所有成员都必须添加DataMember标签,来指示这些成员做为数据成员,而可以被序列化和反序列化

    可以被序列化的类型包括:

    ·数据契约类型,就是添加DataContract标签的类型

    ·集合,数组与集合

    ·枚举,可以对枚举类型添加DataContract标签,然后,必须对枚举成员添加EnumMember标签,例如:

    [DataContract]

    public enum eErrorType

    {

    [EnumMember]

    No1,

    [EnumMember]

    No2,

    [EnumMember]

    No3,

    [EnumMember]

    No4

    }

    ·.NET Framework 基元类型 包括,字符,字串,字节,数值类型,object,时间,时间戳,guidUri

    ·Serializable修饰的类型

    ·原始的xmlado.net关系数据的类型

    (三)异常契约

    用于在服务操作在遇到处理错误时,返回的soap错误。这个通过FaultContractAttribute标签来实现。

    WCF服务在两种错误系统下工作(一是托管的应用程序中的Exception异常,另一种是soap异常),所以,发送到客户端的异常要由托管的异常信息转化为Soap异常信息。

    这里说一下FaultException<T> 泛型类,其中T表示可序列化错误详细信息类型。

    例如:

    ·契约

    [FaultContract(typeof(eErrorType))]

    int Devide(int a, int b);

    ·服务

    public int Devide(int a, int b)

    {

        switch (b)

        {

    case 0:

             throw new FaultException<eErrorType>(eErrorType.No1);

    case 1:

             throw new FaultException<eErrorType>(eErrorType.No2);

        }

        return a /b;

    }

    其中eErrorType前文已经给出

     

    客户端:

    int result = client.Devide(10, 0);

     

    catch (FaultException<FirstInstance.eErrorType> ex)

    {

        Console.WriteLine(ex.Detail.ToString());

    }

    异常信息:No1

    (四)消息契约

    WCF的核心是消息交换。例如WSHttpBinding绑定,编码格式为文本的时候,那么消息就是一个完整的Soap,就是一个封套;如果是MTOM时,那就是另一种格式了。

    为了验证消息的格式,现在在绑定中把安全选项加上,使用不加密:

    <wsHttpBinding>

    <binding name="BindingSelf"

    messageEncoding="Text" textEncoding="utf-8">

    <security mode="None"></security>

    </binding>

    </wsHttpBinding>

     

    然后,看一看消息格式是怎么样的:

    <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"

    xmlns:a="http://www.w3.org/2005/08/addressing">

    <s:Header>

         <a:Action s:mustUnderstand="1">

    http://www.selftest.com/test1/

    ICaculateService/GetCustomerByIdResponse

    </a:Action>

    <a:RelatesTo>

    urn:uuid:944ad5e1-7c2a-4617-a7a1-64bdc5b25d47

    </a:RelatesTo>

    </s:Header>

    <s:Body>

    <GetCustomerByIdResponse

    xmlns="http://www.selftest.com/test1">

    <GetCustomerByIdResult

    xmlns:b=" http://schemas.datacontract.org

    /2004/07/FirstService "

    xmlns:i="http://www.w3.org/2001/XMLSchema-instance">

         <b:Address>Shandong</b:Address>

         <b:CustomerName>Songjiang</b:CustomerName>

    <b:Unid>1</b:Unid>

    </GetCustomerByIdResult>

    </GetCustomerByIdResponse>

    </s:Body>

    </s:Envelope>

     

    在服务端是这样契约的:

    [DataContract]

    public class Customer

    {

    [DataMember]

    public int Unid { get; set; }

     

    [DataMember]

    public string CustomerName { get; set; }

     

    [DataMember]

    public string Address { get; set; }

    }

     

    方法GetCustomerById返回了一个Customer对象:

    <b:Address>Shandong</b:Address>

         <b:CustomerName>Songjiang</b:CustomerName>

    <b:Unid>1</b:Unid>

    这些就是它的属性及值。

     

    现在通过消息契约,来设置一下消息的格式。

    [MessageContract]

    public class Customer

    {

    [MessageHeader(Name="selfHeader001")]

    public int Unid { get; set; }

     

    [MessageHeader(Name = "selfHeader002")]

    public string CustomerName { get; set; }

     

    [MessageBodyMember(Name="selfBody001")]

    public string Address { get; set; }

    }

     

     

    <s:Envelope

    xmlns:s="http://www.w3.org/2003/05/soap-envelope"

    xmlns:a="http://www.w3.org/2005/08/addressing">

    <s:Header>

         <a:Action s:mustUnderstand="1">

    http://www.selftest.com/test1/ICaculateService

    /GetCustomerByIdResponse

    </a:Action>

         <h:selfHeader001

    xmlns:h="http://www.selftest.com/test1">

    1

    </h:selfHeader001>

         <h:selfHeader002

    xmlns:h="http://www.selftest.com/test1">

    Songjiang

    </h:selfHeader002>  

    <a:RelatesTo>

    urn:uuid:6ea8a734-d01f-4cf4-85ce-5fae03e538d9

    </a:RelatesTo>

      </s:Header>

    <s:Body>

    <Customer xmlns="http://www.selftest.com/test1">

         <selfBody001>Shandong</selfBody001>

      </Customer>

      </s:Body>

      </s:Envelope>

     

    可以看出这种消息契约非常灵活。现在来为customer消息添加一个文本文件。

    [MessageBodyMember(Name="text001")]

    public Byte[] TextFile { get; set; }

     

    包中的结果

    <text001>MTIzNCBxd2VydA==</text001>

     

  • 相关阅读:
    Enterprise Library 2.0 技巧(4):如何用编程的方法来配置Logging Application Block
    Castle IOC容器实践之EnterpriseLibrary Configuration Facility
    Castle开发系列文章上了Castle的官方网站
    DataGridView也泛型?——一个不错的DataGridView控件
    Enterprise Library for .NET Framework 3.0 what would you like to see?
    设计是否可以更合理一点?——关于ORM中业务实体的讨论
    Enterprise Library 2.0 技巧(2):如何将配置信息保存到数据库中
    关于Castle IOC容器自动装配的问题
    数据库重构与数据库单元测试
    BLINQ初体验
  • 原文地址:https://www.cnblogs.com/jams742003/p/1684093.html
Copyright © 2020-2023  润新知