Mobile WCF Bug???

最近做一个Mobile项目,服务端采用java Xfire的WebService, 客户端为Windows Mobile, Mobile 程序使用 WCF 客户端, 测试环境服务器为Tomcat, 一切正常,迁移到WebLogic 10 出现一个奇怪的问题。

形如下面的服务方法:

    public User GetUser();

其中User为一个自定义引用对象。

 

当服务返回空 (null )时, 使用 NetCFSvcUtil 生成代码调用此方法时,返回的 User 并不为 null,  居然是一个使用默认构造函数构造的 User 对象(所有属性为默认值),最后通过调式代码发现是客户端在处理Xml 中的 Nillable 属性时存在缺陷。

以下是响应的Soap消息体(消息头的命名空间定义省略):

 

<GetUserResonse>

<out>

  <User xsi:nil="true"></User>

</out>

</GetUserResonse>

 

这种格式的XML 使用 XmlSerializer 类进行反序列化会产生非空的 User 对象。

 

而下面这种格式就会产生null对象(正确的解析):

 

<GetUserResonse>

<out>

  <User xsi:nil="true" />

</out>

</GetUserResonse>

 

我就纳闷了,<User xsi:nil="true"></User>和<User xsi:nil="true" />只是表示形式不同,但是XmlSerializer反序列化会产生不同的结果,不知哪位大拿能够给小弟解惑。

 

目前的解决方案,在CFContractSerializer中添加FormatNillable方法:

 

代码
private  Stream FormatNillable(XmlReader reader)
        {
            MemoryStream ms 
=   new  MemoryStream();
            XmlDocument xd 
=   new  XmlDocument();

            xd.Load(reader);
            XmlNamespaceManager manager 
=   new  XmlNamespaceManager(xd.NameTable);
            manager.AddNamespace(
" nn " " http://www.w3.org/2001/XMLSchema-instance " );
            XmlNodeList list 
=  xd.SelectNodes( " //*[@nn:nil = 'true'] " , manager);
            
foreach  (XmlElement element  in  list)
            {
                element.IsEmpty 
=   true ;
            }

            xd.Save(ms);
            ms.Position 
=   0 ;
            
return  ms;
        }

 

 

修改CFContractSerializer的ReadObject方法:

代码
public   override   object  ReadObject(System.Xml.XmlDictionaryReader reader,  bool  verifyObjectName)
        {
            
if  ((verifyObjectName  ==   false ))
            {
                
throw   new  System.NotSupportedException();
            }
            
if  ( this .info.IsWrapped)
            {
                
//  Some WSDLs incorrectly advertise their response message namespaces.
                
//  Attempt to interop with these by coercing our expected namespace to match.
                 if  (( this .serializer.CanDeserialize(reader)  ==   false ))
                {
                    
this .createSerializer( new  System.Xml.XmlQualifiedName(System.Xml.XmlConvert.DecodeName(reader.LocalName), reader.NamespaceURI));
                }
                
using  (Stream stream  =   this .FormatNillable(reader))
                {
                    
return   this .serializer.Deserialize(stream);
                }
            }
            
else
            {
                System.IO.MemoryStream ms 
=   new  System.IO.MemoryStream();
                System.Xml.XmlWriterSettings settings 
=   new  System.Xml.XmlWriterSettings();
                settings.OmitXmlDeclaration 
=   true ;
                System.Xml.XmlWriter innerWriter 
=  System.Xml.XmlDictionaryWriter.Create(ms, settings);
                innerWriter.WriteStartElement(artificialWrapper.Name, artificialWrapper.Namespace);
                
string [] commonPrefixes  =   new   string [] {
                            
" xsi " ,
                            
" xsd " };
                
for  ( int  i  =   0 ; (i  <  commonPrefixes.Length); i  =  (i  +   1 ))
                {
                    
string  ns  =  reader.LookupNamespace(commonPrefixes[i]);
                    
if  ((ns  !=   null ))
                    {
                        innerWriter.WriteAttributeString(
" xmlns " , commonPrefixes[i],  null , ns);
                    }
                }
                
for  (
                ; ((reader.NodeType 
==  System.Xml.XmlNodeType.EndElement)
                            
==   false );
                )
                {
                    innerWriter.WriteNode(reader, 
false );
                }
                innerWriter.WriteEndElement();
                innerWriter.Close();
                ms.Position 
=   0 ;
                
using  (System.Xml.XmlReader innerReader  =  System.Xml.XmlDictionaryReader.Create(ms))
                {
                    
using  (Stream stream  =   this .FormatNillable(innerReader))
                    {
                        
object  obj  =   this .serializer.Deserialize(stream);
                        
return  obj;
                    }
                }
            }
        }

 

 

通过手工格式化这个XML可以处理此问题,但是这里还是恳请高手赐教,这是WCF的BUG还是我对这个问题理解有误?

 

你可能感兴趣的:(mobile)