Получение НЕОБРАБОТАННЫХ Данных Мыла от веб-Ссылочного Клиента, работающего в ASP.net

92
задан John Saunders 4 September 2012 в 14:19
поделиться

6 ответов

Я внес следующие изменения в web.config для получения SOAP (Запрос/Ответ) Конверт. Это произведет всю необработанную информацию о SOAP в файл trace.log.

<system.diagnostics>
  <trace autoflush="true"/>
  <sources>
    <source name="System.Net" maxdatasize="1024">
      <listeners>
        <add name="TraceFile"/>
      </listeners>
    </source>
    <source name="System.Net.Sockets" maxdatasize="1024">
      <listeners>
        <add name="TraceFile"/>
      </listeners>
    </source>
  </sources>
  <sharedListeners>
    <add name="TraceFile" type="System.Diagnostics.TextWriterTraceListener"
      initializeData="trace.log"/>
  </sharedListeners>
  <switches>
    <add name="System.Net" value="Verbose"/>
    <add name="System.Net.Sockets" value="Verbose"/>
  </switches>
</system.diagnostics>
129
ответ дан Keltex 24 November 2019 в 06:27
поделиться

Можно реализовать SoapExtension, который регистрирует полный запрос и ответ на файл журнала. Можно тогда включить SoapExtension в web.config, который облегчает становиться включения - выключения для отладки целей. Вот пример, который я нашел и изменил для своего собственного использования в моем случае, вход был сделан 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:

<webServices>
  <soapExtensionTypes>
    <add type="YourNamespace.SoapLoggerExtension, YourAssembly" 
       priority="1" group="0" />
  </soapExtensionTypes>
</webServices>
34
ответ дан duckworth 24 November 2019 в 06:27
поделиться

Попробуйте Fiddler2, он позволит Вам осмотреть запросы и ответ. Могло бы стоить отметить, что Скрипач работает и с http и с трафиком HTTPS.

21
ответ дан Aaron Fischer 24 November 2019 в 06:27
поделиться

Я предпочел бы иметь платформу, делают вход для Вас путем сцепления в регистрирующемся потоке, который регистрируется, поскольку платформа обрабатывает тот базовый поток. Следующее не является столь же чистым, как я хотел бы его, так как Вы не можете решить между запросом и ответом в методе ChainStream. Следующее - то, как я обрабатываю его. С благодарностью Jon Hanna для переопределения потоковой идеи

public class LoggerSoapExtension : SoapExtension
{
    private static readonly string LOG_DIRECTORY = ConfigurationManager.AppSettings["LOG_DIRECTORY"];
    private LogStream _logger;

    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)
    {
        _logger = new LogStream(stream);
        return _logger;
    }
    public override void ProcessMessage(SoapMessage message)
    {
        if (LOG_DIRECTORY != null)
        {
            switch (message.Stage)
            {
                case SoapMessageStage.BeforeSerialize:
                    _logger.Type = "request";
                    break;
                case SoapMessageStage.AfterSerialize:
                    break;
                case SoapMessageStage.BeforeDeserialize:
                    _logger.Type = "response";
                    break;
                case SoapMessageStage.AfterDeserialize:
                    break;
            }
        }
    }
    internal class LogStream : Stream
    {
        private Stream _source;
        private Stream _log;
        private bool _logSetup;
        private string _type;

        public LogStream(Stream source)
        {
            _source = source;
        }
        internal string Type
        {
            set { _type = value; }
        }
        private Stream Logger
        {
            get
            {
                if (!_logSetup)
                {
                    if (LOG_DIRECTORY != null)
                    {
                        try
                        {
                            DateTime now = DateTime.Now;
                            string folder = LOG_DIRECTORY + now.ToString("yyyyMMdd");
                            string subfolder = folder + "\\" + now.ToString("HH");
                            string client = System.Web.HttpContext.Current != null && System.Web.HttpContext.Current.Request != null && System.Web.HttpContext.Current.Request.UserHostAddress != null ? System.Web.HttpContext.Current.Request.UserHostAddress : string.Empty;
                            string ticks = now.ToString("yyyyMMdd'T'HHmmss.fffffff");
                            if (!Directory.Exists(folder))
                                Directory.CreateDirectory(folder);
                            if (!Directory.Exists(subfolder))
                                Directory.CreateDirectory(subfolder);
                            _log = new FileStream(new System.Text.StringBuilder(subfolder).Append('\\').Append(client).Append('_').Append(ticks).Append('_').Append(_type).Append(".xml").ToString(), FileMode.Create);
                        }
                        catch
                        {
                            _log = null;
                        }
                    }
                    _logSetup = true;
                }
                return _log;
            }
        }
        public override bool CanRead
        {
            get
            {
                return _source.CanRead;
            }
        }
        public override bool CanSeek
        {
            get
            {
                return _source.CanSeek;
            }
        }

        public override bool CanWrite
        {
            get
            {
                return _source.CanWrite;
            }
        }

        public override long Length
        {
            get
            {
                return _source.Length;
            }
        }

        public override long Position
        {
            get
            {
                return _source.Position;
            }
            set
            {
                _source.Position = value;
            }
        }

        public override void Flush()
        {
            _source.Flush();
            if (Logger != null)
                Logger.Flush();
        }

        public override long Seek(long offset, SeekOrigin origin)
        {
            return _source.Seek(offset, origin);
        }

        public override void SetLength(long value)
        {
            _source.SetLength(value);
        }

        public override int Read(byte[] buffer, int offset, int count)
        {
            count = _source.Read(buffer, offset, count);
            if (Logger != null)
                Logger.Write(buffer, offset, count);
            return count;
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            _source.Write(buffer, offset, count);
            if (Logger != null)
                Logger.Write(buffer, offset, count);
        }
        public override int ReadByte()
        {
            int ret = _source.ReadByte();
            if (ret != -1 && Logger != null)
                Logger.WriteByte((byte)ret);
            return ret;
        }
        public override void Close()
        {
            _source.Close();
            if (Logger != null)
                Logger.Close();
            base.Close();
        }
        public override int ReadTimeout
        {
            get { return _source.ReadTimeout; }
            set { _source.ReadTimeout = value; }
        }
        public override int WriteTimeout
        {
            get { return _source.WriteTimeout; }
            set { _source.WriteTimeout = value; }
        }
    }
}
[AttributeUsage(AttributeTargets.Method)]
public class LoggerSoapExtensionAttribute : SoapExtensionAttribute
{
    private int priority = 1;
    public override int Priority
    {
        get
        {
            return priority;
        }
        set
        {
            priority = value;
        }
    }
    public override System.Type ExtensionType
    {
        get
        {
            return typeof(LoggerSoapExtension);
        }
    }
}
1
ответ дан 24 November 2019 в 06:27
поделиться

Вы не определили, какой язык Вы используете, но предполагаете C#/.NET, которую Вы могли использовать расширения SOAP .

Иначе, используйте сниффера такой в качестве Wireshark

0
ответ дан Anton Gogolev 24 November 2019 в 06:27
поделиться

Похоже, решение Тима Картера не работает, если вызов веб-ссылки вызывает исключение. Я пытался получить необработанный веб-резонанс, чтобы я мог изучить его (в коде) в обработчике ошибок после того, как возникнет исключение. Однако я обнаружил, что журнал ответов, записанный методом Тима, пуст, когда вызов вызывает исключение. Я не совсем понимаю код, но похоже, что метод Тима врезается в процесс после точки, где.Net уже аннулировал и отклонил веб-ответ.

Я работаю с клиентом, который вручную разрабатывает веб-сервис с помощью низкоуровневого кодирования. На этом этапе они добавляют свои собственные сообщения об ошибках внутреннего процесса в виде сообщений в формате HTML в ответ ПЕРЕД ответом в формате SOAP. Конечно, автоматическая веб-ссылка на .Net взрывается по этому поводу. Если бы я мог получить необработанный HTTP-ответ после создания исключения, я мог бы искать и анализировать любой SOAP-ответ в смешанном возвращающемся HTTP-ответе и знать, получили ли они мои данные нормально или нет.

Позже ...

Вот решение, которое работает даже после выполнения (обратите внимание, что я только после ответа - тоже могу получить запрос):

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;
        }
    }
}

Вот как вы настраиваете его в конфигурации file:

<configuration>
     ...
  <system.web>
    <webServices>
      <soapExtensionTypes>
        <add type="ChuckBevitt.GetRawResponseSoapExtension, TestCallWebService"
           priority="1" group="0" />
      </soapExtensionTypes>
    </webServices>
  </system.web>
</configuration>

"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 будет работать, потому что вы изменили тип потока с ConnectStream на MemoryStream в ChainStream, а MemoryStream разрешает операции поиска.(Я пробовал преобразовать ConnectStream в MemoryStream - не разрешено.)

Итак ... Microsoft должна либо разрешить операции поиска для типа ChainStream, либо сделать SoapMessage.Stream действительно доступной только для чтения копией, как и предполагалось быть. (Напишите своему конгрессмену и т. Д.)

Еще одно замечание. После создания способа получить необработанный HTTP-ответ после исключения я все еще не получил полного ответа (как определено анализатором HTTP). Это произошло потому, что, когда веб-служба разработки добавляла сообщения об ошибках HTML в начало ответа, она не настраивала заголовок Content-Length, поэтому значение Content-Length было меньше размера фактического тела ответа. Все, что я получил, это количество символов в значении Content-Length - остальные отсутствовали. Очевидно, что когда .Net читает поток ответа, он просто считывает количество символов Content-Length и не допускает, чтобы значение Content-Length могло быть неправильным. Это так и должно быть; но если значение заголовка Content-Length неверно, единственный способ получить весь текст ответа - это использовать сниффер HTTP (я использую HTTP Analyzer из http://www.ieinspector.com ) .

6
ответ дан 24 November 2019 в 06:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: