第七讲:数据契约(2)
代码
https://yunpan.cn/cPns5DkGnRGNs 密码:3913
前面不止一次地强调,WCF下的序列化与反序列化解决的是数据在两种状态之间 相互 转化的问题:托管类型对象转换成XML 。
由于类型定义了对象的数据结构,所以无论是对于序列化还是反序列化,都必须事先确定对象的类型。如果被序列化对象或被反序列化生成对象包含不可知的类型,序列化和反序列化将会失败。为了确保DataContractSerializer的正常序列化和饭序列化,需要将“未知”类型加入DataContractSerializer“已知”类型列表中。
例如 :
我们服务端的数据类型 A 和 B(A 类上面 打了 DataContract 特性的标签,将A变成了 数据契约, B 类并没有做任何描述的操作,也就是说B类只是一个普通类型 ), B继承了A ,所以 正常的情况下 如果 某个方法的 参数 是 A类型,那么 传入 B类型是不应该有错误的。因为 B是A的子类。 可这里 WCF 并不认识B,尽管 方法的 参数 是A
这里WCF会报错的,(.Net的类型可以分为两种:声明类型和真实类型。我们提倡面向接口的编程,对象的真实类型往往需要在运行时才能确定,在编程的时候只需要指明类型的声明类型,比如类型实现的接口或抽象类。)当我们使用基于接口或抽象类(类)创建
的DataContractSerializer(数据契约)去序列化一个实现了该接口或继承该抽象类的实例时,往往会因为无法识别对象的真实类型造成不能正常的序列化。
所以客户端 去调用方法并传入A类型的子类 类型 作为参数 也是会报错的。 因为 B 类型并不是 已知的类型。
具体应该怎么做呢?那这种情况下 我们就应该 将 " 未知 " 类型加入DataContractSerializer " 已知 " 类型列表中。
那现在 就是 应该我们的 KnownTypeAttribute 与ServiceKnowTypeAttribute 两个特性出场的时候了。
1.KnownTypeAttribute :
KnownTypeAttribute应用于数据契约中,用于设置继承于该数据契约类型的子数据契约类型,或者引用其他潜在的类型。
2.ServiceKnowTypeAttribute :
ServiceKnowTypeAttribute既可以应用于服务契约的接口和方法上,也可以应用在服务实现的类和方法上。如果应用在服务契约类型上,未知类型的这个类型 在所有实现了该契约的服务操作中有效,如果应用于服务契约的操作方法上,则定义的未知类型在所有实现了该契约的服务对应的操作方法中有效.
上面的两种方法,二选一,两种都可以做到 将未知类型加入到 已知类型当中。
我们再次看Demo,云盘上有
[ 7-01 ]
Client:客户端
ContentTypes:数据契约层
GigManager:服务契约层 ( 这里 把服务契约的 实现 也写到了 这里。当然 也可以把它分开 )
Hosting:服务器寄宿
首先看 GigManager:服务契约层
[ 7-02 ]
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.ServiceModel; 6 using ContentTypes; 7 8 namespace GigManager 9 { 10 11 [ServiceContract] 12 public interface IGigManagerService 13 { 14 15 [OperationContract] 16 //[ServiceKnownType(typeof(Order))] 17 void Save(OrderBase order); 18 } 19 20 public class GigManagerService : IGigManagerService 21 { 22 public void Save(OrderBase order) 23 { 24 25 } 26 } 27 28 }
然后 看 ContentTypes:数据契约层
[ 7-03 ]
[ 7-04 ]
OrderBase.cs
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.ServiceModel; 6 using System.Runtime.Serialization; 7 namespace ContentTypes 8 { 9 10 [DataContract] 11 //[KnownType(typeof(Order))] 12 public class OrderBase 13 { 14 [DataMember] 15 public Guid ID { get; set; } 16 17 [DataMember] 18 public DateTime Date { get; set; } 19 20 [DataMember] 21 public string Customer { get; set; } 22 23 [DataMember] 24 public string ShipAddress { get; set; } 25 } 26 }
[ 7-05 ]
Order.cs
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Runtime.Serialization; 6 7 namespace ContentTypes 8 { 9 [DataContract] 10 public class Order : OrderBase 11 { 12 [DataMember] 13 public double TotalPrice { get; set; } 14 } 15 16 }
可以看到数据契约层中有 两个 类,一个OrderBase 为父类, 一个 Order 为 OrderBase 的子类
接下来看 Hosting:服务器寄宿( 这里的代码没有什么改变与第六讲一样 )
代码
[ 7-06 ]
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.ServiceModel; 6 7 namespace Hosting 8 { 9 class Program 10 { 11 static void Main(string[] args) 12 { 13 using (ServiceHost host = new ServiceHost(typeof(GigManager.GigManagerService))) 14 { 15 host.Open(); 16 Console.WriteLine(); 17 Console.WriteLine("服务已经启动"); 18 Console.ReadLine(); 19 } 20 } 21 } 22 }
appconfig 配置:
[ 7-07 ]
1 <?xml version="1.0" encoding="utf-8" ?> 2 <configuration> 3 <system.serviceModel> 4 <services> 5 <service name="GigManager.GigManagerService" behaviorConfiguration="serviceBehavior"> 6 <endpoint address="GigManagerService" contract="GigManager.IGigManagerService" binding="netTcpBinding"></endpoint> 7 <endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex"></endpoint> 8 <host> 9 <baseAddresses> 10 <add baseAddress="http://127.0.0.1:8000"/> 11 <add baseAddress="net.tcp://127.0.0.1:9000"/> 12 </baseAddresses> 13 </host> 14 </service> 15 </services> 16 <behaviors> 17 <serviceBehaviors> 18 <behavior name="serviceBehavior"> 19 <serviceMetadata httpGetEnabled="true"/> 20 </behavior> 21 </serviceBehaviors> 22 </behaviors> 23 </system.serviceModel> 24 </configuration>
最后看 Client:客户端
代码
[ 7-08 ]
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using Client.localhost; 6 using ContentTypes; 7 8 namespace Client 9 { 10 class Program 11 { 12 static void Main(string[] args) 13 { 14 using (localhost.GigManagerServiceClient proxy = new Client.localhost.GigManagerServiceClient()) 15 { 16 Order order = new Order(); 17 order.ID = Guid.NewGuid(); 18 order.Customer = "NCS"; 19 order.Date = DateTime.Today; 20 order.ShipAddress = "sssssssssss"; 21 order.TotalPrice = 888.8; 22 proxy.Save(order); 23 Console.WriteLine(order.ID.ToString()); 24 Console.WriteLine(order.Customer); 25 Console.Read(); 26 } 27 } 28 } 29 }
appconfig 配置: ( 这里的代码没有什么改变与第六讲一样 )
这里的配置 是我们 添加了 服务引用 自动生成 的 ,可以不管
[ 7-09 ]
1 <?xml version="1.0" encoding="utf-8" ?> 2 <configuration> 3 <system.serviceModel> 4 <bindings> 5 <netTcpBinding> 6 <binding name="NetTcpBinding_IGigManagerService" closeTimeout="00:01:00" 7 openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" 8 transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions" 9 hostNameComparisonMode="StrongWildcard" listenBacklog="10" 10 maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="10" 11 maxReceivedMessageSize="65536"> 12 <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" 13 maxBytesPerRead="4096" maxNameTableCharCount="16384" /> 14 <reliableSession ordered="true" inactivityTimeout="00:10:00" 15 enabled="false" /> 16 <security mode="Transport"> 17 <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" /> 18 <message clientCredentialType="Windows" /> 19 </security> 20 </binding> 21 </netTcpBinding> 22 </bindings> 23 <client> 24 <endpoint address="net.tcp://127.0.0.1:9000/GigManagerService" 25 binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IGigManagerService" 26 contract="localhost.IGigManagerService" name="NetTcpBinding_IGigManagerService"> 27 <identity> 28 <userPrincipalName value="20080904-1145\Administrator" /> 29 </identity> 30 </endpoint> 31 </client> 32 </system.serviceModel> 33 </configuration>
我们仔细看 这里 ,这里的 需要的参数是OrderBase类型,而我们传入的是OrderBase 的 子类Order 类型,所以这里一定会出错。
[ 7-10 ]
运行后 的报错
[ 7-11 ]
错误消息:
格式化程序尝试对消息反序列化时引发异常: 尝试对参数 http://tempuri.org/ 进行反序列化时出错: order。InnerException 消息是“元素“http://tempuri.org/:order”含有“http://schemas.datacontract.org/2004/07/ContentTypes:Order”数据协定的数据。反序列化程序不知道映射到此协定的类型。请将与“Order”对应的类型添加到已知类型的列表中,例如,通过使用 KnownTypeAttribute 属性或通过将其添加到传递给 DataContractSerializer 的已知类型的列表等方法。”。有关详细信息,请参阅 InnerException。
这里很清楚的告诉了 我们 不认识 Order 类型。
如何代码实现?
1.使用KnownTypeAttribute
在父类的 数据契约上 加上 [KnownType(typeof(Order))] 特性 , 将 Order 这个 " 未知 " 类型 加入 " 已知 " 类型列表中。
[ 7-12 ]
2.使用ServiceKnownType
在需要用到该未知类型 操作的服务契约上或者服务契约中的方法上 打上 [ServiceKnownType(typeof(Order))] 特性标签 ,则定义的 未知类型 在所有实现了该契约的服务对应的操作中有效.
特性打在 服务契约 上面
[ 7-13 ]
或者 特性打在 服务契约中的方法上
[ 7-14 ]
好 , 打上 特性之后 ,我们再试一试 ,这样就可以了。
转载于:https://www.cnblogs.com/xulang/p/5495108.html
第七讲:数据契约(2)相关推荐
- 王家林 云计算分布式大数据Hadoop实战高手之路第七讲Hadoop图文训练课程:通过HDFS的心跳来测试replication具体的工作机制和流程...
这一讲主要深入使用HDFS命令行工具操作Hadoop分布式集群,主要是通过实验的配置hdfs-site.xml文件的心跳来测试replication具体的工作和流程. 通过HDFS的心跳来测试repl ...
- 数据分析 第七讲 pandas练习 数据的合并、分组聚合、时间序列、pandas绘图
文章目录 数据分析 第七讲 pandas练习 数据的合并和分组聚合 一.pandas-DataFrame 练习1 对于这一组电影数据,如果我们想runtime(电影时长)的分布情况,应该如何呈现数据? ...
- python字典、列表、元祖使用场景_python学习第七讲,python中的数据类型,列表,元祖,字典,之元祖使用与介绍...
python学习第七讲,python中的数据类型,列表,元祖,字典,之元祖使用与介绍 一丶元祖 1.元祖简介 元祖跟列表类似.只不过是有区别的. 如下: tuple(元祖英文) 跟列表类似, 元素不能 ...
- 高翔Slambook第七讲代码解读(特征点提取)
前言:小白创建了一个微信公众号,主要面向学习视觉的小伙伴,分享一些学习过程中的感受和一些技术文章.公众号里文章也会更新在CSDN中,不过由于工作量较大,会出现一段时间的延时,感兴趣的小伙伴可以关注公众 ...
- 32位汇编第七讲,混合编程,内联汇编
32位汇编第七讲,混合编程 博客园IBinary原创 QQ:2510908331 博客连接:http://www.cnblogs.com/iBinary/ 转载请注明出处,谢谢 混合编程的概念,有时 ...
- WCF 之 数据契约
前面几篇讲的都只能传递string类型的简单参数,数据契约就是用来解决如传递一个带有多个属性的Class类型的对象的. WCF推荐使用数据契约的方式实现数据的序列化.这部分的内容很好理解但是很重要,先 ...
- PE格式第七讲,重定位表
PE格式第七讲,重定位表 作者:IBinary 出处:http://www.cnblogs.com/iBinary/ 版权所有,欢迎保留原文链接进行转载:) 一丶何为重定位(注意,不是重定位表格) 首 ...
- 几何畸变的类型_第七讲 几何纠正(摄影测量与遥感).pdf
第七讲 几何纠正(摄影测量与遥感) 第七讲:遥感数据预处理 第七讲:遥感数据预处理 --几何纠正 --几何纠正 几何纠正 几何纠正 几何纠正 • 遥感影像一般需要经过几何纠正的预处理去除 • 遥感影像 ...
- 高翔orbslam_高翔Slambook第七讲代码解读(特征点提取)
点击蓝色字关注我们! 大家好我是小绿. 作为一个视觉SLAM的入门学徒,高翔的书我看了一遍,视频也跟了一遍,代码在自己的电脑上也跑过,但总觉得跟啥都没学没有太大区别. 于是乎决定开始看代码.由于不是计 ...
最新文章
- 程序员毕业两年,如何在帝都购房上车?
- 使用Chrome DevTools的Timeline和Profiles提高Web应用程序的性能
- 基于Oracle11gR2 GRID的单实例库备份恢复
- pythonfind_python实现find -name的功能
- camel.js_Camel 2.11 –没有Spring的Camel Web应用程序
- 小程序自定义数字键盘|仿微信支付、支付宝支付密码键盘
- mysql在官网下载完解压后安装
- 腾讯等技术大佬分享的高可用架构干货,全在这里了
- SSD 超详细入门(代码+原文)
- jupyter 更改主题 换成黑色背景
- iOS自动化测试需求实现(iOS按键精灵类似)
- Java实现熵值法计算_熵值法确定权重的步骤及适用范围
- win10安装RabbitMQ教程
- C#datagrid与datagridview的区别
- 深入理解git push
- android 开发比较好的学习网站和博主
- ARKit之路-运动跟踪原理
- 计算机网络原理(谢希仁第八版)第三章课后习题答案
- 【算法•日更•第十五期】信息奥赛一本通1594:涂抹果酱题解
- 分享6款优秀的 AR/VR 开源库 – 切切歆语的博客 – CSDN博客