web-dev-qa-db-fra.com

Capture SOAP requêtes vers un service Web ASP.NET ASMX

Tenez compte de la nécessité de consigner les demandes SOAP SOAP entrantes vers un service Web ASP.NET ASMX. La tâche consiste à capturer le XML brut envoyé au service Web.

Le message entrant doit être enregistré pour l'inspection de débogage. L'application possède déjà sa propre bibliothèque de journalisation, donc l'utilisation idéale serait quelque chose comme ceci:

//string or XML, it doesn't matter.
string incomingSoapRequest = GetSoapRequest();

Logger.LogMessage(incomingSoapRequest);
  • Existe-t-il des solutions faciles pour capturer le XML brut des requêtes SOAP SOAP entrantes?
  • Quels événements géreriez-vous pour accéder à cet objet et aux propriétés pertinentes?
  • Y a-t-il quand même IIS peut capturer la demande entrante et pousser vers un journal?
30
p.campbell

Une façon de capturer le message brut est d'utiliser SoapExtensions .

Une alternative à SoapExtensions consiste à implémenter IHttpModule et à saisir le flux d'entrée à mesure qu'il arrive.

public class LogModule : IHttpModule
{
    public void Init(HttpApplication context)
    {
        context.BeginRequest += this.OnBegin;
    }

    private void OnBegin(object sender, EventArgs e)
    {
        HttpApplication app = (HttpApplication)sender;
        HttpContext context = app.Context;

        byte[] buffer = new byte[context.Request.InputStream.Length];
        context.Request.InputStream.Read(buffer, 0, buffer.Length);
        context.Request.InputStream.Position = 0;

        string soapMessage = Encoding.ASCII.GetString(buffer);

        // Do something with soapMessage
    }

    public void Dispose()
    {
        throw new NotImplementedException();
    }
}
19
nivlam

Vous pouvez également implémenter en plaçant le code dans Global.asax.cs

protected void Application_BeginRequest(object sender, EventArgs e)
{
    // Create byte array to hold request bytes
    byte[] inputStream = new byte[HttpContext.Current.Request.ContentLength];

    // Read entire request inputstream
    HttpContext.Current.Request.InputStream.Read(inputStream, 0, inputStream.Length);

    //Set stream back to beginning
    HttpContext.Current.Request.InputStream.Position = 0;

    //Get  XML request
    string requestString = ASCIIEncoding.ASCII.GetString(inputStream);

}

J'ai une méthode utilitaire dans mon service Web que j'utilise pour capturer la demande quand quelque chose arrive que je n'attends pas comme une exception non gérée.

    /// <summary>
    /// Captures raw XML request and writes to FailedSubmission folder.
    /// </summary>
    internal static void CaptureRequest()
    {
        const string procName = "CaptureRequest";

        try
        {
            log.WarnFormat("{0} - Writing XML request to FailedSubmission folder", procName);

            byte[] inputStream = new byte[HttpContext.Current.Request.ContentLength];

            //Get current stream position so we can set it back to that after logging
            Int64 currentStreamPosition = HttpContext.Current.Request.InputStream.Position;

            HttpContext.Current.Request.InputStream.Position = 0;

            HttpContext.Current.Request.InputStream.Read(inputStream, 0, HttpContext.Current.Request.ContentLength);

            //Set back stream position to original position
            HttpContext.Current.Request.InputStream.Position = currentStreamPosition;

            string xml = ASCIIEncoding.ASCII.GetString(inputStream);

            string fileName = Guid.NewGuid().ToString() + ".xml";

            log.WarnFormat("{0} - Request being written to filename: {1}", procName, fileName);

            File.WriteAllText(Configuration.FailedSubmissionsFolder + fileName, xml);
        }
        catch
        {
        }

    }

Ensuite, dans web.config, je stocke plusieurs valeurs AppSetting qui définissent le niveau que je veux utiliser pour capturer la demande.

    <!-- true/false - If true will write to an XML file the raw request when any Unhandled exception occurrs -->
    <add key="CaptureRequestOnUnhandledException" value="true"/>

    <!-- true/false - If true will write to an XML file the raw request when any type of error is returned to the client-->
    <add key="CaptureRequestOnAllFailures" value="false"/>

    <!-- true/false - If true will write to an XML file the raw request for every request to the web service -->
    <add key="CaptureAllRequests" value="false"/>

Ensuite, dans mon Application_BeginRequest, je l'ai modifié comme ça. Notez que la configuration est une classe statique que je crée pour lire les propriétés de web.config et d'autres domaines.

    protected void Application_BeginRequest(object sender, EventArgs e)
    {

        if(Configuration.CaptureAllRequests)
        {
            Utility.CaptureRequest();
        }
    }
18
Jim Scott

Vous savez que vous n'avez pas réellement besoin de créer un HttpModule non?

Vous pouvez également lire le contenu du Request.InputStream depuis votre asmx WebMethod.

Voici n article que j'ai écrit sur cette approche .

Le code est le suivant:

using System;
using System.Collections.Generic;
using System.Web;
using System.Xml;
using System.IO;
using System.Text;
using System.Web.Services;
using System.Web.Services.Protocols;

namespace SoapRequestEcho
{
  [WebService(
  Namespace = "http://soap.request.echo.com/",
  Name = "SoapRequestEcho")]
  public class EchoWebService : WebService
  {

    [WebMethod(Description = "Echo Soap Request")]
    public XmlDocument EchoSoapRequest(int input)
    {
      // Initialize soap request XML
      XmlDocument xmlSoapRequest = new XmlDocument();

      // Get raw request body
      Stream receiveStream = HttpContext.Current.Request.InputStream;

      // Move to beginning of input stream and read
      receiveStream.Position = 0;
      using (StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8))
      {
        // Load into XML document
        xmlSoapRequest.Load(readStream);
      }

      // Return
      return xmlSoapRequest;
    }
  }
}
12
Steven de Salas