关于自定义实体类和Web服务之间的类型共享
2006-08-27 22:39
375 查看
由于个人习惯使用自定义实体类,所以在写Web服务时常常返回的是实体类或是它的数组。刚开始还可以,但时间一长,老觉的默认的方法在共享类型上太麻烦。直到最近才发现只要小小的一点改变就可以解决问题。因为自己已经走了很长时间的弯路,所以不希望大家也和小弟犯同样的错误,就在此斗胆把自己的心得和一些想法写出来。
举例来说:
有这样的一个项目 RemoteGetObj
[align=left] 里面有3个子项目: 一个类库 Obj_Lib;一个Web服务 RetObj_WebSer;一个WinForm ClientFrom[/align]
其中 RetObj_WebSer 和 ClientFrom 引用 Obj_Lib 而 ClientFrom又引用RetObj_WebSer Web服务
Obj_Lib 的数据定义如下:
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
<Serializable()> _
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedBlock.gif)
Public Structure BaseObjStructure BaseObj
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
Public sName As String
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif)
End Structure
Web 服务RetObj_WebSer 义如下
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
<WebMethod()> _
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedBlock.gif)
Public Function GetObjWebSer()Function GetObjWebSer() As Obj_Lib.BaseObj
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
Dim ret As Obj_Lib.BaseObj
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
ret.sName = "hello world"
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
Return ret
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif)
End Function
客户端 ClientFrom 如果按默认的Web服务代理生成的代码如下
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
'<remarks/> <System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/RemoteObject_WebSer/Service1/GetObjWebSer", RequestNamespace:="http://tempuri.org/RemoteObject_WebSer/Service1", ResponseNamespace:="http://tempuri.org/RemoteObject_WebSer/Service1", Use:=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle:=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)> _
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedBlock.gif)
Public Function GetObjWebSer()Function GetObjWebSer() As BaseObj
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
Dim results() As Object = Me.Invoke("GetObjWebSer", New Object(-1) {})
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
Return CType(results(0),BaseObj)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif)
End Function
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedBlock.gif)
<System.Xml.Serialization.XmlTypeAttribute([Namespace ]Namespace]:="http://tempuri.org/RemoteObject_WebSer/Service1")> _
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedSubBlock.gif)
Public Class BaseObjClass BaseObj
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
'<remarks/>
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
Public sName As String
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockEnd.gif)
End Class
在调用它的时候,GetObjWebSer 函数返回的是 [Web服务名].BaseObj,而不是它们共同引用的Obj_Lib.BaseObj。两个类型虽然类型名称一样 并且 数据结构也完全一样。但由于命名空间的不同,.Net会认为他们完全不同,所以不能用等号直接拷贝。
以前一直不以为这是个问题,无非再写一次等量拷贝代码,就是用一段机械性的代码把一个类型复制到另一个代码上。可后来发现随着代码量的上升和实体类数量的增加,这种笨方法无论在代码的可读性、维护性和结构上不行;更令人不能忍受的是在性能和内存使用上完全的失败。遗憾的是,当发现问题时为时已晚,大量的现有的重复代码已经无法再修改了,所以当时用了个利用反射功能自动复制这些重复的类的方法 ,可无奈性能就此无法令人接受;最后在网上疯狂学习,总算勉强搞了个用反射在运行时动态生成可执行代码来完成复制类的功能,虽然稳定性不好,但毕竟混过了当时的任务。
在结束这次任务后,我马上开始研究解决这个问题的办法,最近总算有了些小想法,供大家参考.
1 、最简单的方法: 修改代理类的源代码。
仔细看发现代理类函数不是直接生成类返回的
[align=left][/align]
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedBlock.gif)
Public Function GetObjWebSer()Function GetObjWebSer() As BaseObj
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
Dim results() As Object = Me.Invoke("GetObjWebSer", New Object(-1) {})
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
Return CType(results(0),BaseObj)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif)
End Function
[align=left] 从上面可以看出几个特点 Invoke 后的服务名必须和函数名一致,我曾尝试修改函数名结果返回了个“服务名无效”的错误。[/align]
第二行代码 用Ctype来手动制定返回数据的类型。
[align=left] 由此推测有如下可能:Invoke函数可能利用反射,通过第一个参数获得当前函数的返回类型,再找到该类型的构造函数,创建一个该类型的实例。利用SOAP返回的XML,根据XML节点查找该类型是否有和SOAP里的节点名称一致的Field,有的话赋值,没得话跳过。 那么我们改动如下[/align]
[align=left][/align]
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedBlock.gif)
Public Function GetObjWebSer()Function GetObjWebSer() As Obj_Lib.BaseObj
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
Dim results() As Object = Me.Invoke("GetObjWebSer", New Object(-1) {})
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
Return CType(results(0), Obj_Lib.BaseObj)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif)
End Function
[align=left]结果,只要这么小小的改动一下,Web服务的代理类就可以直接返回自定义的实体类。(当时发现时 狂吐血2小时,我的青春啊~~~白白浪费了)。后来再做了试验,得到的结论是:不一定要原来的自定义实体类。任何类型,只要包含原来实体类里有效数据相同的数据名称就可了。Eg: [/align]
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
<Serializable()> _
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedBlock.gif)
Public Structure ClassAStructure ClassA
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
Public sName As String
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif)
End Structure
[align=left] 也可以[/align]
[align=left]这种方法快速有效,但有个小问题。Web服务不是一次编写就能好的,难不了要修改结构。[/align]
[align=left]只要使用一次“更新Web引用”的命令,就又要修改一次原代码。[/align]
举例来说:
有这样的一个项目 RemoteGetObj
[align=left] 里面有3个子项目: 一个类库 Obj_Lib;一个Web服务 RetObj_WebSer;一个WinForm ClientFrom[/align]
其中 RetObj_WebSer 和 ClientFrom 引用 Obj_Lib 而 ClientFrom又引用RetObj_WebSer Web服务
Obj_Lib 的数据定义如下:
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
<Serializable()> _
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedBlock.gif)
Public Structure BaseObjStructure BaseObj
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
Public sName As String
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif)
End Structure
Web 服务RetObj_WebSer 义如下
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
<WebMethod()> _
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedBlock.gif)
Public Function GetObjWebSer()Function GetObjWebSer() As Obj_Lib.BaseObj
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
Dim ret As Obj_Lib.BaseObj
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
ret.sName = "hello world"
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
Return ret
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif)
End Function
客户端 ClientFrom 如果按默认的Web服务代理生成的代码如下
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
'<remarks/> <System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/RemoteObject_WebSer/Service1/GetObjWebSer", RequestNamespace:="http://tempuri.org/RemoteObject_WebSer/Service1", ResponseNamespace:="http://tempuri.org/RemoteObject_WebSer/Service1", Use:=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle:=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)> _
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedBlock.gif)
Public Function GetObjWebSer()Function GetObjWebSer() As BaseObj
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
Dim results() As Object = Me.Invoke("GetObjWebSer", New Object(-1) {})
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
Return CType(results(0),BaseObj)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif)
End Function
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedBlock.gif)
<System.Xml.Serialization.XmlTypeAttribute([Namespace ]Namespace]:="http://tempuri.org/RemoteObject_WebSer/Service1")> _
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedSubBlock.gif)
Public Class BaseObjClass BaseObj
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
'<remarks/>
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
Public sName As String
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockEnd.gif)
End Class
在调用它的时候,GetObjWebSer 函数返回的是 [Web服务名].BaseObj,而不是它们共同引用的Obj_Lib.BaseObj。两个类型虽然类型名称一样 并且 数据结构也完全一样。但由于命名空间的不同,.Net会认为他们完全不同,所以不能用等号直接拷贝。
以前一直不以为这是个问题,无非再写一次等量拷贝代码,就是用一段机械性的代码把一个类型复制到另一个代码上。可后来发现随着代码量的上升和实体类数量的增加,这种笨方法无论在代码的可读性、维护性和结构上不行;更令人不能忍受的是在性能和内存使用上完全的失败。遗憾的是,当发现问题时为时已晚,大量的现有的重复代码已经无法再修改了,所以当时用了个利用反射功能自动复制这些重复的类的方法 ,可无奈性能就此无法令人接受;最后在网上疯狂学习,总算勉强搞了个用反射在运行时动态生成可执行代码来完成复制类的功能,虽然稳定性不好,但毕竟混过了当时的任务。
在结束这次任务后,我马上开始研究解决这个问题的办法,最近总算有了些小想法,供大家参考.
1 、最简单的方法: 修改代理类的源代码。
仔细看发现代理类函数不是直接生成类返回的
[align=left][/align]
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedBlock.gif)
Public Function GetObjWebSer()Function GetObjWebSer() As BaseObj
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
Dim results() As Object = Me.Invoke("GetObjWebSer", New Object(-1) {})
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
Return CType(results(0),BaseObj)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif)
End Function
[align=left] 从上面可以看出几个特点 Invoke 后的服务名必须和函数名一致,我曾尝试修改函数名结果返回了个“服务名无效”的错误。[/align]
第二行代码 用Ctype来手动制定返回数据的类型。
[align=left] 由此推测有如下可能:Invoke函数可能利用反射,通过第一个参数获得当前函数的返回类型,再找到该类型的构造函数,创建一个该类型的实例。利用SOAP返回的XML,根据XML节点查找该类型是否有和SOAP里的节点名称一致的Field,有的话赋值,没得话跳过。 那么我们改动如下[/align]
[align=left][/align]
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedBlock.gif)
Public Function GetObjWebSer()Function GetObjWebSer() As Obj_Lib.BaseObj
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
Dim results() As Object = Me.Invoke("GetObjWebSer", New Object(-1) {})
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
Return CType(results(0), Obj_Lib.BaseObj)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif)
End Function
[align=left]结果,只要这么小小的改动一下,Web服务的代理类就可以直接返回自定义的实体类。(当时发现时 狂吐血2小时,我的青春啊~~~白白浪费了)。后来再做了试验,得到的结论是:不一定要原来的自定义实体类。任何类型,只要包含原来实体类里有效数据相同的数据名称就可了。Eg: [/align]
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
<Serializable()> _
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedBlock.gif)
Public Structure ClassAStructure ClassA
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
Public sName As String
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif)
End Structure
[align=left] 也可以[/align]
[align=left]这种方法快速有效,但有个小问题。Web服务不是一次编写就能好的,难不了要修改结构。[/align]
[align=left]只要使用一次“更新Web引用”的命令,就又要修改一次原代码。[/align]
相关文章推荐
- Web 服务编程技巧及窍门: 改善 J2EE 与 .NET 之间的互操作性——管理集合、数组,乃至原始数据类型 (转)
- 关于父子进程之间的数据共享
- rails关于一个Action的多次或多个Action之间共享数据的思路
- 通过Web服务共享Windows剪贴板.pdf
- 关于tomcat注册成一个服务,并修改启动类型
- 多Web服务器之间共享Session的解决方案
- Delphi7调用web服务的数据类型匹配问题
- 从Web服务中返回自定义对象
- js class模型 关于 初始化key值为非基本类型是 实例之间是引用该变量
- 关于rsync共享服务的几个常见错误
- 关于android 7.0系统怎么添加自定义的系统服务
- 利用微软WebService技术实现远程数据库存取 利用web服务在不同站点间共享同一数据库
- Web 服务所支持的数据类型
- 多Web服务器之间共享Session的解决方案
- 关于web.xml不同版本之间的区别
- web项目与微信对接报错误码48002 Api禁用(一般是管理组类型与Api不匹配,例如普通管理组调用会话服务的Api)
- 让自定义的类型可以和任意的类型之间转换
- 多Web服务器之间共享Session的解决方案
- Java中关于Json对象类型和字符串类型之间互相转化的问题 .
- 关于自定义类型名和函数名相同