using System;

namespace CSConsole.net.catcert.psis
{	using System.Diagnostics;
	using System.Xml.Serialization;
	using System;
	using System.Web.Services.Protocols;
	using System.ComponentModel;
	using System.Web.Services;

	using System.IO;
	using System.Web;
	
	/// <summary>The attribute [ClientSoapLogger()] 
	/// will appear in the data return method found in the
	/// proxy code.</summary>
	[AttributeUsage(AttributeTargets.Method)]
	public class ClientSoapLoggerAttribute : 
		SoapExtensionAttribute
	{
		private int m_Priority = 0;

		public override Type ExtensionType
		{
			get { return typeof(ClientSoapLogger); }
		}

		public override int Priority
		{
			get { return m_Priority;  }
			set { m_Priority = value; }
		}
	} // End of class ClientSoapLoggerAttribute

	/// <summary>This class handles the data 
	/// during the differing states and 
	/// does so autonomously; ie in the background 
	/// without affecting standard processing..</summary>
	public class ClientSoapLogger : SoapExtension
	{
		public Stream oldStream;
		public Stream newStream;

		public override object GetInitializer(
			Type serviceType)
		{
			return null;
		}
		public override object GetInitializer(
			LogicalMethodInfo methodInfo, 
			SoapExtensionAttribute attribute)
		{
			return null;
		}
		public override void Initialize(object initializer)
		{
			return;
		}

		/// <summary>Here is where we take a 
		/// dip into the stream. Due to the
		/// nature of streams if we dipped 
		/// without copying, we would damage the
		/// stream.</summary>
		public override Stream ChainStream(Stream stream)
		{
			oldStream = stream;
			newStream = new MemoryStream();
			return newStream;
		}

		/// <summary>With this override we can 
		/// access the data during different stages
		/// of processing. Logging occurs during the 
		/// before and after serialization.</summary>
		public override void ProcessMessage(SoapMessage message)
		{
			switch(message.Stage)
			{
				case SoapMessageStage.BeforeDeserialize: 
					LogResponse(message); break;
				case SoapMessageStage.AfterSerialize:    
					LogRequest(message);  break;

					// Do nothing on other states
				case SoapMessageStage.AfterDeserialize:
				case SoapMessageStage.BeforeSerialize:                    
				default:
					break;
			}
		}
		// Class continued in step 4

		/// <summary>Publish out the message received 
		/// either in the HttpContext for ASP pages
		/// or publish via remoting for webservices 
		/// and winform applications.</summary>
		public void LogResponse(SoapMessage message)
		{
			Copy(oldStream,newStream);

			newStream.Position = 0;

			string strSOAPresponse = 
				ExtractFromStream(newStream);

			HttpContext hc = HttpContext.Current;

			if (hc != null)
				hc.Items.Add("SOAPResponse", 
					strSOAPresponse);
			else
				System.Runtime.Remoting.Messaging.CallContext.SetData(
					"SOAPResponse",strSOAPresponse);
	      
			newStream.Position = 0;

		}

		public void LogRequest(SoapMessage message)
		{  
			newStream.Position = 0;
			String SoapRequest = ExtractFromStream(newStream);
			newStream.Position = 0;  
         
			Copy(newStream, oldStream);

			HttpContext hc = HttpContext.Current;

			if (hc != null)
				hc.Items.Add("SOAPRequest", SoapRequest);
			else
				System.Runtime.Remoting.Messaging.CallContext
					.SetData("SOAPRequest", SoapRequest);
			
			Console.WriteLine(SoapRequest);
         
		} 

		/// <summary>Transfer the text from the target 
		/// stream from the current position.</summary>
		private String ExtractFromStream(Stream target)
		{
			if (target != null)
				return (new StreamReader(target)).ReadToEnd();

			return "";
		}

		/// <summary>Facilitate the copying process.</summary>
		private void Copy(Stream from, Stream to)
		{
			TextReader reader = new StreamReader(from);
			TextWriter writer = new StreamWriter(to);
			writer.WriteLine(reader.ReadToEnd());
			writer.Flush();
		}
	} // End ClientSoapLogger class</PRE>

}
