Получите SOAP-сообщение перед отправкой в ​​WebService в.NET

Я звоню на внешний HTTPS веб-сервис.

Чтобы проверить, что не так, владельцу нужен SOAP-запрос, который я отправляю.

У меня есть веб-ссылка и сгенерированный прокси-класс, созданный VS 2008...

Есть ли способ увидеть сообщение SOAP перед его отправкой?

Я думаю, в некотором.net-коде... потому что Sniffers, которые я пробовал, не "видели" вызов веб-службы, не знаю почему.

4 ответа

Решение

Вы можете просто сериализовать объект запроса перед отправкой, например так:

var sreq = new SomeSoapRequest();

// ... fill in here ...

var serxml = new System.Xml.Serialization.XmlSerializer(sreq.GetType());
var ms = new MemoryStream();
serxml.Serialize(ms, sreq);
string xml = Encoding.UTF8.GetString(ms.ToArray());

// in xml string you have SOAP request

Предложение @mting923 было действительно полезным, спасибо!

Другие идеи (например, использование SoapExtension или создание "шпионских" классов а-ля Как мне получить доступ к ответу SOAP) интересны, но не могут быть использованы в.NET Core. Но сгенерированный прокси-класс SOAP по-прежнему остается просто клиентом WCF под капотом, и поэтому подход IClientMessageInspector работает хорошо, даже для функции.NET Core Azure, вызывающей старую веб-службу SOAP.

В приведенном выше примере ответная проводная связь подразумевается, но не показана полностью. Кроме того, в последних версиях API.NET CoreMessageInspectors сейчас ClientMessageInspectors а также Behaviors сейчас EndpointBehaviors. Итак, для полноты, в функции Azure.NET Core 3.1 у меня работает следующее:

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

После вызова веб-службы на прокси-сервере клиента, soapInspector.LastRequestXml а также soapInspector.LastResponseXml будет содержать необработанный запрос и ответ SOAP (в виде строк).

Вы можете использовать IClientMEssageInspector и IEndpointBehavior, чтобы выполнить это. Я обнаружил, что использование этого способа может захватить точный запрос мыла, скорее всего, как запрос скрипача:

Создайте такой класс в том же проекте:

public class ClientMessageInspector : System.ServiceModel.Dispatcher.IClientMessageInspector
    {
        #region IClientMessageInspector Members
        public string LastRequestXml { get; private set; }

        public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
        {

        }

        public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
        {
            string requestHeaderName = request.Headers.Action.Replace("urn:#",string.Empty);
            LastRequestXml = request.ToString();
            string serializedRequestFile = string.Format(requestHeaderName + "_request_{0}.xml", DateTime.Now.ToString("yyyyMMddHHmmss"));
            string exportedFolder = ConfigurationManager.AppSettings["SubmittedRequestXmLocation"];
            printSoapRequest(request, exportedFolder, serializedRequestFile);

            return request;
        }

        public void printSoapRequest(System.ServiceModel.Channels.Message request, string exportedFolder, string fileName)
        {
            if (exportedFolder.Equals(string.Empty))
                return;

            if (!Directory.Exists(exportedFolder))
            {
                Directory.CreateDirectory(exportedFolder);
            }
            string exportedFile = string.Format("{0}\\{1}", exportedFolder, fileName);
            if (File.Exists(exportedFile))
            {
                File.Delete(exportedFile);
            }

            string strRequestXML = request.ToString();
            XDocument xDoc = XDocument.Parse(strRequestXML);
            XmlWriter xw = XmlWriter.Create(exportedFile);
            xDoc.Save(xw);
            xw.Flush();
            xw.Close();
            LogOutput("Request file exported: " + exportedFile);

        }

    }

    public class CustomInspectorBehavior : IEndpointBehavior
    {
        private readonly ClientMessageInspector clientMessageInspector = new ClientMessageInspector();

        public string LastRequestXml
        {
            get { return clientMessageInspector.LastRequestXml; }
        }

        public string LastResponseXml
        {
            get { return clientMessageInspector.LastRequestXml; }
        }

        public void AddBindingParameters(
            ServiceEndpoint endpoint,
            System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {
        }

        public void Validate(ServiceEndpoint endpoint)
        {
        }

        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
            clientRuntime.MessageInspectors.Add(clientMessageInspector);
        }
    }

Тогда вы можете назвать это следующим образом:

ProxyClass _class = new ProxyClass();
var requestInterceptor = new CustomInspectorBehavior();
           _client.Endpoint.Behaviors.Add(requestInterceptor);

Когда вы вызываете сервисный метод, он автоматически выполняет перехватчик и печатает вывод. Используя этот способ, вы также можете манипулировать мыльным сообщением перед отправкой на сервер!

Добавьте это в элемент вашего файла web.config или App.config. Он создаст файл trace.log в папке bin/Debug вашего проекта. Или вы можете указать абсолютный путь к файлу журнала с помощью атрибута initializeData.

  <system.diagnostics>
    <trace autoflush="true"/>
    <sources>
      <source name="System.Net" maxdatasize="9999" tracemode="protocolonly">
        <listeners>
          <add name="TraceFile" type="System.Diagnostics.TextWriterTraceListener" initializeData="trace.log"/>
        </listeners>
      </source>
    </sources>
    <switches>
      <add name="System.Net" value="Verbose"/>
    </switches>
  </system.diagnostics>

Он предупреждает, что атрибуты maxdatasize и tracemode не разрешены, но они увеличивают объем данных, которые могут быть зарегистрированы, и избегают регистрации всего в шестнадцатеричном формате.

Если вы работаете в более ограниченной среде и не можете позволить себе такое приложение, как Fiddler, вы можете сделать следующее:

  1. Создайте свою веб-ссылку как обычно.
  2. Напишите код для выполнения любого вызова веб-метода, который вы собираетесь мне.
  3. Создайте новый ASP .NET проект по вашему выбору, я пошел с MVC 4.
  4. Создайте обработчик или контроллер / действие и извлеките поток запросов следующим образом:

using (var reader = new System.IO.StreamReader(Request.InputStream)) { result = reader.ReadToEnd(); }

  1. Установите точку останова и запустите ее в режиме отладки.
  2. На вашем клиенте установите URL-адрес SOAP-запроса для вашего нового контроллера / обработчика.
  3. Запустите ваш клиент. Вы должны поймать точку останова в своем веб-приложении с помощью сообщения SOAP.

Это не идеальное или симпатичное решение, но если вы работаете в умеренно ограниченных условиях, оно выполнит свою работу.

Другие вопросы по тегам