将SOAP请求捕获到ASP.NET ASMX Web服务

考虑将传入的SOAP请求logging到ASP.NET ASMX Web服务的要求。 其任务是捕获发送到Web服务的原始XML。

传入的消息需要logging下来进行debugging检查。 应用程序已经有了自己的日志库,所以理想的用法是这样的:

//string or XML, it doesn't matter. string incomingSoapRequest = GetSoapRequest(); Logger.LogMessage(incomingSoapRequest); 
  • 有没有简单的解决scheme来捕获传入的SOAP请求的原始XML?
  • 你会处理哪些事件来访问这个对象和相关的属性?
  • 反正有IIS可以捕获传入的请求并推送到日志?

捕获原始消息的一种方法是使用SoapExtensions 。

SoapExtensions的一个替代方法是实现IHttpModule,并在inputstream中获取inputstream。

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

您也可以通过将代码放在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); } 

我在我的web服务中有一个实用程序方法,当我不期待像未处理的exception那样的事情发生时,我用它来捕获请求。

  /// <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 { } } 

然后在web.config中,我存储了几个AppSetting值,这些值定义了我想用来捕获请求的级别。

  <!-- 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"/> 

然后在我的Application_BeginRequest中,我修改了它。 请注意,Configuration是一个静态类,用于从web.config和其他区域读取属性。

  protected void Application_BeginRequest(object sender, EventArgs e) { if(Configuration.CaptureAllRequests) { Utility.CaptureRequest(); } } 

你知道你实际上不需要创build一个HttpModule吗?

您也可以从asmx WebMethod读取Request.InputStream的内容。

这里是一篇关于这个方法的文章 。

代码如下:

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

有没有简单的方法来做到这一点。 你将不得不实施一个SoapExtension 。 上一个链接中的示例显示了可用于logging数据的扩展。

如果你一直在使用WCF,那么你可以简单地设置configuration来产生消息日志。


根据Steven de Salas的说法,您可以使用webmethod中的Request.InputStream属性。 我还没有尝试过,但他说这是有效的。

我想用http和httpstesting这个,并且同时运行和不运行其他的SoapExtensions。 这些东西可能会影响InputStream所设置的streamtypes。 例如,某些数据stream无法查找,例如,可能会在数据结束后放置一个数据stream,并且无法移动到起点。

我知道我已经4年了,但现在我们还有小提琴手也这样做。