关于自定义实体类和Web服务之间的类型共享

由于个人习惯使用自定义实体类,所以在写Web服务时常常返回的是实体类或是它的数组。刚开始还可以,但时间一长,老觉的默认的方法在共享类型上太麻烦。直到最近才发现只要小小的一点改变就可以解决问题。因为自己已经走了很长时间的弯路,所以不希望大家也和小弟犯同样的错误,就在此斗胆把自己的心得和一些想法写出来。
 
举例来说:
 有这样的一个项目 RemoteGetObj
  里面有3个子项目: 一个 类库 Obj_Lib;一个 Web 服务 RetObj_WebSer;一个 WinForm  ClientFrom
  其中 RetObj_WebSer ClientFrom 引用 Obj_Lib  ClientFrom又引用 RetObj_WebSer Web服务
 
Obj_Lib 的数据定义如下:
< Serializable() >  _
Public   Structure BaseObj
    
Public sName As String
End Structure
 
Web 服务 RetObj_WebSer 义如下
     < WebMethod() >  _
    
Public   Function GetObjWebSer() As Obj_Lib.BaseObj
        
Dim ret As Obj_Lib.BaseObj
        ret.sName 
= "hello world"
        
Return ret
End Function
 
客户端 ClientFrom 如果按默认的Web服务代理生成的代码如下
  ' <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)> _
         Public   Function GetObjWebSer() As BaseObj
            
Dim results() As Object = Me.Invoke("GetObjWebSer"New Object(-1) {})
            
Return CType(results(0),BaseObj)
        
End Function

    
< System.Xml.Serialization.XmlTypeAttribute([ Namespace]:="http://tempuri.org/RemoteObject_WebSer/Service1")> _
    
Public Class BaseObj
        
        
'<remarks/>
        Public sName As String
End Class
 
 
在调用它的时候,GetObjWebSer 函数返回的是 [Web服务名].BaseObj,而不是它们共同引用的Obj_Lib.BaseObj。两个类型虽然类型名称一样 并且 数据结构也完全一样。但由于命名空间的不同,.Net会认为他们完全不同,所以不能用等号直接拷贝。
以前一直不以为这是个问题,无非再写一次等量拷贝代码,就是用一段机械性的代码把一个类型复制到另一个代码上。可后来发现随着代码量的上升和实体类数量的增加,这种笨方法无论在代码的可读性、维护性和结构上不行;更令人不能忍受的是在性能和内存使用上完全的失败。遗憾的是,当发现问题时为时已晚,大量的现有的重复代码已经无法再修改了,所以当时用了个利用反射功能自动复制这些重复的类的方法 ,可无奈性能就此无法令人接受;最后在网上疯狂学习,总算勉强搞了个用反射在运行时动态生成可执行代码来完成复制类的功能,虽然稳定性不好,但毕竟混过了当时的任务。
在结束这次任务后,我马上开始研究解决这个问题的办法,最近总算有了些小想法,供大家参考.
1 、最简单的方法: 修改代理类的源代码。
   仔细看发现代理类函数不是直接生成类返回的
         Public   Function GetObjWebSer() As BaseObj
            
Dim results() As Object = Me.Invoke("GetObjWebSer"New Object(-1) {})
            
Return CType(results(0),BaseObj)
        
End Function
   从上面可以看出几个特点 Invoke 后的服务名必须和函数名一致,我曾尝试修改函数名结果返回了个“服务名无效”的错误。
   第二行代码 用Ctype来手动制定返回数据的类型。
   由此推测有如下可能:Invoke 函数可能利用反射,通过第一个参数获得当前函数的返回类型,再找到该类型的构造函数,创建一个该类型的实例。利用SOAP 返回的XML ,根据XML 节点查找该类型是否有和SOAP 里的节点名称一致的Field ,有的话赋值,没得话跳过。 那么我们改动如下
         Public   Function GetObjWebSer() As Obj_Lib.BaseObj
            
Dim results() As Object = Me.Invoke("GetObjWebSer"New Object(-1) {})
            
Return CType(results(0), Obj_Lib.BaseObj)
        
End Function
 
结果,只要这么小小的改动一下,Web服务的代理类就可以直接返回自定义的实体类。(当时发现时 狂吐血2小时,我的青春啊~~~白白浪费了)。后来再做了试验,得到的结论是:不一定要原来的自定义实体类。任何类型,只要包含原来实体类里有效数据相同的数据名称就可了。Eg:
< Serializable() >  _
Public   Structure ClassA
    
Public sName As String
End Structure
 也可以
这种方法快速有效,但有个小问题。Web服务不是一次编写就能好的,难不了要修改结构。
只要使用一次“更新 Web 引用”的命令,就又要修改一次原代码
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值