当前位置:  开发笔记 > 后端 > 正文

从在ASP.net中运行的Web引用客户端获取RAW Soap数据

如何解决《从在ASP.net中运行的Web引用客户端获取RAWSoap数据》经验,为你挑选了5个好方法。

我正试图在我当前的项目中解决一个Web服务客户端问题.我不确定服务服务器的平台(很可能是LAMP).我相信他们身边有一个错误,因为我已经消除了我的客户的潜在问题.客户端是从服务WSDL自动生成的标准ASMX类型Web引用代理.

我需要得到的是RAW SOAP消息(请求和响应)

最好的方法是什么?



1> 小智..:

我进行了以下更改web.config以获取SOAP(请求/响应)信封.这会将所有原始SOAP信息输出到该文件trace.log.


  
  
    
      
        
      
    
    
      
        
      
    
  
  
    
  
  
    
    
  


好.但对我来说XML就像:System.Net详细:0:[14088] 00000000:3C 3F 78 6D 6C 20 76 65-72 73 69 6F 6E 3D 22 31:<?xml version ="1 System.Net详细: 0:[14088] 00000010:2E 30 22 20 65 6E 63 6F-64 69 6E 67 3D 22 75 74:.0"encoding ="ut .......任何想法如何格式化或只有xml数据.?
它已经没用了,我用wireshark来查看原始的SOAP数据.但无论如何,谢谢!
这在2012年2月使用VS 2010对我不起作用.任何人都知道更新的解决方案吗?
这很有帮助.但是,在我的情况下,响应是Gzip并且从组合输出中拉出ASCII或十六进制代码是一种痛苦.他们的替代输出方法是二进制还是仅文本?
@Dediqated - 您可以通过调整上面示例中initializeData属性的值来设置trace.log文件的路径.
这也适用于app.config,我收到不允许maxdatasize字段的消息,但它仍然有效!
要删除十六进制数据,请使用tracemode ="protocolonly".我还设置了maxdatasize ="9999".我得到了这两个属性的警告,但它们都有效.

2> duckworth..:

您可以实现SoapExtension,将完整请求和响应记录到日志文件中.然后,您可以在web.config中启用SoapExtension,这样可以轻松打开/关闭以进行调试.这是我为自己使用找到并修改的一个示例,在我的例子中,日志记录是由log4net完成的,但您可以用自己的方法替换日志方法.

public class SoapLoggerExtension : SoapExtension
{
    private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
    private Stream oldStream;
    private Stream newStream;

    public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute)
    {
        return null;
    }

    public override object GetInitializer(Type serviceType)
    {
        return null;
    }

    public override void Initialize(object initializer)
    {

    }

    public override System.IO.Stream ChainStream(System.IO.Stream stream)
    {
        oldStream = stream;
        newStream = new MemoryStream();
        return newStream;
    }

    public override void ProcessMessage(SoapMessage message)
    {

        switch (message.Stage)
        {
            case SoapMessageStage.BeforeSerialize:
                break;
            case SoapMessageStage.AfterSerialize:
                Log(message, "AfterSerialize");
                    CopyStream(newStream, oldStream);
                    newStream.Position = 0;
                break;
                case SoapMessageStage.BeforeDeserialize:
                    CopyStream(oldStream, newStream);
                    Log(message, "BeforeDeserialize");
                break;
            case SoapMessageStage.AfterDeserialize:
                break;
        }
    }

    public void Log(SoapMessage message, string stage)
    {

        newStream.Position = 0;
        string contents = (message is SoapServerMessage) ? "SoapRequest " : "SoapResponse ";
        contents += stage + ";";

        StreamReader reader = new StreamReader(newStream);

        contents += reader.ReadToEnd();

        newStream.Position = 0;

        log.Debug(contents);
    }

    void ReturnStream()
    {
        CopyAndReverse(newStream, oldStream);
    }

    void ReceiveStream()
    {
        CopyAndReverse(newStream, oldStream);
    }

    public void ReverseIncomingStream()
    {
        ReverseStream(newStream);
    }

    public void ReverseOutgoingStream()
    {
        ReverseStream(newStream);
    }

    public void ReverseStream(Stream stream)
    {
        TextReader tr = new StreamReader(stream);
        string str = tr.ReadToEnd();
        char[] data = str.ToCharArray();
        Array.Reverse(data);
        string strReversed = new string(data);

        TextWriter tw = new StreamWriter(stream);
        stream.Position = 0;
        tw.Write(strReversed);
        tw.Flush();
    }
    void CopyAndReverse(Stream from, Stream to)
    {
        TextReader tr = new StreamReader(from);
        TextWriter tw = new StreamWriter(to);

        string str = tr.ReadToEnd();
        char[] data = str.ToCharArray();
        Array.Reverse(data);
        string strReversed = new string(data);
        tw.Write(strReversed);
        tw.Flush();
    }

    private void CopyStream(Stream fromStream, Stream toStream)
    {
        try
        {
            StreamReader sr = new StreamReader(fromStream);
            StreamWriter sw = new StreamWriter(toStream);
            sw.WriteLine(sr.ReadToEnd());
            sw.Flush();
        }
        catch (Exception ex)
        {
            string message = String.Format("CopyStream failed because: {0}", ex.Message);
            log.Error(message, ex);
        }
    }
}

[AttributeUsage(AttributeTargets.Method)]
public class SoapLoggerExtensionAttribute : SoapExtensionAttribute
{
    private int priority = 1; 

    public override int Priority
    {
        get { return priority; }
        set { priority = value; }
    }

    public override System.Type ExtensionType
    {
        get { return typeof (SoapLoggerExtension); }
    }
}

然后,将以下部分添加到web.config,其中YourNamespace和YourAssembly指向SoapExtension的类和程序集:


  
    
  



3> 小智..:

不知道为什么用web.config或序列化程序类大惊小怪.以下代码对我有用:

XmlSerializer xmlSerializer = new XmlSerializer(myEnvelope.GetType());

using (StringWriter textWriter = new StringWriter())
{
    xmlSerializer.Serialize(textWriter, myEnvelope);
    return textWriter.ToString();
}


`myEnvelope`来自哪里?
我不明白为什么这个答案没有更多的赞成,直接和重点!做得好!
这个答案不会产生肥皂信封,它只是序列化为xml。如何获得肥皂信封的要求?

4> Aaron Fische..:

试试Fiddler2,它会让你检查请求和响应.值得注意的是,Fiddler同时使用http和https流量.


Fiddler可以解密https流量

5> Chuck Bevitt..:

如果对Web引用的调用抛出异常,看起来Tim Carter的解决方案不起作用.我一直试图获得原始网络共鸣,所以我可以在抛出异常后在错误处理程序中检查它(在代码中).但是,我发现当调用抛出异常时,Tim的方法写的响应日志是空白的.我并不完全理解代码,但看起来Tim的方法在.Net已经失效并放弃了Web响应之后切入了这个过程.

我正在与一个使用低级编码手动开发Web服务的客户端合作.此时,他们将自己的内部进程错误消息作为HTML格式的消息添加到SOAP格式化响应之前的响应中.当然,自动化的.Net网络参考会对此产生影响.如果我在抛出异常后得到原始HTTP响应,我可以查找并解析混合返回HTTP响应中的任何SOAP响应,并知道他们收到的数据是否正常.

后来......

这是一个有效的解决方案,即使在执行之后(注意我只是在响应之后 - 也可以得到请求):

namespace ChuckBevitt
{
    class GetRawResponseSoapExtension : SoapExtension
    {
        //must override these three methods
        public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute)
        {
            return null;
        }
        public override object GetInitializer(Type serviceType)
        {
            return null;
        }
        public override void Initialize(object initializer)
        {
        }

        private bool IsResponse = false;

        public override void ProcessMessage(SoapMessage message)
        {
            //Note that ProcessMessage gets called AFTER ChainStream.
            //That's why I'm looking for AfterSerialize, rather than BeforeDeserialize
            if (message.Stage == SoapMessageStage.AfterSerialize)
                IsResponse = true;
            else
                IsResponse = false;
        }

        public override Stream ChainStream(Stream stream)
        {
            if (IsResponse)
            {
                StreamReader sr = new StreamReader(stream);
                string response = sr.ReadToEnd();
                sr.Close();
                sr.Dispose();

                File.WriteAllText(@"C:\test.txt", response);

                byte[] ResponseBytes = Encoding.ASCII.GetBytes(response);
                MemoryStream ms = new MemoryStream(ResponseBytes);
                return ms;

            }
            else
                return stream;
        }
    }
}

以下是在配置文件中配置它的方法:


     ...
  
    
      
        
      
    
  

"TestCallWebService"应该替换为库的名称(恰好是我正在使用的测试控制台应用程序的名称).

你真的不应该去ChainStream; 你应该能够从ProcessMessage更简单地做到:

public override void ProcessMessage(SoapMessage message)
{
    if (message.Stage == SoapMessageStage.BeforeDeserialize)
    {
        StreamReader sr = new StreamReader(message.Stream);
        File.WriteAllText(@"C:\test.txt", sr.ReadToEnd());
        message.Stream.Position = 0; //Will blow up 'cause type of stream ("ConnectStream") doesn't alow seek so can't reset position
    }
}

如果您查找SoapMessage.Stream,它应该是一个只读流,您可以使用它来检查此时的数据.这是一个搞砸的原因,如果您确实读取了流,后续处理炸弹没有发现数据错误(流已结束)并且您无法将位置重置为开头.

有趣的是,如果您同时使用ChainStream和ProcessMessage两种方法,ProcessMessage方法将起作用,因为您在ChainStream中将流类型从ConnectStream更改为MemoryStream,而MemoryStream允许搜索操作.(我尝试将ConnectStream转换为MemoryStream - 不允许.)

所以.....微软应该允许在ChainStream类型上进行搜索操作,或者使SoapMessage.Stream真正成为一个只读副本.(写你的国会议员等......)

还有一点.在异常之后创建了一种检索原始HTTP响应的方法之后,我仍然没有得到完整的响应(由HTTP嗅探器确定).这是因为当开发Web服务将HTML错误消息添加到响应的开头时,它没有调整Content-Length标头,因此Content-Length值小于实际响应主体的大小.我得到的只是Content-Length值的字符数 - 其余的都没有了.显然,当.Net读取响应流时,它只读取Content-Length的字符数,并且不允许Content-Length值可能出错.这是应该的; 但是如果Content-Length标头值错误,那么获得整个响应体的唯一方法就是使用HTTP嗅探器(来自http://www.ieinspector.com的 I user HTTP Analyzer ).

推荐阅读
携手相约幸福
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有