最近做一个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还是我对这个问题理解有误?

 

posted on 2010-07-15 15:08  sharping  阅读(1214)  评论(2编辑  收藏  举报