(如果这里有什么需要澄清/更详细的话,请告诉我。)
我有一个应用程序(C#,2.*框架),它使用SOAP与第三方with服务进行接口。我使用thinktecture的WSCF外接程序对提供的WSDL创建客户端实现。出于我无法控制的原因,SOAP消息交换使用WSE2.0作为安全性(为了包含WSE2.0引用,必须修改thinctecture实现)。除了“正常”数据包之外,我还附加了一个存储的X509证书和一个来自以前调用的二进制安全令牌到另一个web服务。我们正在使用某种类型的SSL加密--我不知道具体细节。
所有必要的序列化/反序列化都包含在web服务客户端中--这意味着当控件在调用客户端后返回给我时,SOAP响应中包含的整个XML字符串对我来说是不可用的--只是反序列化的组件。别误会我的意思--我觉得这很好,因为这意味着我不需要自己去做。
但是,为了让我有一些值得存储/存档的东西,我必须在根元素中重新序列化数据。这似乎是浪费资源,因为我的结果是在SOAP响应。
现在问我的问题:我如何才能访问SOAP响应的“清除”版本,这样我就不必重新序列化存储/归档的所有内容了?
编辑--我的应用程序是一个运行为网络服务的“无格式”windows应用程序--由WebsphereMQ客户端触发器监视器触发。我不认为ASP.NET解决方案适用。
编辑--因为到目前为止的共识是,我的应用程序是否是ASP.NET并不重要,所以我会给CodeMelt(以及克里斯的)解决方案一个机会。
发布于 2008-11-01 23:49:17
您可以利用现有WSE2.0框架中的SoapExtension来拦截来自服务器的响应。
public class MyClientSOAPExtension : SoapExtension
{
Stream oldStream;
Stream newStream;
// Save the Stream representing the SOAP request or SOAP response into
// a local memory buffer.
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:
// before the XML deserialized into object.
break;
case SoapMessageStage.AfterDeserialize:
break;
case SoapMessageStage.BeforeSerialize:
break;
case SoapMessageStage.AfterSerialize:
break;
default:
throw new Exception("Invalid stage...");
}
}
}在SoapMessageStage.BeforeDeserialize的阶段,您可以从旧流读取所需的预期数据(例如,使用XmlReader)。然后将预期的数据存储在某个地方供自己使用,还需要将旧的流数据转发到newstream for web服务稍后阶段才能使用这些数据,例如将XML反序列化为对象。
从MSDN记录web服务的所有流量的示例。
发布于 2011-03-03 12:54:11
下面是一个示例,您可以使用Visual引用来设置http://footballpool.dataaccess.eu/data/info.wso?WSDL
基本上,您必须在webservice调用链中插入一个XmlReader spyer,它将重建原始的XML。
我相信这种方式在某种程度上比使用SoapExtensions更简单。
解决方案是受http://orbinary.com/blog/2010/01/getting-the-raw-soap-xml-sent-via-soaphttpclientprotocol/启发的
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using System.Reflection;
using System.Xml;
namespace ConsoleApplication1 {
public class XmlReaderSpy : XmlReader {
XmlReader _me;
public XmlReaderSpy(XmlReader parent) {
_me = parent;
}
/// <summary>
/// Extracted XML.
/// </summary>
public string Xml;
#region Abstract method that must be implemented
public override XmlNodeType NodeType {
get {
return _me.NodeType;
}
}
public override string LocalName {
get {
return _me.LocalName;
}
}
public override string NamespaceURI {
get {
return _me.NamespaceURI;
}
}
public override string Prefix {
get {
return _me.Prefix;
}
}
public override bool HasValue {
get { return _me.HasValue; }
}
public override string Value {
get { return _me.Value; }
}
public override int Depth {
get { return _me.Depth; }
}
public override string BaseURI {
get { return _me.BaseURI; }
}
public override bool IsEmptyElement {
get { return _me.IsEmptyElement; }
}
public override int AttributeCount {
get { return _me.AttributeCount; }
}
public override string GetAttribute(int i) {
return _me.GetAttribute(i);
}
public override string GetAttribute(string name) {
return _me.GetAttribute(name);
}
public override string GetAttribute(string name, string namespaceURI) {
return _me.GetAttribute(name, namespaceURI);
}
public override void MoveToAttribute(int i) {
_me.MoveToAttribute(i);
}
public override bool MoveToAttribute(string name) {
return _me.MoveToAttribute(name);
}
public override bool MoveToAttribute(string name, string ns) {
return _me.MoveToAttribute(name, ns);
}
public override bool MoveToFirstAttribute() {
return _me.MoveToFirstAttribute();
}
public override bool MoveToNextAttribute() {
return _me.MoveToNextAttribute();
}
public override bool MoveToElement() {
return _me.MoveToElement();
}
public override bool ReadAttributeValue() {
return _me.ReadAttributeValue();
}
public override bool Read() {
bool res = _me.Read();
Xml += StringView();
return res;
}
public override bool EOF {
get { return _me.EOF; }
}
public override void Close() {
_me.Close();
}
public override ReadState ReadState {
get { return _me.ReadState; }
}
public override XmlNameTable NameTable {
get { return _me.NameTable; }
}
public override string LookupNamespace(string prefix) {
return _me.LookupNamespace(prefix);
}
public override void ResolveEntity() {
_me.ResolveEntity();
}
#endregion
protected string StringView() {
string result = "";
if (_me.NodeType == XmlNodeType.Element) {
result = "<" + _me.Name;
if (_me.HasAttributes) {
_me.MoveToFirstAttribute();
do {
result += " " + _me.Name + "=\"" + _me.Value + "\"";
} while (_me.MoveToNextAttribute());
//Let's put cursor back to Element to avoid messing up reader state.
_me.MoveToElement();
}
if (_me.IsEmptyElement) {
result += "/";
}
result += ">";
}
if (_me.NodeType == XmlNodeType.EndElement) {
result = "</" + _me.Name + ">";
}
if (_me.NodeType == XmlNodeType.Text || _me.NodeType == XmlNodeType.Whitespace) {
result = _me.Value;
}
if (_me.NodeType == XmlNodeType.XmlDeclaration) {
result = "<?" + _me.Name + " " + _me.Value + "?>";
}
return result;
}
}
public class MyInfo : ConsoleApplication1.eu.dataaccess.footballpool.Info {
protected XmlReaderSpy _xmlReaderSpy;
public string Xml {
get {
if (_xmlReaderSpy != null) {
return _xmlReaderSpy.Xml;
}
else {
return "";
}
}
}
protected override XmlReader GetReaderForMessage(System.Web.Services.Protocols.SoapClientMessage message, int bufferSize) {
XmlReader rdr = base.GetReaderForMessage(message, bufferSize);
_xmlReaderSpy = new XmlReaderSpy((XmlReader)rdr);
return _xmlReaderSpy;
}
}
class Program {
static void Main(string[] args) {
MyInfo info = new MyInfo();
string[] rest = info.Cities();
System.Console.WriteLine("RAW Soap XML response :\n"+info.Xml);
System.Console.ReadLine();
}
}
}发布于 2020-08-20 02:28:22
旧的线程,但如果其他人希望今天这样做:这些想法利用SoapExtension或创建‘间谍’类是很好的,但不工作在.NET核心。
@mting923关于使用IClientMessageInspector方法的建议在.NET Core3.1中有效;参见此处:在将SOAP消息发送到WebService ( .NET )之前获取它。
生成的SOAP代理类仍然只是幕后的WCF客户端,因此IClientMessageInspector方法可以工作,即使对于调用旧的SOAP服务的.NET核心Azure函数也是如此。在.NET Core3.1Azure函数中,以下内容适用于我:
public class SoapMessageInspector : IClientMessageInspector
{
public string LastRequestXml { get; private set; }
public string LastResponseXml { get; private set; }
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
LastRequestXml = request.ToString();
return request;
}
public void AfterReceiveReply(ref Message reply, object correlationState)
{
LastResponseXml = reply.ToString();
}
}
public class SoapInspectorBehavior : IEndpointBehavior
{
private readonly SoapMessageInspector inspector_ = new SoapMessageInspector();
public string LastRequestXml => inspector_.LastRequestXml;
public string LastResponseXml => inspector_.LastResponseXml;
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
}
public void Validate(ServiceEndpoint endpoint)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.ClientMessageInspectors.Add(inspector_);
}
}然后它可以像这样设置:
var client = new ServiceClient();
var soapInspector = new SoapInspectorBehavior();
client.Endpoint.EndpointBehaviors.Add(soapInspector);在调用客户机代理上的web服务调用之后,soapInspector.LastRequestXml和soapInspector.LastResponseXml将包含原始SOAP请求和响应(作为字符串)。
https://stackoverflow.com/questions/256234
复制相似问题