WCF技术剖析之十五:数据契约代理(DataContractSurrogate)在序列化中的作用
原文:WCF技术剖析之十五:数据契约代理(DataContractSurrogate)在序列化中的作用
[爱心链接:拯救一个25岁身患急性白血病的女孩[内有苏州电视台经济频道《天天山海经》为此录制的节目视频(苏州话)]]如果一个类型,不一定是数据契约,和给定的数据契约具有很大的差异,而我们要将该类型的对象序列化成基于数据契约对应的XML。反之,对于一段给定的基于数据契约的XML,要通过反序列化生成该类型的对象,我们该如何实现这样的场景?
比如下面定义了两个类型Contact和Customer,其中Customer是数据契约,Contact的Sex属性相当于Customer的Gender属性,而Contact的FullName可以看成是Customer的FirstName和LastName的组合。现在我们要做的是将一个Contact对象序列化成基于Customer数据契约对应的结构的XML,或者对于一段基于Customer数据契约对应结构的XML,将其反序列化生成Contact对象。
1: public class Contact
2: {
3: public string FullName
4: { get; set; }
5:
6: public string Sex
7: { get; set; }
8:
9: public override bool Equals(object obj)
10: {
11: Contact contact = obj as Contact;
12: if (contact == null)
13: {
14: return false;
15: }
16:
17: return this.FullName == contact.FullName && this.Sex == contact.Sex;
18: }
19:
20: public override int GetHashCode()
21: {
22: return this.FullName.GetHashCode() ^ this.Sex.GetHashCode();
23: }
24: }
1: [DataContract(Namespace = "http://www.artech.com")]
2: public class Customer
3: {
4: [DataMember(Order = 1)]
5: public string FirstName
6: { get; set; }
7:
8: [DataMember(Order = 2)]
9: public string LastName
10: { get; set; }
11:
12: [DataMember(Order = 3)]
13: public string Gender
14: { get; set; }
15: }
为实现上面的要求,要涉及WCF中一个特殊的概念:数据契约代理(DataContract Surrogate)。WCF通过一个接口System.Runtime.Serialization.IDataContractSurrogate来表示数据契约代理。IDataContractSurrogate用于实现在序列化、反序列化、数据契约的导入和导出过程中对对象或者类型的替换。以上面Contact和Customer为例,在正常的情况下,DataContractSerializer针对类型Customer对一个真正的Customer对象进行序列化,现在要求的是通过DataContractSerializer序列化一个Contact对象,并且要生成与Customer等效的XML,就要在序列化的过程中实现类型的替换(由Contact类型替换成Customer类型)和对象的替换(由Contact对象替换成Customer对象)。
我们先来看看IDataContractSurrogate的定义,序列化相关的方法有以下3个,如果想具体了解IDataContractSurrogate在数据契约导入、导出,以及代码生成方面的应用可以参考MSDN相关文档,在这里就不多作介绍了。
- GetDataContractType:获取进行序列化、反序列化或者数据契约导入导出基于的数据契约的类型,实现此方法相当于实现了类型的替换;
- GetObjectToSerialize:在序列化之前获取序列化的对象,实现了此方法相当于为序列化实现了对象替换;
- GetDeserializedObject:当完成反序列化工作后,通过方法获得被反序列化生成的对象,通过此方法可以用新的对象替换掉真正被反序列化生成的原对象。
1: public interface IDataContractSurrogate
2: {
3: Type GetDataContractType(Type type);
4: object GetObjectToSerialize(object obj, Type targetType);
5: object GetDeserializedObject(object obj, Type targetType);
6:
7: object GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType);
8: object GetCustomDataToExport(Type clrType, Type dataContractType);
9: void GetKnownCustomDataTypes(Collection<Type> customDataTypes);
10: Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData);
11: CodeTypeDeclaration ProcessImportedType(CodeTypeDeclaration typeDeclaration, CodeCompileUnit compileUnit);
12: }
现在我专门为Contact和Customer之间的转换创建了一个自定义的DataContractSurrogate:ContractSurrogate。在GetDataContractType中,如果发现类型是Contact,则替换成Customer。在GetObjectToSerialize方法中,将用于序列化的Contact对象用Customer对象替换,而在GetDeserializedObject中则用Contact对象替换反序列化生成的Customer对象。
1: public class ContractSurrogate : IDataContractSurrogate
2: {
3:
4: public object GetCustomDataToExport(Type clrType, Type dataContractType)
5: {
6: return null;
7: }
8:
9: public object GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType)
10: {
11: return null;
12: }
13:
14: public Type GetDataContractType(Type type)
15: {
16: if (type == typeof(Contact))
17: {
18: return typeof(Customer);
19: }
20:
21: return type;
22: }
23:
24: public object GetDeserializedObject(object obj, Type targetType)
25: {
26: Customer customer = obj as Customer;
27: if (customer == null)
28: {
29: return obj;
30: }
31:
32: return new Contact
33: {
34: FullName = string.Format("{0} {1}", customer.FirstName, customer.LastName),
35: Sex = customer.Gender
36: };
37: }
38:
39: public void GetKnownCustomDataTypes(Collection<Type> customDataTypes)
40: {
41:
42: }
43:
44: public object GetObjectToSerialize(object obj, Type targetType)
45: {
46: Contact contact = obj as Contact;
47: if (contact == null)
48: {
49: return obj;
50: }
51:
52:
53: return new Customer
54: {
55: FirstName = contact.FullName.Split(" ".ToCharArray())[0],
56: LastName = contact.FullName.Split(" ".ToCharArray())[1],
57: Gender = contact.Sex
58: };
59: }
60:
61: public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
62: {
63: return null;
64: }
65:
66: public CodeTypeDeclaration ProcessImportedType(CodeTypeDeclaration typeDeclaration, CodeCompileUnit compileUnit)
67: {
68: return typeDeclaration;
69: }
70: }
为了演示ContractSurrogate在序列化和反序列化中所起的作用,创建了Serialize<T>和Deserialize<T>两个辅助方法,通过创建DataContractSerializer进行序列化和反序列化。方法中的dataContractSurrogate参数被传入DataContractSerializer的构造函数中。
1: public static void Serialize<T>(T instance, string fileName, IDataContractSurrogate dataContractSurrogate)
2: {
3: DataContractSerializer serializer = new DataContractSerializer(typeof(T), null, int.MaxValue, false, false, dataContractSurrogate);
4: using (XmlWriter writer = new XmlTextWriter(fileName, Encoding.UTF8))
5: {
6: serializer.WriteObject(writer, instance);
7: Process.Start(fileName);
8: }
9: }
10:
11: public static T Deserialize<T>( string fileName, IDataContractSurrogate dataContractSurrogate)
12: {
13: DataContractSerializer serializer = new DataContractSerializer(typeof(T), null, int.MaxValue, false, false, dataContractSurrogate);
14: using (XmlReader reader = new XmlTextReader(fileName))
15: {
16: return (T)serializer.ReadObject(reader);
17: }
18: }
借助于上面定义的ContractSurrogate和两个辅助方法,我们通过下面的程序演示IDataContractSurrogate在序列化和反序列化过程中所起的作用。
1: string fileName = @"E:\contact.xml";
2: Contact contactToSerialize = new Contact
3: {
4: FullName = "Bill Gates",
5: Sex = "Male"
6: };
7: IDataContractSurrogate dataContractSurrogate = new ContractSurrogate();
8: Serialize<Contact>(contactToSerialize, fileName, dataContractSurrogate);
9:
10: Contact contactToDeserialize = Deserialize<Contact>(fileName, dataContractSurrogate);
11: Console.WriteLine("contactToSerialize.Equals(contactToDeserialize) = {0}", contactToSerialize.Equals(contactToDeserialize) );
下面的XML表述Contract对象被序列化后的结果,显而易见,这和真正序列化一个Customer对象是完全一样的。不仅如此,基于下面一段XML反序列化生成的Contact对象和用于序列化的对象是相等的,这通过最终的输出结果可以看出来。
1: <Customer xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.artech.com">
2: <FirstName>Bill</FirstName>
3: <LastName>Gates</LastName>
4: <Gender>Male</Gender>
5: </Customer>
输出结果:
1: contactToSerialize.Equals(contactToDeserialize) = True
在进行服务寄宿的时候,可以通过如下代码指定IDataContractSurrogate。
1: using (ServiceHost serviceHost = new ServiceHost(typeof(InventoryCheck)))
2: foreach (ServiceEndpoint ep in serviceHost.Description.Endpoints)
3: {
4: foreach (OperationDescription op in ep.Contract.Operations)
5: {
6: DataContractSerializerOperationBehavior dataContractBehavior =
7: op.Behaviors.Find<DataContractSerializerOperationBehavior>()
8: as DataContractSerializerOperationBehavior;
9: if (op.Behaviors.Find<DataContractSerializerOperationBehavior>()
10: != null)
11: dataContractBehavior.DataContractSurrogate = new ContractSurrogate();
12: op.Behaviors.Add(op.Behaviors.
13: Find<DataContractSerializerOperationBehavior>());
14:
15: dataContractBehavior = new DataContractSerializerOperationBehavior(op);
16: dataContractBehavior.DataContractSurrogate =
17: new ContractSurrogate ();
18: op.Behaviors.Add(dataContractBehavior);
19: }
20: }
注:部分内容节选自《WCF技术剖析(卷1)》第五章:序列化与数据契约(Serialization and Data Contract)
出处:http://artech.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
WCF技术剖析之十五:数据契约代理(DataContractSurrogate)在序列化中的作用的更多相关文章
- WCF技术剖析之十四:泛型数据契约和集合数据契约(下篇)
原文:WCF技术剖析之十四:泛型数据契约和集合数据契约(下篇) [爱心链接:拯救一个25岁身患急性白血病的女孩[内有苏州电视台经济频道<天天山海经>为此录制的节目视频(苏州话)]]在.NE ...
- WCF技术剖析之十二:数据契约(Data Contract)和数据契约序列化器(DataContractSerializer)
原文:WCF技术剖析之十二:数据契约(Data Contract)和数据契约序列化器(DataContractSerializer) [爱心链接:拯救一个25岁身患急性白血病的女孩[内有苏州电视台经济 ...
- WCF技术剖析之十六:数据契约的等效性和版本控制
原文:WCF技术剖析之十六:数据契约的等效性和版本控制 数据契约是对用于交换的数据结构的描述,是数据序列化和反序列化的依据.在一个WCF应用中,客户端和服务端必须通过等效的数据契约方能进行有效的数据交 ...
- WCF技术剖析之十八:消息契约(Message Contract)和基于消息契约的序列化
原文:WCF技术剖析之十八:消息契约(Message Contract)和基于消息契约的序列化 [爱心链接:拯救一个25岁身患急性白血病的女孩[内有苏州电视台经济频道<天天山海经>为此录制 ...
- WCF技术剖析之三十:一个很有用的WCF调用编程技巧[上篇]
原文:WCF技术剖析之三十:一个很有用的WCF调用编程技巧[上篇] 在进行基于会话信道的WCF服务调用中,由于受到并发信道数量的限制,我们需要及时的关闭信道:当遇到某些异常,我们需要强行中止(Abor ...
- WCF技术剖析之十:调用WCF服务的客户端应该如何进行异常处理
原文:WCF技术剖析之十:调用WCF服务的客户端应该如何进行异常处理 在前面一片文章(服务代理不能得到及时关闭会有什么后果?)中,我们谈到及时关闭服务代理(Service Proxy)在一个高并发环境 ...
- WCF技术剖析之十九:深度剖析消息编码(Encoding)实现(下篇)
原文:WCF技术剖析之十九:深度剖析消息编码(Encoding)实现(下篇) [爱心链接:拯救一个25岁身患急性白血病的女孩[内有苏州电视台经济频道<天天山海经>为此录制的节目视频(苏州话 ...
- WCF技术剖析之三十:一个很有用的WCF调用编程技巧[下篇]
原文:WCF技术剖析之三十:一个很有用的WCF调用编程技巧[下篇] 在<上篇>中,我通过使用Delegate的方式解决了服务调用过程中的异常处理以及对服务代理的关闭.对于<WCF技术 ...
- WCF技术剖析之八:ClientBase<T>中对ChannelFactory<T>的缓存机制
原文:WCF技术剖析之八:ClientBase<T>中对ChannelFactory<T>的缓存机制 和传统的分布式远程调用一样,WCF的服务调用借助于服务代理(Service ...
随机推荐
- AutoCAD 2013官方简体中文破解版(32 / 64位),带激活码和注册机
AutoCAD 2014下载地址:http://ideapad.zol.com.cn/61/160_603697.html 安装及破解方法:(注册机下载在下方) 1.安装Autodesk AutoCA ...
- android获取系统wifi状态等
WIFI 获取WIFI状态 WifiManager wifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE); ...
- boost::bind的使用方法
bind - boost 头文件: boost/bind.hpp bind 是一组重载的函数模板.用来向一个函数(或函数对象)绑定某些参数. bind的返回值是一个函数对象. 它的源文件太长了. 看不 ...
- 《Python学习手册》
读书笔记请见Github博客:http://wuxichen.github.io/Myblog/reading/2014/10/04/LearningPython.html
- 性能超越 Redis 的 NoSQL 数据库 SSDB
idea's blog - 性能超越 Redis 的 NoSQL 数据库 SSDB 性能超越 Redis 的 NoSQL 数据库 SSDB C/C++语言编程, SSDB Views: 8091 | ...
- Android中如何判断是否联网
首先在AndroidManifest.xml中添加与连接网络相关的权限: [xhtml] view plain copy <uses-permission android:name=&qu ...
- Unity Notes调制粒子系统的颗粒的最大数目
Unity该粒子系统是很容易使用.这样的问题是在实际的过程中遇到的:以控制的粒子系统组件的动态需要可产生颗粒的最大数目. 看doc他说,有maxParticles控制.却没有这个开放的參数.仅仅能通过 ...
- iOS开发App上传的三大步骤
上传流程 1.itunse connect中->“我的App”中新建创建应用,填写相关的信息 a.项目名称(多创建几个),避免重名 b.想好应用的类型 c.应用截图(5.5,4.7,4,3.5寸 ...
- C# 方法的调用
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- SilkTest天龙八部系列7-动态对象识别
在测试web应用时,我们常常需要面对web页面对象变化频繁,并且使用预定义方式识别对象慢的困难.为了解决这些问题,SilkTest引入了dynamic object recognition技术,它使用 ...