深入Atlas系列:Web Sevices Access in Atlas示例(2) - 自定义JavaScriptConverter处理循环引用对象

简介:
中 我举了一个简单例子,说明了存在循环引用的对象在序列化时,服务器端和客户端都会出现异常。在这篇文章里,我将通过一个示例来说明如何通过自定义 JavaScriptConverter来处理存在循环引用的对象。这个示例所用的方式也基本上可以在处理复杂对象时使用,因为复杂对象最重要的一点就是 存在复杂引用,其余的特点,估计也就是成员较多了。

  同样,我们先定义存在循环引用的类。他们依旧是Boy和Girl,能够互相引用。代码如下:
ContractedBlock.gif  Boy类与Girl类代码

  然后,我们就一一发现问题,并解决它:

一、解决服务器端序列化问题:

  我们先写需要使用的Web Services方法:
ContractedBlock.gif  GetBoyWithGirlfriend方法

  很显然,它们存在循环引用,如果使用了Atlas内部的JSON序列化方法的话,就会抛出异常。那么我们该怎么解决这个问题呢?方法就是自定 义一个JavaScriptConvert。在这里,我们写一个BoyConverter,首先重载它的SupportedTypes属性,表明这个 Converter所支持的类型。
ContractedBlock.gif  SupportedTypes属性代码

  在之前文章中我们分析的代码可知,这个属性只有在初始化的Converter映射的时候被调用一次,所以我们能够直接new一个数组并返回,不会有任何的性能损失。

   接下来我们要做的事情就是重载JavaScriptConverter的Serialize方法了,它接受一个object对象作为参数,输出序列化结 果。由于我们需要序列化后的对象也保持着循环引用,因此完全使用JSON方式是无法做到的,那么我们该怎么做呢?我们知道,在客户端反序列化服务器端传来 的结果,使用的就是简单的“eval("(" + body + ")")”这样的方法,由于这一点,我们来看一下下面的代码被“反序列化”时会得到什么结果呢?  
function (){  return   100 ; }.call()

  得到的结果就是100!在这里,其实我们定义了一个函数,并过它的call方法进行了调用。在函数体中,我们可以写任意的代码,任意多的语句。这样,我们的做法就显而易见了。代码如下:
ContractedBlock.gif  Serialize方法

  首先判断对象o是不是Boy类型,如果不是,那么抛出异常。然后就通过拼接字符串输出。事实上,对于一个良好实现的Serialize方法, 它需要判断传入的Boy对象的Girlfriend属性是否为null等信息,然后输出不同的结果。在这里,仅仅是一个演示,我就没有过多追究了。:)

  我们的Serialize方法写完了,然后就要使用它了。请注意,为了使用它,我们需要将它添加到Web.config文件的相应节点中,如下:
< microsoft .web >
    
< converters >
        ……
        
< add  type ="Jeffz.JavaScriptConvertDemo.BoyConverter"   />
    
</ converters >
    ……
</ microsoft.web >

  于是我们就来看一下它的使用代码,首先是HTML
ContractedBlock.gif  HTML代码

  点击“Get!”按钮将会调用Web Services方法,并将结果显示在“GetBoyWithGirlfriend”这个DIV中。所需的Javascript如下:
ContractedBlock.gif  getBoyWithGirlfriend函数代码

  代码非常简单,就不多说了,如果得到了正确结果,那么会在DIV中显示“You did a good job!”等字样,我们直接来看一下使用效果吧:

  打开之后:
JSConverter_1.jpg

  在文本框内填上信息,并点击“Get!”按钮。得到正确结果了:
JSConverter_2.jpg

  我们看一下Fiddler获得的信息:
JSConverter_3.jpg

  很明显,我们自定义的BoyConverter生效了。:)



二、解决客户端序列化和服务器端反序列化的问题:

  再写一个Web Services方法,接收一个Boy类型的对象作为参数:
ContractedBlock.gif  SetBoyWithGirlfriend方法代码

  这次我们先来看HTML代码,和前一个例子的代码非常相似:
ContractedBlock.gif  HTML代码

  在客户端,如果构造了循环引用的对象,如果使用了默认的序列化方法,将会无限递归最终Stack Overflow。在《 深入Atlas系列:Web Sevices Access in Atlas(4) - 对于复杂数据类型的支持(上) 》中,我们看出我们可以为对象附加一个serialize方法来自定义序列化方式。那么我们就来看一下这个方法的代码:
ContractedBlock.gif  serialize方法代码

  我们最终还是会使用Sys.Serialization.JSON.serialize方法来序列化一个客户端对象,不过在这之前需要进行处 理。首先delete该对象上的serialize方法,否则调用Sys.Serialization.JSON.serialize方法时又将进入当前 的serialize函数。接下来的delete操作删除循环引用,最后才使用Sys.Serialization.JSON.serialize方法序 列化该对象。注意,在得到了序列化结果之后,需要this对象的状态恢复,例如serialize函数和循环引用。

  然后,在服务器端,我们在BoyConverter内重载Desirialize方法,目的是得到反序列化后的Boy对象。代码如下:
ContractedBlock.gif  Deserialize方法代码

  首先判断t的类型是不是Boy,然后调用基类的Deserialize方法进行反序列化。这个方法会调用Atlas内部的反序列化方法,而且 避开对于某个反序列化类型寻找相应Converter的逻辑,否则又会出现了无限递归,最终抛出StackOverflowException。最后,当 然就是恢复boy对象与boy.Girlfriend之间的循环引用了。

  我们来看一下客户端的Javascript代码:
ContractedBlock.gif  setBoyWithGirlfriend方法

  越来越感受到Function.createDelegete方法(第5行)的重要性。如果没有它,很多功能的实现都会麻烦许多。

  我们来看一下使用效果。首先,打开页面:
JSConverter_4.jpg

  在文本框内填写信息,并点击“Set!”按钮:
JSConverter_5.jpg

  说明客户端的序列化操作和反序列化操作都成功了!


三、实现更良好的客户端序列化和服务器端反序列化的代码:

  事实上,我们的序列化代码实现还不够良好。例如,如果boy.Girlfriend.Boyfriend不是boy怎么办呢(……)?因此我们不能在客户端和服务器端简单地处理序列化和反序列化操作。我们需要做一个“标记”。

  我们就在Girl对象中作标记吧,将其代码修改如下:
ContractedBlock.gif  Girl类修改后代码

  需要注意的是__HasClientBoyfriend变量的作用只是为了标记,在序列化Girl类型对象时不应该输出,所以我们使用XmlIgnoreAttribute来禁止其被序列化。

  我们在客户端的serialize方法自然也需要有些修改:
ContractedBlock.gif  serialize方法修改后代码

  在序列化的时候判断了是否的确有循环引用,如果有的话,则在this.Girlfriend对象上做一个__HasClientBoyfriend的标记。

  最后需要修改的就是BoyConverter的Deserialize方法了:
ContractedBlock.gif  修改后Deserialize方法代码

  现在,只有当boy.Girlfriend的__HasClientBoyfriend标记为true时才重新建立循环引用。如果仅仅是一个 普通的boy对象,则不会有多余的操作。如果有朋友感兴趣的话,可以使用Fiddler查看Girl类型的序列化结果,可以发现 __HasClientBoyfriend没有被序列化输出,这就是XmlIgnoreAttribute的效果。

  事实上,上面的代码多少还有点小问题,不过个人认为,作为一个示例来说,这已经足够了。


   在这篇文章中,我演示了JavaScriptConverter的基本使用,但是它的作用还不止这些。不知道大家有没有发现,在上面的示例中如果需要在 客户端作序列化操作,则需要在客户端与服务器端同时进行代码维护。显然这种做法非常不利于分发和部署组件。在今后的示例中,我将配合Atlas为Web Service方法建立Proxy的讲解,演示如何使用JavaScriptConverter来将所有的代码都在服务器端进行维护。不过那会涉及到目前 所有的文章,另外还包括以后会讲到的Atlas为Web Services方法建立Proxy方面的内容。结合Atlas的方方面面,能使我们的开发更为成熟。  


  点击这里下载示例源文件。


本文转自 jeffz 51CTO博客,原文链接:xxxhttp://blog.51cto.com/jeffz/60798xxx,如需转载请自行联系原作者

相关文章
|
17天前
|
安全 前端开发 API
【Azure 应用服务】Azure Web App 服务默认支持一些 Weak TLS Ciphers Suite,是否有办法自定义修改呢?
【Azure 应用服务】Azure Web App 服务默认支持一些 Weak TLS Ciphers Suite,是否有办法自定义修改呢?
|
19天前
|
前端开发 开发者
new操作符背后的秘密:揭开Web前端对象创建的神秘面纱!
【8月更文挑战第23天】在Web前端开发中,`new`操作符是创建对象实例的核心。本文以`Person`构造函数为例,通过四个步骤解析`new`操作符的工作原理:创建空对象、设置新对象原型、执行构造函数并调整`this`指向、判断并返回最终对象。了解这些有助于开发者更好地理解对象实例化过程,从而编写出更规范、易维护的代码。
23 0
|
20天前
|
XML JavaScript 测试技术
Web自动化测试框架(基础篇)--HTML页面元素和DOM对象
本文为Web自动化测试入门指南,介绍了HTML页面元素和DOM对象的基础知识,以及如何使用Python中的Selenium WebDriver进行元素定位、操作和等待机制,旨在帮助初学者理解Web自动化测试中的关键概念和操作技巧。
33 1
|
11天前
|
开发者 Java Spring
【绝技揭秘】掌握Vaadin数据绑定:一键同步Java对象,告别手动数据烦恼,轻松玩转Web应用开发!
【8月更文挑战第31天】Vaadin不仅是一个功能丰富的Java Web应用框架,还提供了强大的数据绑定机制,使开发者能轻松连接UI组件与后端Java对象,简化Web应用开发流程。本文通过创建一个简单的用户信息表单示例,详细介绍了如何使用Vaadin的`Binder`类实现数据绑定,包括字段与模型属性的双向绑定及数据验证。通过这个示例,开发者可以更专注于业务逻辑而非繁琐的数据同步工作,提高开发效率和应用可维护性。
30 0
|
15天前
|
JavaScript PHP 开发者
PHP中的异常处理与自定义错误处理器构建高效Web应用:Node.js与Express框架实战指南
【8月更文挑战第27天】在PHP编程世界中,异常处理和错误管理是代码健壮性的关键。本文将深入探讨PHP的异常处理机制,并指导你如何创建自定义错误处理器,以便优雅地管理运行时错误。我们将一起学习如何使用try-catch块捕获异常,以及如何通过set_error_handler函数定制错误响应。准备好让你的代码变得更加可靠,同时提供更友好的错误信息给最终用户。
|
2月前
|
开发框架 JSON 前端开发
利用查询条件对象,在Asp.net Web API中实现对业务数据的分页查询处理
利用查询条件对象,在Asp.net Web API中实现对业务数据的分页查询处理
|
1月前
|
JavaScript 前端开发 中间件
打造卓越后端:构建高效API的最佳实践与实战代码示例——解锁高性能Web服务的秘密
【8月更文挑战第2天】构建高效后端API:最佳实践与代码示例
52 0
|
2月前
|
网络协议 安全 Python
我们将使用Python的内置库`http.server`来创建一个简单的Web服务器。虽然这个示例相对简单,但我们可以围绕它展开许多讨论,包括HTTP协议、网络编程、异常处理、多线程等。
我们将使用Python的内置库`http.server`来创建一个简单的Web服务器。虽然这个示例相对简单,但我们可以围绕它展开许多讨论,包括HTTP协议、网络编程、异常处理、多线程等。
|
3月前
|
开发框架 .NET API
ASP.NET Core Web中使用AutoMapper进行对象映射
ASP.NET Core Web中使用AutoMapper进行对象映射
|
4月前
|
JavaScript 前端开发 架构师
Web Components:自定义元素与Shadow DOM的实践
Web Components是用于创建可重用自定义HTML元素的技术集合,包括Custom Elements、Shadow DOM、HTML Templates和Slots。通过Custom Elements定义新元素,利用Shadow DOM封装私有样式,&lt;slot&gt;元素允许插入内容。自定义元素支持事件处理和属性观察,可复用且样式隔离。它们遵循Web标准,兼容各前端框架,注重性能优化,如懒加载和Shadow DOM优化。
42 0
下一篇
DDNS