我在数据库中有一个XML文档,它是某个类Foo的实例的XML序列化表示:
<?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>
现在假设我想编写一个返回Foo实例的ASP.NET Web服务方法,如下所示:
[WebMethod]
public Foo GimmeFoo()
{
}
问题:我想返回序列化的Foo,但没有在GimmeFoo()方法中首先反序列化(现实生活中的Foo相当大,将它从反序列化中感到愚蠢之后不久由SOAP精灵自动重新编译数据库。
我是否可以在Web服务(或者我可以在其正文中编写的某些代码)上发布任何属性,这些属性允许我发送Foo实例而无需首先反序列化它?
答案 0 :(得分:1)
这预先假定只有已知的客户端才会调用此服务,因为其他语言可能无法反序列化此xml文件。
在我看来,如果是这种情况,那么为什么不只是有一个REST服务将数据传回,因为你没有正确使用网络服务,IMO。例如,如果我使用GSOAP(在C中)或PHP作为客户端,你的xml文件是否有用,因为我需要自己反序列化它。
反序列化然后让Web服务重新序列化可能是一种痛苦,但IMO,这是正确的方法,如果你必须使用web服务。
此外,如果您传回这个序列化的XML文件(即IMO,这是一个糟糕的设计),那么客户端和服务器之间会有很强的耦合。
答案 1 :(得分:0)
您可以从Web服务返回XmlElement或XmlDocument类型。只需返回序列化的XML。
答案 2 :(得分:0)
我发现了一种可能不是最优雅的方式,但却完成了工作。我们的想法是将所有工作委托给一个自定义的SoapExtension派生类,并且实际上在WebMethod本身中什么也不做 - WebMethod只是作为调用的端点:
[WebMethod]
public Foo GimmeFoo()
{
return null;
}
但是这里有魔力:你编写了一个拦截所有SOAP流量的SoapExtension,当SoapMessageStage.AfterSerialize阶段到达时,你会坚持已经序列化的有效载荷:
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中的属性执行此操作(这就是我所做的):
<system.web>
<webServices>
<soapExtensionTypes>
<add type="SoapSerializationTest.SerializationPassThrough, SoapSerializationTest" priority="1" />
</soapExtensionTypes>
</webServices>
<system.web>
我从中导出这些代码段的原始代码示例位于http://msdn.microsoft.com/en-us/library/7w06t139(VS.85).aspx。