WCF初探-16:WCF数据协定之基础知识

数据协定概念

  • “数据协定”是在服务与客户端之间达成的正式协议,用于以抽象方式描述要交换的数据。 也就是说,为了进行通信,客户端和服务不必共享相同的类型,而只需共享相同的数据协定。 数据协定为每一个做数据交换时需要被序列化的参数或者返回值做了精确定义。

数据协定特点

  • 默认情况下, WCF使用称为数据协定序列化程序的序列化引擎对数据进行序列化和反序列化(与 XML 进行相互转换)。 所有 .NET Framework 基元类型(如整型和字符串型)以及某些被视为基元的类型(如 DateTime 和 XmlElement)无需做其他任何准备工作就可序列化并被视为拥有默认数据协定。创建数据协定时需要考虑的事项:
  1. 仅当用于未标记的类型时,才接受 IgnoreDataMemberAttribute 属性。 这包括未使用 DataContractAttribute、SerializableAttribute、CollectionDataContractAttribute 或 EnumMemberAttribute 属性之一标记的类型,或通过任何其他方式(如 IXmlSerializable)标记为可序列化的类型。
  2. 可以将 DataMemberAttribute 属性 (Attribute) 应用于字段和属性 (Property)。
  3. 成员可访问性级别(internal、private、protected 或 public)对数据协定无任何影响。
  4. 如果将 DataMemberAttribute 属性应用于静态成员,则将忽略该属性。
  5. 在序列化期间,为属性数据成员调用 property-get 代码来获取要序列化的属性的值。
  6. 在反序列化期间,首先创建一个未初始化的对象,而不在该类型上调用任何构造函数。 然后反序列化所有数据成员。
  7. 在反序列化期间,为属性数据成员调用 property-set 代码,将属性设置为要反序列化的值。
  8. 对于将要生效的数据协定,它必须能序列化其所有数据成员。
  • 创建类或结构的基本数据协定时,通过将 DataContractAttribute 属性应用于类来声明该类型具有数据协定。通过将 DataMemberAttribute 属性 (Attribute) 应用于每个成员来定义要序列化的成员(属性 (Property)、字段或事件)。但是,即使未用这些属性进行标记的类型也会进行序列化和反序列化。 适用的规则和例外如下:
  1. DataContractSerializer 使用新创建的类型的默认属性 (Property) 从不带属性 (Attribute) 的类型推断数据协定。
  2. 除非对成员应用 IgnoreDataMemberAttribute 属性 (Attribute),否则所有公共字段以及具有公共 get 和 set 方法的属性 (Property) 都会序列化。
  3. 序列化语义与 XmlSerializer 的语义类似。
  4. 在未标记的类型中,仅序列化具有不带参数的构造函数的公共类型。 此规则的例外是用于 IExtensibleDataObject 接口的 ExtensionDataObject。
  5. 只读字段、没有 get 或 set 方法的属性以及具有内部或私有 set 或 get 方法的属性不会进行序列化。 此类属性会被忽略,但不会引发异常(get-only 集合的情况除外)。
  6. 会忽略 XmlSerializer 属性(如 XmlElement、XmlAttribute、XmlIgnore、XmlInclude 等)。
  7. 如果未将 DataContractAttribute 属性应用于某个给定类型,则序列化程序会忽略该类型中应用了 DataMemberAttribute 属性的所有成员。
  8. 未使用 DataContractAttribute 属性 (Attribute) 进行标记的类型中支持 KnownTypes 属性 (Property)。 这包括对未标记类型上的 KnownTypeAttribute 属性 (Attribute) 的支持。
  9. 若要使公共成员、属性 (Property) 或字段“退出”序列化过程,请向该成员应用 IgnoreDataMemberAttribute 属性 (Attribute)。
  • 在一些应用程序中,有必要知道各个数据成员中数据的发送顺序或预期接收顺序(比如序列化 XML 中数据的显示顺序)。 有时,必须要更改此顺序。数据排序的基本规则包括:
  1. 如果数据协定类型是继承层次结构的一部分,则其基类型的数据成员始终排在第一位。
  2. 排在下一位的是当前类型的数据成员(按字母顺序排列),这些成员未设置 DataMemberAttribute 属性 (attribute) 的 Order 属性 (property)。
  3. 再下面是设置了 DataMemberAttribute 属性 (attribute) 的 Order 属性 (property) 的任何数据成员。 这些成员首先按 Order 属性的值排序,如果多个成员具有特定的 Order 值,则按字母顺序排列。 可以跳过 Order 值。
  • 给定类型的默认数据协定名称是该类型的名称。 若要重写默认值,请将 DataContractAttribute 的 Name 属性设置为其他名称。给定字段或属性的默认数据成员名称是该字段或属性的名称。 若要重写默认值,请将 DataMemberAttribute 的 Name 属性设置为其他值。数据协定命名空间采用统一资源标识符 (URI) 的形式。 URI 可以是绝对的,也可以是相对的。 默认情况下,会为特定类型的数据协定分配公共语言运行库 (CLR) 命名空间中该类型的命名空间。数据协定命名的基本规则包括:
  1. 完全限定的数据协定名称由命名空间和名称组成。
  2. 数据成员只有名称,而没有命名空间。
  3. 处理数据协定时,WCF 基础结构对于命名空间以及数据协定和数据成员的名称区分大小写。
  • 默认情况下,任何给定的 CLR 命名空间(采用 Clr.Namespace 格式)都会映射到“http://schemas.datacontract.org/2004/07/Clr.Namespace”命名空间。 若要重写此默认值,请对整个模块或程序集应用 ContractNamespaceAttribute 属性。 或者,若要控制每种类型的数据协定命名空间,请设置 DataContractAttribute 的 Namespace 属性。

数据协定示例

  • 解决方案如下:

  

  • 工程结构说明如下:
  1. Service:类库类型,WCF服务端程序。定义服务契约接口IUserInfo,定义操作契约方法GetInfo获取用户信息,定义数据契约User,提供用户信息的传输对象。IUserInfo.cs的代码如下:
using System.ServiceModel;
using System.Runtime.Serialization;

namespace Service
{
    [ServiceContract]
    public interface IUserInfo
    {
        [OperationContract]
        User[] GetInfo();
    }

    [DataContract(Name="DCUser",Namespace="http://wangweimutou.DCUser")]
    public class User
    {
        [DataMember(Order=1)]
        public int ID { get; set; }

        [DataMember(Name="姓名",Order=2)]
        public string Name { get; set; }

        [DataMember]
        private int Age;

        private string Address;

        [DataMember]
        public string Email { get; set; }

        [IgnoreDataMember]
        public string Phone { get; set; }

        private string _job;
        [DataMember]
        public string Job
        {
            get { return _job; }
            set { _job = value; }
        }

        public string Nationality { get; set; }
    }
}

  UserInfo.cs的代码如下:

  

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Service
{
    public class UserInfo:IUserInfo
    {
        public User[] GetInfo()
        {
            List<User> listData = new List<User>();
            return listData.ToArray();
        }
    }
}

  2.  Host:控制台应用程序,服务承载程序。添加对Service程序集的引用,Program.cs的代码如下:

  

using System;
using System.ServiceModel;
using Service;

namespace Host
{
    class Program
    {
        static void Main(string[] args)
        {
            using (ServiceHost host = new ServiceHost(typeof(UserInfo)))
            {
                host.Opened += delegate { Console.WriteLine("服务已经启动,按任意键终止!"); };
                host.Open();
                Console.Read();
            }
        }
    }
}

  App.config的代码如下:

  

<?xml version="1.0"?>
<configuration>
    <system.serviceModel>

        <services>
            <service name="Service.UserInfo" behaviorConfiguration="mexBehavior">
                <host>
                    <baseAddresses>
                        <add baseAddress="http://localhost:1234/UserInfo/"/>
                    </baseAddresses>
                </host>
                <endpoint address="" binding="wsHttpBinding" contract="Service.IUserInfo" />
                <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
            </service>
        </services>

        <behaviors>
            <serviceBehaviors>
                <behavior name="mexBehavior">
                    <serviceMetadata httpGetEnabled="true"/>
                    <serviceDebug includeExceptionDetailInFaults="true"/>
                </behavior>
            </serviceBehaviors>
        </behaviors>
    </system.serviceModel>
</configuration>

  3.  Client:控制台引用程序,启动Host程序寄宿服务,在命令行中输入以下命令,将生成的UserInfoClient.cs和App.config文件拷贝到Client程序目录下。

  

  UserInfoClient.cs代码如下:

  

//------------------------------------------------------------------------------
// <auto-generated>
//     此代码由工具生成。
//     运行时版本:2.0.50727.5485
//
//     对此文件的更改可能会导致不正确的行为,并且如果
//     重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------

[assembly: System.Runtime.Serialization.ContractNamespaceAttribute("http://wangweimutou.DCUser", ClrNamespace="wangweimutou.dcuser")]

namespace wangweimutou.dcuser
{
    using System.Runtime.Serialization;

    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
    [System.Runtime.Serialization.DataContractAttribute(Name="DCUser", Namespace="http://wangweimutou.DCUser")]
    public partial class DCUser : object, System.Runtime.Serialization.IExtensibleDataObject
    {

        private System.Runtime.Serialization.ExtensionDataObject extensionDataField;

        private int AgeField;

        private string EmailField;

        private string JobField;

        private int IDField;

        private string 姓名Field;

        public System.Runtime.Serialization.ExtensionDataObject ExtensionData
        {
            get
            {
                return this.extensionDataField;
            }
            set
            {
                this.extensionDataField = value;
            }
        }

        [System.Runtime.Serialization.DataMemberAttribute()]
        public int Age
        {
            get
            {
                return this.AgeField;
            }
            set
            {
                this.AgeField = value;
            }
        }

        [System.Runtime.Serialization.DataMemberAttribute()]
        public string Email
        {
            get
            {
                return this.EmailField;
            }
            set
            {
                this.EmailField = value;
            }
        }

        [System.Runtime.Serialization.DataMemberAttribute()]
        public string Job
        {
            get
            {
                return this.JobField;
            }
            set
            {
                this.JobField = value;
            }
        }

        [System.Runtime.Serialization.DataMemberAttribute(Order=3)]
        public int ID
        {
            get
            {
                return this.IDField;
            }
            set
            {
                this.IDField = value;
            }
        }

        [System.Runtime.Serialization.DataMemberAttribute(Order=4)]
        public string 姓名
        {
            get
            {
                return this.姓名Field;
            }
            set
            {
                this.姓名Field = value;
            }
        }
    }
}

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(ConfigurationName="IUserInfo")]
public interface IUserInfo
{

    [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IUserInfo/GetInfo", ReplyAction="http://tempuri.org/IUserInfo/GetInfoResponse")]
    wangweimutou.dcuser.DCUser[] GetInfo();
}

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public interface IUserInfoChannel : IUserInfo, System.ServiceModel.IClientChannel
{
}

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public partial class UserInfoClient : System.ServiceModel.ClientBase<IUserInfo>, IUserInfo
{

    public UserInfoClient()
    {
    }

    public UserInfoClient(string endpointConfigurationName) :
            base(endpointConfigurationName)
    {
    }

    public UserInfoClient(string endpointConfigurationName, string remoteAddress) :
            base(endpointConfigurationName, remoteAddress)
    {
    }

    public UserInfoClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
            base(endpointConfigurationName, remoteAddress)
    {
    }

    public UserInfoClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
            base(binding, remoteAddress)
    {
    }

    public wangweimutou.dcuser.DCUser[] GetInfo()
    {
        return base.Channel.GetInfo();
    }
}

客户端数据契约解析

  • 我们进UserInfoClient.cs中生成的数据契约代码提取出来,代码显示如下:
[assembly: System.Runtime.Serialization.ContractNamespaceAttribute("http://wangweimutou.DCUser", ClrNamespace="wangweimutou.dcuser")]

namespace wangweimutou.dcuser
{
    using System.Runtime.Serialization;

    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
    [System.Runtime.Serialization.DataContractAttribute(Name="DCUser", Namespace="http://wangweimutou.DCUser")]
    public partial class DCUser : object, System.Runtime.Serialization.IExtensibleDataObject
    {

        private System.Runtime.Serialization.ExtensionDataObject extensionDataField;

        private int AgeField;

        private string EmailField;

        private string JobField;

        private int IDField;

        private string 姓名Field;

        public System.Runtime.Serialization.ExtensionDataObject ExtensionData
        {
            get{ return this.extensionDataField;}
            set{this.extensionDataField = value;}
        }

        [System.Runtime.Serialization.DataMemberAttribute()]
        public int Age
        {
            get{return this.AgeField;}
            set{this.AgeField = value;}
        }

        [System.Runtime.Serialization.DataMemberAttribute()]
        public string Email
        {
            get{return this.EmailField;}
            set{this.EmailField = value;}
        }

        [System.Runtime.Serialization.DataMemberAttribute()]
        public string Job
        {
            get{return this.JobField;}
            set{this.JobField = value;}
        }

        [System.Runtime.Serialization.DataMemberAttribute(Order=3)]
        public int ID
        {
            get{return this.IDField;}
            set{this.IDField = value;}
        }

        [System.Runtime.Serialization.DataMemberAttribute(Order=4)]
        public string 姓名
        {
            get{return this.姓名Field;}
            set{this.姓名Field = value;}
        }
    }
}
  • 从上面的代码可以看出我们的数据契约的Name变成了DCUser,Namespace变成了http://wangweimutou.DCUser,这和服务端的数据契约对应。
  • 代理类中的数据契约生成的属性有6个,服务端数据契约定义的属性有8个,其中产生的差异,我们用以下图形来说明:

  

总结

  • 通过上面的示例,我们了解DataContract的序列化的顺序和一些基本属性设置,也了解到DataContract的一些默认特点。
时间: 2025-01-14 07:51:49

WCF初探-16:WCF数据协定之基础知识的相关文章

学习大数据要什么基础知识?学到什么程度才能从事大数据行业?

因为大数据前景好,薪资高,很多人想通过参加学习大数据,然后进入大数据行业发展.但是因为大数据的门槛较高,对于学习人员有一定的要求,那么学习大数据需要什么基础知识呢? 首先我们了解下对于大数据学习者本身的学历水平的要求 目前大多数的机构,对于大数据学习者要求必须是大专学历以上,而且大专学历还要求是计算机相关专业的,如果是本科及本科以上的,则对专业要求适当的放宽.同时大数据分为两大方向:大数据开发和大数据分析. 这两大方向的对于基础知识的要求不同,大数据分析偏向于分析,对于编程要求不高,相较而言对于

我们一起学习WCF 第五篇数据协定和消息协定(附上源码)

A:数据协定(“数据协定”是在服务与客户端之间达成的正式协议,用于以抽象方式描述要交换的数据. 也就是说,为了进行通信,客户端和服务不必共享相同的类型,而只需共享相同的数据协定. 数据协定为每个参数或返回类型精确定义为进行交换而序列化哪些数据(将哪些数据转换为 XML)摘自MSDN)也就说数据协定是客户端和服务端之间达成的数据协议,相互通信的参数会被序列化然后进行传输.那么我用图来表示为什么用数据协定. 下面用图来说明其几个用处 那么下面我们来看看数据协定的代码实现 1:创建一个协定类 1 [D

学习大数据需要哪些基础知识

1.思维模式转变的催化剂是大量新技术的诞生,它们能够处理大数据分析所带来的3个V的挑战.扎根于开源社区,Hadoop已经是目前大数据平台中应用率最高的技术,特别是针对诸如文本.社交媒体订阅以及视频等非结构化数据. 2.除分布式文件系统之外,伴随Hadoop一同出现的还有进行大数据集处理MapReduce架构.根据权威报告显示,许多企业都开始使用或者评估Hadoop技术来作为其大数据平台的标准. 3.我们生活的时代,相对稳定的数据库市场中还在出现一些新的技术,而且在未来几年,它们会发挥作用.事实上

hadoop大数据平台安全基础知识入门

概述 以 Hortonworks Data Platform (HDP) 平台为例 ,hadoop大数据平台的安全机制包括以下两个方面: 身份认证 即核实一个使用者的真实身份,一个使用者来使用大数据引擎平台,这个使用者需要表明自己是谁,即提供自己的身份证明,大数据平台需要检验这个证明,确定这个证明是有效的,且不是伪造的.否则,就拒绝这个使用者进入大数据引擎. 授权管理 这个使用者的真实身份核实之后,需要对这个使用者的使用权限进行界定,即这个使用者在大数据平台中能够使用什么组件,能够获取哪些资源,

数据中心服务器基础知识大全

服务器对于每个从事it工作的人来说并不陌生,但是服务器所涉及的各种知识细节,并非大家都十分清楚,为了让大家深入了解服务器的关建知识点,我在网络上找到一些资料,合并整理,旨在帮助大家从服务器的架构和分类开始. 按照服务器的体系来分,服务器哦主要分为非x86服务器和x86服务器. 非x86服务器 非x86服务器包括大型机.小型机和UNIX服务器,它们是使用RISC或EPIC,并且主要采用UNIX和其它专用操作系统,RISC处理器主要包括IBM公司的Power和PowerPC处理器,SUN和富士通合作

WCF初探-22:WCF中使用Message类(上)

前言 从我们学习WCF以来,就一直强调WCF是基于消息的通信机制.但是由于WCF给我们做了高级封装,以至于我们在使用WCF的时候很少了解到消息的内部机制.由于WCF的架构的可扩展性,针对一些特殊情况,WCF为我们提供了Message类来深度定制消息结构,以便我们拓展WCF的通信机制. 在之前的文章中,我们针对一些常用的WCF传递数据的方式进行了说明,比如数据协定和消息协定等.他们传递的数据最终都会转化为消息的实例.具体参照:        WCF初探-16:WCF数据协定之基础知识       

大数据学习路线是什么?学大数据需要什么基础?

因为大数据前景好,薪资高,很多人想通过参加学习大数据,然后进入大数据行业发展.但是因为大数据的门槛较高,对于学习人员有一定的要求,那么学习大数据需要什么基础知识呢? 一起来了解下对于大数据学习者本身的学历水平的要求. 目前大多数的机构,对于大数据学习者要求必须是大专学历以上,而且大专学历还要求是理工科相关专业的,如果是本科及本科以上的,则对专业要求适当的放宽.同时大数据分为两大方向:大数据开发和数据分析. 这两大方向的对于基础知识的要求不同,数据分析偏向应用层面,对于编程要求不高,相较而言对于基

java基础知识回顾之javaIO类--RandomAccessFile类

java.io 类 RandomAccessFile java.lang.Object java.io.RandomAccessFile1.该类不是IO流中的子类.2.该类既能读又能写.3.该对象内部分装了一个字节数组,通过指针可以操作数组中的元素.4.其实该对象就是将字节输入流和输出流进行了封装.5.该对象只能对文件操作,目的和源只能是文件对象.通过看构造方法可以看得出来.RandomAccessFile(File file, String mode) RandomAccessFile(Str

学习大数据需要掌握的知识,需要学习的数据技术

大数据的发展历程总体上可以划分为三个重要阶段,萌芽期.成熟期和大规模应用期,20世纪90年至21世纪初,为萌芽期,随着,一批商业智能工具和知识管理技术的开始和应用,度过了数据萌芽,21世纪前十年则为成熟期,主要标志为,大数据解决方案逐渐走向成熟,形成了并行计算与分布式系统两大核心技,谷歌的GFS和MapReduce等大数据技术受到追捧,Hadoop平台开始大行期道,2010年以后,为大规模应用期,标志为,数据应用***各行各业,数据驱动决策,信息社会智能化程度快速提高. 数据时代的到来,也推动了