处理第三方Web服务中的无效SOAP消息

在与不同公司的Web服务交互过程中,发现有些服务会返回无效的XML数据。这些数据之所以无效,可能是因为使用了过时的模式,或者存在一些微妙的问题,导致Microsoft的反序列化程序抛出异常。由于需要查看发送给数据,不得不绕过反序列化操作,直接访问原始的SOAP消息,而Microsoft的代码拒绝透露给Web服务。本文解释了是如何通过创建一个特定属性,将其绑定到方法调用上,从而在序列化之前查看SOAP消息,并在需要时记录消息的。

步骤1:在代理代码中插入自定义属性

由于正在使用外部Web服务,要么必须处理Microsoft生成的代理代码,要么必须手动创建它;无论如何,需要找到返回数据的调用位置。那就是将放置专用属性的位置。如果它是一个生成的代理,那么需要查看隐藏的文件Reference.cs,它位于Web服务文件夹中。找到后,定位返回数据的主要方法。那就是需要添加属性以处理反序列化情况的位置。

步骤2:定义自定义属性SoapExtensionAttribute

属性是数据记录过程的钩子。以下是作为属性的类,具有适当的覆盖。

public class ClientSoapLoggerAttribute : SoapExtensionAttribute { private int m_Priority = 0; public override Type ExtensionType { get { return typeof(ClientSoapLogger); } } public override int Priority { get { return m_Priority; } set { m_Priority = value; } } }

步骤3:创建SoapExtension

SOAP扩展将以自主的方式处理SOAP消息的处理流程。目标不是破坏数据流,只是为了数据提取而查看它。

public class ClientSoapLogger : SoapExtension { public Stream oldStream; public Stream newStream; public override object GetInitializer(Type serviceType) { return null; } public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute) { return null; } public override void Initialize(object initializer) { return; } public override Stream ChainStream(Stream stream) { oldStream = stream; newStream = new MemoryStream(); return newStream; } public override void ProcessMessage(SoapMessage message) { switch (message.Stage) { case SoapMessageStage.BeforeDeserialize: LogResponse(message); break; case SoapMessageStage.AfterSerialize: LogRequest(message); break; case SoapMessageStage.AfterDeserialize: case SoapMessageStage.BeforeSerialize: default: break; } } }

步骤4:记录数据

这是真正让头疼的步骤。如果代码在一个Web服务中(代码是一个Web服务调用另一个Web服务),那么如何将数据在SOAP处理和访问代理的代码之间传递呢?在某些情况下,如ASP.NET,可以将消息放在HttpContext中,但这对Web服务代码来说并不是一个选项。下面的代码处理了HttpContext为null的情况,将数据放在Remoting调用上下文中。

public void LogResponse(SoapMessage message) { Copy(oldStream, newStream); newStream.Position = 0; string strSOAPresponse = ExtractFromStream(newStream); HttpContext hc = HttpContext.Current; if (hc != null) hc.Items.Add("SOAPResponse", strSOAPresponse); else System.Runtime.Remoting.Messaging.CallContext.SetData("SOAPResponse", strSOAPresponse); newStream.Position = 0; } private String ExtractFromStream(Stream target) { if (target != null) return (new StreamReader(target)).ReadToEnd(); return ""; } private void Copy(Stream from, Stream to) { TextReader reader = new StreamReader(from); TextWriter writer = new StreamWriter(to); writer.WriteLine(reader.ReadToEnd()); writer.Flush(); } protected virtual void DiagnoseResponseProblem() { HttpContext hc = HttpContext.Current; string SoapResponse = null; string SoapRequest = null; if (hc != null) { SoapRequest = hc.Items["SOAPRequest"].ToString(); SoapResponse = hc.Items["SOAPResponse"].ToString(); } else { try { SoapResponse = System.Runtime.Remoting.Messaging.CallContext.GetData("SOAPResponse").ToString(); SoapRequest = System.Runtime.Remoting.Messaging.CallContext.GetData("SOAPRequest").ToString(); System.Runtime.Remoting.Messaging.CallContext.FreeNamedDataSlot("SOAPResponse"); System.Runtime.Remoting.Messaging.CallContext.FreeNamedDataSlot("SOAPRequest"); } catch (System.Exception) { } } }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485