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