WCF初探-16:WCF数据协定之基础知识
数据协定概念
- “数据协定”是在服务与客户端之间达成的正式协议,用于以抽象方式描述要交换的数据。 也就是说,为了进行通信,客户端和服务不必共享相同的类型,而只需共享相同的数据协定。 数据协定为每一个做数据交换时需要被序列化的参数或者返回值做了精确定义。
数据协定特点
- 默认情况下, WCF使用称为数据协定序列化程序的序列化引擎对数据进行序列化和反序列化(与 XML 进行相互转换)。 所有 .NET Framework 基元类型(如整型和字符串型)以及某些被视为基元的类型(如 DateTime 和 XmlElement)无需做其他任何准备工作就可序列化并被视为拥有默认数据协定。创建数据协定时需要考虑的事项:
- 仅当用于未标记的类型时,才接受 IgnoreDataMemberAttribute 属性。 这包括未使用 DataContractAttribute、SerializableAttribute、CollectionDataContractAttribute 或 EnumMemberAttribute 属性之一标记的类型,或通过任何其他方式(如 IXmlSerializable)标记为可序列化的类型。
- 可以将 DataMemberAttribute 属性 (Attribute) 应用于字段和属性 (Property)。
- 成员可访问性级别(internal、private、protected 或 public)对数据协定无任何影响。
- 如果将 DataMemberAttribute 属性应用于静态成员,则将忽略该属性。
- 在序列化期间,为属性数据成员调用 property-get 代码来获取要序列化的属性的值。
- 在反序列化期间,首先创建一个未初始化的对象,而不在该类型上调用任何构造函数。 然后反序列化所有数据成员。
- 在反序列化期间,为属性数据成员调用 property-set 代码,将属性设置为要反序列化的值。
- 对于将要生效的数据协定,它必须能序列化其所有数据成员。
- 创建类或结构的基本数据协定时,通过将 DataContractAttribute 属性应用于类来声明该类型具有数据协定。通过将 DataMemberAttribute 属性 (Attribute) 应用于每个成员来定义要序列化的成员(属性 (Property)、字段或事件)。但是,即使未用这些属性进行标记的类型也会进行序列化和反序列化。 适用的规则和例外如下:
- DataContractSerializer 使用新创建的类型的默认属性 (Property) 从不带属性 (Attribute) 的类型推断数据协定。
- 除非对成员应用 IgnoreDataMemberAttribute 属性 (Attribute),否则所有公共字段以及具有公共 get 和 set 方法的属性 (Property) 都会序列化。
- 序列化语义与 XmlSerializer 的语义类似。
- 在未标记的类型中,仅序列化具有不带参数的构造函数的公共类型。 此规则的例外是用于 IExtensibleDataObject 接口的 ExtensionDataObject。
- 只读字段、没有 get 或 set 方法的属性以及具有内部或私有 set 或 get 方法的属性不会进行序列化。 此类属性会被忽略,但不会引发异常(get-only 集合的情况除外)。
- 会忽略 XmlSerializer 属性(如 XmlElement、XmlAttribute、XmlIgnore、XmlInclude 等)。
- 如果未将 DataContractAttribute 属性应用于某个给定类型,则序列化程序会忽略该类型中应用了 DataMemberAttribute 属性的所有成员。
- 未使用 DataContractAttribute 属性 (Attribute) 进行标记的类型中支持 KnownTypes 属性 (Property)。 这包括对未标记类型上的 KnownTypeAttribute 属性 (Attribute) 的支持。
- 若要使公共成员、属性 (Property) 或字段“退出”序列化过程,请向该成员应用 IgnoreDataMemberAttribute 属性 (Attribute)。
- 在一些应用程序中,有必要知道各个数据成员中数据的发送顺序或预期接收顺序(比如序列化 XML 中数据的显示顺序)。 有时,必须要更改此顺序。数据排序的基本规则包括:
- 如果数据协定类型是继承层次结构的一部分,则其基类型的数据成员始终排在第一位。
- 排在下一位的是当前类型的数据成员(按字母顺序排列),这些成员未设置 DataMemberAttribute 属性 (attribute) 的 Order 属性 (property)。
- 再下面是设置了 DataMemberAttribute 属性 (attribute) 的 Order 属性 (property) 的任何数据成员。 这些成员首先按 Order 属性的值排序,如果多个成员具有特定的 Order 值,则按字母顺序排列。 可以跳过 Order 值。
- 给定类型的默认数据协定名称是该类型的名称。 若要重写默认值,请将 DataContractAttribute 的 Name 属性设置为其他名称。给定字段或属性的默认数据成员名称是该字段或属性的名称。 若要重写默认值,请将 DataMemberAttribute 的 Name 属性设置为其他值。数据协定命名空间采用统一资源标识符 (URI) 的形式。 URI 可以是绝对的,也可以是相对的。 默认情况下,会为特定类型的数据协定分配公共语言运行库 (CLR) 命名空间中该类型的命名空间。数据协定命名的基本规则包括:
- 完全限定的数据协定名称由命名空间和名称组成。
- 数据成员只有名称,而没有命名空间。
- 处理数据协定时,WCF 基础结构对于命名空间以及数据协定和数据成员的名称区分大小写。
- 默认情况下,任何给定的 CLR 命名空间(采用 Clr.Namespace 格式)都会映射到“http://schemas.datacontract.org/2004/07/Clr.Namespace”命名空间。 若要重写此默认值,请对整个模块或程序集应用 ContractNamespaceAttribute 属性。 或者,若要控制每种类型的数据协定命名空间,请设置 DataContractAttribute 的 Namespace 属性。
数据协定示例
- 解决方案如下:
- 工程结构说明如下:
- 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=)]
- public int ID { get; set; }
- [DataMember(Name="姓名",Order=)]
- 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=)]
- public int ID
- {
- get
- {
- return this.IDField;
- }
- set
- {
- this.IDField = value;
- }
- }
- [System.Runtime.Serialization.DataMemberAttribute(Order=)]
- 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=)]
- public int ID
- {
- get{return this.IDField;}
- set{this.IDField = value;}
- }
- [System.Runtime.Serialization.DataMemberAttribute(Order=)]
- public string 姓名
- {
- get{return this.姓名Field;}
- set{this.姓名Field = value;}
- }
- }
- }
- 从上面的代码可以看出我们的数据契约的Name变成了DCUser,Namespace变成了http://wangweimutou.DCUser,这和服务端的数据契约对应。
- 代理类中的数据契约生成的属性有6个,服务端数据契约定义的属性有8个,其中产生的差异,我们用以下图形来说明:
总结
- 通过上面的示例,我们了解DataContract的序列化的顺序和一些基本属性设置,也了解到DataContract的一些默认特点。
WCF初探-16:WCF数据协定之基础知识的更多相关文章
- [SQL]SQL Server数据表的基础知识与增查删改
SQL Server数据表的基础知识与增查删改 由张晨辉(学生) 于19天 前发表 | 阅读94次 一.常用数据类型 .整型:bigint.int.smallint.tinyint .小数:decim ...
- 我们一起学习WCF 第五篇数据协定和消息协定
A:数据协定(“数据协定”是在服务与客户端之间达成的正式协议,用于以抽象方式描述要交换的数据. 也就是说,为了进行通信,客户端和服务不必共享相同的类型,而只需共享相同的数据协定. 数据协定为每个参数或 ...
- python 爬虫与数据可视化--python基础知识
摘要:偶然机会接触到python语音,感觉语法简单.功能强大,刚好朋友分享了一个网课<python 爬虫与数据可视化>,于是在工作与闲暇时间学习起来,并做如下课程笔记整理,整体大概分为4个 ...
- 【大数据】Clickhouse基础知识
第1章 ClickHouse概述 1.1 什么是ClickHouse ClickHouse 是俄罗斯的Yandex于2016年开源的列式存储数据库(DBMS),主要用于在线分析处理查询(OLAP),能 ...
- hadoop大数据平台安全基础知识入门
概述 以 Hortonworks Data Platform (HDP) 平台为例 ,hadoop大数据平台的安全机制包括以下两个方面: 身份认证 即核实一个使用者的真实身份,一个使用者来使用大数据引 ...
- Android开发之数据存储——SharedPreferences基础知识详解,饿补学会基本知识,开发者必会它的用法。
一.数据存储选项:Data Storage --Storage Options[重点] 1.Shared Preferences Store private primitive data in key ...
- python 爬虫与数据可视化--爬虫基础知识
一.python中的模块 模块的安装:pip install 模块名 导入模块与函数:import requests . from pymongo import MongoClient json模块的 ...
- WCF初探文章列表
WCF初探-1:认识WCF WCF初探-6:WCF服务配置 WCF初探-2:手动实现WCF程序 WCF初探-7:WCF服务配置工具使用 WCF初探-3:WCF消息交换模式之单向模式 WCF初探-8:W ...
- WCF初探-22:WCF中使用Message类(上)
前言 从我们学习WCF以来,就一直强调WCF是基于消息的通信机制.但是由于WCF给我们做了高级封装,以至于我们在使用WCF的时候很少了解到消息的内部机制.由于WCF的架构的可扩展性,针对一些特殊情况, ...
随机推荐
- Linux命令之tcpdump
项目中常用到的抓包命令: 1. tcpdump -i eth0:1 udp poort 6015 -Xvv 2. tcpdump host 239.16.101.27 -Xvv 3. tcpdump ...
- 使用Redux管理你的React应用
因为redux和react的版本更新的比较频繁,博客园这里用的redux版本是1.0.1,如果你关心最新版本的使用技巧,欢迎来我的Github查看(https://github.com/matthew ...
- tomcat 大并发报错 Maximum number of threads (200) created for connector with address null and port 8080
1.INFO: Maximum number of threads (200) created for connector with address null and port 8091 说明:最大线 ...
- 关于ajax伪实时动态下拉显示最新数据
var list= data.data.list; //list是ajax返回的数组Array].Id).length>) { return false; } //$("#learnL ...
- [Python]如何获取目录下,最后更新的文件
#-*- coding: utf-8 -*- __author__ = 'tsbc' import time import datetime import os day = time.strftime ...
- CSS 盒子模型概述
一.简介 CSS 盒子模型(元素框)由元素内容(content).内边距(padding).边框(border).外边距(margin)组成. 盒子模型,最里面的部分是实际内容:直接包围内 ...
- CentOS下LAMP一键yum安装脚本
本脚本适用环境: 系统支持:CentOS/Redhat/Fedora 内存要求:≥64M 硬盘要求:2GB以上的剩余空间 服务器必须配置好软件源和可连接外网 必须具有系统 root 权限 建议使用干净 ...
- 【Spring】对象后期处理,BeanPostProcessor
当我们使用Spring容器管理对象时,需要对对象进行一些后期处理时,比如数据处理.数据预加载,可以使用BeanPostProcessor接口. 简单演示它的用法. 定义扫描包,显示定义BeanPost ...
- 执行大量的Redis命令,担心效率问题?用Pipelining试试吧~
参考的优秀文章 Request/Response protocols and RTT 来源 原来,系统中一个树结构的数据来源是Redis,由于数据增多.业务复杂,查询速度并不快.究其原因,是单次查询的 ...
- php实战正则表达式:验证手机号
摘自http://www.tuicool.com/articles/MFNZRzu 本文通过逐步完善一个验证手机号的正则表达式来介绍了正则表达式中的 字符组 .量词 . 字符串起始/结束位置 . 分组 ...