2009-04-23 47 views
1

我有在数据库中,这是有一定类Foo的一个实例的XML的序列化表示的XML文档:返回从其XML表示的复杂类型在.NET网络服务

<?xml version="1.0" encoding="utf-16"?> 
<Foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    <StringProp>hello</StringProp> 
    <IntProp>5</IntProp> 
</Foo> 

假设现在我想写一个返回美孚的一个实例的ASP.NET Web服务方法,像这样:

[WebMethod] 
public Foo GimmeFoo() 
{ 
} 

的问题:我想回到系列化富,但不首先反序列化它GimmeFoo内( )方法(Foo真实生活是相当大的,从DB反序列化它然后让SOAP精灵在不久之后自动进行反序列化会感觉很愚蠢)。

是否有任何属性可以在Web服务(或者我可以在其主体中编写的某些代码)上使用,它允许我发送Foo实例而无需先将其反序列化?

+0

圭多 - 如果切换到WCF,你可以* *(如果你真的想)使用无类型的“消息”型的参数,它可能会实现这一点 - 你可以手动编写你的消息体(如XML)。不过,我认为ASP.NET Web服务不会提供这种服务。 – 2009-04-23 20:46:41

回答

0

我发现了一种方法,可能不是最优雅,但能够完成任务。我们的想法是委托所有工作到自定义的SoapExtension派生类,实际上什么也不做在的WebMethod本身 - 将WebMethod只是有作为呼叫端点:

[WebMethod] 
public Foo GimmeFoo() 
{ 
    return null; 
} 

但这里的神奇:你写的拦截所有SOAP流量,而当SoapMessageStage.AfterSerialize阶段到达一个的SoapExtension,你在那里坚持你已经系列化有效载荷:

public class SerializationPassThrough : SoapExtension 
{ 
    private Stream oldStream; 
    private Stream newStream; 

    // Other overrides... 

    public override void ProcessMessage(SoapMessage message) 
    { 
     switch (message.Stage) 
     { 
      case SoapMessageStage.BeforeSerialize: 
       // ... 
       break; 
      case SoapMessageStage.AfterSerialize: 
       string newOutput = ReadPreCookedResponseFromDB(); 
       RewriteOutput(newOutput); 
       break; 
      case SoapMessageStage.BeforeDeserialize: 
       // ... 
       break; 
      case SoapMessageStage.AfterDeserialize: 
       // ... 
       break; 
      default: 
       throw new Exception("invalid stage"); 
     } 
    } 

    private void RewriteOutput(string output) 
    { 
     newStream.Position = 0; 
     StreamWriter sw = new StreamWriter(newStream); 
     sw.Write(output); 
     sw.Flush(); 
     newStream.Position = 0; 
     Copy(newStream, oldStream); 
     newStream.Position = 0; 
    } 

    private void Copy(Stream from, Stream to) 
    { 
     TextReader reader = new StreamReader(from); 
     TextWriter writer = new StreamWriter(to); 
     string toWrite = reader.ReadToEnd(); 

     writer.WriteLine(toWrite); 
     writer.Flush(); 
    } 

} 

最后的触摸:您需要指示ASP.NET运行时使用你的SoapExtension。您可以在通过的WebMethod属性做到这一点,或在web.config中(这是我做的):从我得到的这些片段是在http://msdn.microsoft.com/en-us/library/7w06t139(VS.85).aspx

<system.web> 
    <webServices> 
    <soapExtensionTypes> 
     <add type="SoapSerializationTest.SerializationPassThrough, SoapSerializationTest" priority="1" /> 
    </soapExtensionTypes> 
    </webServices> 
<system.web> 

原代码样本。

1

这预示着只有一个已知的客户会调用这个服务,因为其他语言可能无法反序列化此XML文件。

在我看来,如果是这样的话,那么为什么不只是有一个REST服务,将传回数据,因为你没有正确使用web服务,IMO。例如,如果我使用gSOAP的(C语言)或者PHP作为一个客户端,将XML文件是有用的,因为我将需要反序列化它自己。

这可能是反序列化,然后让Web服务重新序列化一个痛苦,但海事组织,这是正确的方式,再次,如果你必须使用一个Web服务。

而且,你的客户端和服务器之间有很强的耦合,如果你传回这个序列化的XML文件,这是再次IMO,一个不好的设计。

+0

XML文件我已经使用System.Xml.Serialization.XmlSerializer,这是由SOAP基础设施中使用的相同的序列化。是否真的没有办法告诉ASP。NET“看,这些东西是预先序列化的,只是使用它”? – 2009-04-23 20:40:42

0

您可以从Web服务返回的XmlElement或XmlDocument的类型。只需返回你的序列化的XML。