Click here to Skip to main content
Click here to Skip to main content
 
Add your own
alternative version

Secure Web Services via TCP/IP

, 30 May 2003
Describes an approach for delivery of Soap Messages serialised using ASP.NET Web Client Services over TCP/IP
wsaltroute2.zip
ArgosAPIExtensions
Bin
Client
ArgosAPIExtensions.dll
WSAltRouteTest.exe
WSIPTransports.dll
Server
WebServices
WSAltRouteArgos
bin
ArgosAPIExtensions.dll
ArgosAPIExtensions.pdb
WSAltRouteArgos.dll
WSAltRouteArgos.pdb
Global.asax
WSAltRouteArgos.csproj.webinfo
WSAltRouteArgos.vsdisco
WSAltRouteBEFake.exe
WSAltRouteTest
App.ico
Web References
ArgosTrinketService
Reference.map
Service1.disco
Service1.wsdl
WSAltRouteBEFake
App.ico
WSAltTransports2
WSQTransports.dll
AsyncHelper.dll
// --------------------------------------------------------------------------------
// Module:      ConsoleDriver.cs
// Author:      SGregory
// Date:        02 January 2003
// Description: Contains dummy back end responses to requests
// --------------------------------------------------------------------------------
// $Archive: <VSS Path To File>/ConsoleDriver.cs $
// $Revision: 1 $ changed on $Date: 02 January 2003 20:01 $
// Last changed by $Author: Administrator $
// --------------------------------------------------------------------------------
using System;
using System.Messaging;
using System.IO;
using System.Text;
using System.Xml;
using System.Threading;							// For IP listening
using System.Net.Sockets;
using System.Configuration;						// For Configuration file access
using System.Collections.Specialized;			// For specialised collections
using Microsoft.Web.Services;
using Microsoft.Web.Services.Dime;				// For WS-Attachment support
using Microsoft.Web.Services.Security;			// For WS-Security support
using Microsoft.Web.Services.Timestamp;


// --------------------------------------------------------------------------------
// Namespace:   WSAltRouteBEFake
// Author:      SGregory
// Date:        02 January 2003
// Description: Encapsulates dummy back-end code  
// --------------------------------------------------------------------------------
namespace WSAltRouteBEFake
{
	using WSCommon;						// Our Common Web Services

	/// <summary>WSAltRouteBEFake.BEService</summary>
    /// <author>Simon G</author>
    /// <date>25 February 2003</date>
    /// <remarks>
    /// This class encapsulates all code requried to run the
    /// dummy queue listener.  It supports the listening on
    /// both MSMQ and MQ queues, and is driven off the corresponding
    /// app.config file included in the project.
    /// </remarks>
    class BEService
	{
		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		static void Main(string[] args)
		{
			// Log startup
			TSLog("WSAltRouteBEFake process started [Monitoring MSMQ and MQ Queues, and IP Sockets].");

			// Read configuration settings
			NameValueCollection colSettings = ConfigurationSettings.AppSettings;
			int intPollDelay = 50;	// Default to 50ms
			bool blnIncludeStackTraceOnException = true;
			string[] arrMSMQQueuesToMonitor = null;
			string[] arrMQQueuesToMonitor = null;
			int intNumMSMQQueues = 0;
			int intNumMQQueues = 0;
			string strLocationOfImages = string.Empty;

			// Pass one - get the number of MSMQ queues and number of MQ queues
			foreach (string strName in colSettings)
			{
				string[] arrVals = colSettings.GetValues(strName);
				if (strName.IndexOf("QueueToMonitor") == 0)
				{
					if (arrVals[0].ToLower().IndexOf("msmq://") == 0)
						intNumMSMQQueues++;
					else
						if (arrVals[0].ToLower().IndexOf("mq://") == 0)
						intNumMQQueues++;
				}
			}

			// Pass two - set up arrays
			if (intNumMSMQQueues > 0)
				arrMSMQQueuesToMonitor = new string[intNumMSMQQueues];
			if (intNumMQQueues > 0)
				arrMQQueuesToMonitor = new string[intNumMQQueues];

			// ...and get list of queues
			if (intNumMSMQQueues > 0 ||
				intNumMQQueues > 0)
			{
				// We'll reuse these variables as counts
				intNumMSMQQueues = 0;
				intNumMQQueues = 0;

				// Loop the settings again
				foreach (string strName in colSettings)
				{
					string[] arrVals = colSettings.GetValues(strName);
					if (strName.ToLower().IndexOf("queuetomonitor") == 0)
					{
						if (arrVals[0].ToLower().IndexOf("msmq://") == 0)
							arrMSMQQueuesToMonitor[intNumMSMQQueues++] = arrVals[0].Replace("msmq://", string.Empty);
						else
							if (arrVals[0].ToLower().IndexOf("mq://") == 0)
							arrMQQueuesToMonitor[intNumMQQueues++] = arrVals[0].Replace("mq://", string.Empty);
					}
					else
						if (strName.ToLower() == "polldelaytime")
					{
						try
						{
							intPollDelay = Convert.ToInt32(arrVals[0]);
						}
						catch(Exception)
						{
							TSLog("  Invalid [PollDelayTime] specified - using default value.");
						}
					}
					else
						if (strName.ToLower() == "notrace")
					{
						if (arrVals[0].ToLower() == "true")
							blnIncludeStackTraceOnException = false;
					}
					else
						if (strName.ToLower().IndexOf("locationofimages") == 0)
					{
						strLocationOfImages = arrVals[0];
						if (strLocationOfImages.EndsWith("\\") == false)
							strLocationOfImages += "\\";
					}
				}

				string strPortToListenOn = ConfigurationSettings.AppSettings["PortToListenOn"];
				int inPortToListenOn = 42000;
				if (strPortToListenOn != null &&
					strPortToListenOn.Length > 0)
					inPortToListenOn = Convert.ToInt32(strPortToListenOn);

				string strLog = "  Monitoring ";
				if (arrMSMQQueuesToMonitor != null)
					strLog += arrMSMQQueuesToMonitor.Length.ToString() + " MSMQ Queues, ";
				if (arrMQQueuesToMonitor != null)
					strLog += arrMQQueuesToMonitor.Length.ToString() + " MQ Queues, ";
				strLog += " - with poll time of " + intPollDelay.ToString() + "ms.";
				TSLog(strLog);
				TSLog("  Monitoring IP Socket on port " + inPortToListenOn.ToString());

				// Spin up a socket listening thread
				m_ipMsgProcessor = new Thread(new ThreadStart(ProcessIPMessages));
				m_ipMsgProcessor.Start();

				// Wait on some queues - some MSMQ, and some MQ...
				for (;;)
				{

					// Do MSMQ queues first
					if (arrMSMQQueuesToMonitor != null)
					{
						foreach (string strName in arrMSMQQueuesToMonitor)
						{
							try
							{
								WaitOnMSMQQ(strName, intPollDelay, blnIncludeStackTraceOnException, strLocationOfImages);
							}
							catch(Exception e)
							{
								TSLog("  Exception while waiting on MSMQ Queue " + strName + " : " + e.Message);
							}
						}
					}

					// Now MQ queues
					if (arrMQQueuesToMonitor != null)
					{
						foreach (string strName in arrMQQueuesToMonitor)
						{
							try
							{
								WaitOnMQQ(strName, intPollDelay, blnIncludeStackTraceOnException, strLocationOfImages);
							}
							catch(Exception e)
							{
								TSLog("  Exception while waiting on MQ Queue " + strName + " : " + e.Message);
							}
						}
					}
				}
			}
			else
			{
				TSLog("WSAltRouteBEFake process terminated [No valid queues defined in app.config configuration file].");
				Console.ReadLine();
			}
		}


		/// <summary>WSAltRouteBEFake.ConsoleDriver.WaitOnMSMQQ</summary>
        /// <author>SGregory</author>
        /// <date>02 January 2003</date>
        /// <remarks>Reads MSMQ queue for the next message - pauses 200ms</remarks>
        /// <param name="vstrQueueName" type="string">Queue to wait on</param>
        /// <param name="vintPollTimerDelay" type="System.Int32">Delay in ms to wait for a message</param>
        /// <param name="vblnIncludeStackTraceOnException" type="System.bool">false means supress trace</param>
        /// <param name="vstrLocationOfImages" type="string">Folder to read / write images from</param>
        /// <preconditions>Queue exists</preconditions>
        /// <postconditions>Message returned or exception</postconditions>
        static void WaitOnMSMQQ(
			string vstrQueueName,
			int vintPollTimerDelay,
			bool vblnIncludeStackTraceOnException,
			string vstrLocationOfImages)
		{
			MessageQueue objQueue = null;

			string strCorrelationId = string.Empty;
			string strReplyToQueue = vstrQueueName + "_resp";
			string strResp = string.Empty;

			try
			{
				// We'll need to wait a little time
				TimeSpan tWaitResp = new TimeSpan(0, 0, 0, 0, vintPollTimerDelay);
				
				// Get hold of the queue
				objQueue = GetMSMQQ(vstrQueueName);		

				// Wait for a message
				Message objRequestMsg = objQueue.Receive(tWaitResp, MessageQueueTransactionType.Single);

				// Close the Queue
				objQueue.Close();

				// Get the message content direct from the BodyStream
				byte[] bufIn = new Byte[objRequestMsg.BodyStream.Length];
				objRequestMsg.BodyStream.Position = 0;
				objRequestMsg.BodyStream.Read(bufIn, 0, (int)objRequestMsg.BodyStream.Length);
				strCorrelationId = objRequestMsg.Id;

				// Process through WSE - this may be a passthru operation
				// if WSE was not used to create the stream
				
				// Hmmm - we need to see if this is DIME based or not
				// To do this we shall simply see if we can read the stream
				// as a DIME stream - creating an Envelope in any case
				SoapEnvelope env = InputStreamToEnvelope(objRequestMsg.BodyStream);

				// Close stream
				objRequestMsg.BodyStream.Close();

				// Create Pipeline - with default filter collection for input and output
				// (i.e. we are not overriding default behaviour in any way)
				Pipeline objWSEPipe = new Pipeline();
				
				// Here comes the pain baby
				objWSEPipe.ProcessInputMessage(env);

				// Extract the resultant Envelope
				bufIn = new UTF8Encoding().GetBytes(env.OuterXml);
			
				// Get the response queue - we shall assume a default
				// but hope the client has passed us a queue to call
				// back on
				if (objRequestMsg.ResponseQueue != null)
					strReplyToQueue = objRequestMsg.ResponseQueue.QueueName;

				// Make adjustments for "Private"
				if (strReplyToQueue.ToUpper().IndexOf("PRIVATE$") >= 0)
					strReplyToQueue = ".\\" + strReplyToQueue;

				// Fake out a response to the message
				strResp = BuildFakeResponseFromBytes(
					"MSMQ", 
					bufIn,
					env.Context,
					strReplyToQueue,
					vstrLocationOfImages);

				// If we have a valid response...use it
				if (strResp.Length > 0)
				{
					// Get the response queue
					objQueue = GetMSMQQ(strReplyToQueue);

					// Send a message back
					MemoryStream stResp = new MemoryStream();
					stResp.Write(new UTF8Encoding().GetBytes(strResp), 0, strResp.Length);
					Message objMsg = new Message();
					objMsg.BodyStream = stResp;
					objMsg.Recoverable = true;
					objMsg.CorrelationId = strCorrelationId;

					// Send the message under a single MSMQ internal transaction
					objQueue.Send(objMsg, MessageQueueTransactionType.Single);
				}
			}
			catch(Exception e)
			{
				// Ignore timeouts as this simply means no queue message was there
				if (e.Message.IndexOf("Timeout for the requested operation has expired") < 0)
				{
					string strMsgForConsole = "Exception [" + e.GetType().ToString() + "] caught in WSAltRouteBEFake[MSMQ]: " + e.Message.Replace(Environment.NewLine, string.Empty);
					if (vblnIncludeStackTraceOnException == true)
						strMsgForConsole += e.StackTrace;
					TSLog(strMsgForConsole);

					// Now construct a Soap fault like a normal HTTP style service would do for free
					// Note that this is to trap Web Services stack errors like WSE issues etc. -
					// MSMQ and MQ errors are ignored
					strResp = BuildFakeResponseFromFault(e);

					// If we have a valid response...use it
					if (strResp.Length > 0)
					{
						// Get the response queue
						objQueue = GetMSMQQ(strReplyToQueue);

						// Send a message back
						MemoryStream stResp = new MemoryStream();
						stResp.Write(new UTF8Encoding().GetBytes(strResp), 0, strResp.Length);
						Message objMsg = new Message();
						objMsg.BodyStream = stResp;
						objMsg.Recoverable = true;
						objMsg.CorrelationId = strCorrelationId;

						// Send the message under a single MSMQ internal transaction
						objQueue.Send(objMsg, MessageQueueTransactionType.Single);
					}
				}
			}
			finally
			{
				// Free resources on Queue
				if (objQueue != null)
					objQueue.Close();
			}
		}

		/// <summary>WSAltRouteBEFake.ConsoleDriver.WaitOnMQQ</summary>
		/// <author>SGregory</author>
		/// <date>02 January 2003</date>
		/// <remarks>Reads MQ queue for the next message - pauses 200ms</remarks>
		/// <param name="vstrQueueName" type="string">Queue to wait on</param>
        /// <param name="vintPollTimerDelay" type="System.Int32">Delay in ms to wait for a message</param>
        /// <param name="vblnIncludeStackTraceOnException" type="System.bool">false means supress trace</param>
        /// <param name="vstrLocationOfImages" type="string">Folder to read / write images from</param>
		/// <preconditions>Queue exists</preconditions>
		/// <postconditions>Message returned or exception</postconditions>
		static void WaitOnMQQ(
			string vstrQueueName,
			int vintPollTimerDelay,
			bool vblnIncludeStackTraceOnException,
			string vstrLocationOfImages)
		{
			MQAX200.MQSession objMQSession = null;
			MQAX200.MQQueueManager objQueueManager = null;
			MQAX200.MQQueue objResponseQueue = null;
			MQAX200.MQQueue objRequestQueue = null;
			MQAX200.MQMessage objResponseMsg = null;
			MQAX200.MQMessage objRequestMsg = null;
			MQAX200.MQPutMessageOptions objPutMsgOpts = null;
			MQAX200.MQGetMessageOptions objGetMsgOpts = null;

			string strCorrelationId = string.Empty;
			string strReplyToQueue = vstrQueueName + "_resp";
			string strResp = string.Empty;

			try
			{
				// Get a Session
				objMQSession = new MQAX200.MQSessionClass();
				// Get a Queue Manager (fdefault one)
				objQueueManager = (MQAX200.MQQueueManager)objMQSession.AccessQueueManager(string.Empty);
				// Open the Queue for read
				objRequestQueue = (MQAX200.MQQueue)objQueueManager.AccessQueue(vstrQueueName, (int)MQAX200.MQ.MQOO_INQUIRE + (int)MQAX200.MQ.MQOO_INPUT_AS_Q_DEF, string.Empty, string.Empty, string.Empty);
				// Ready a message
				objRequestMsg = (MQAX200.MQMessage)objMQSession.AccessMessage();
				objGetMsgOpts = (MQAX200.MQGetMessageOptions)objMQSession.AccessGetMessageOptions();
				objGetMsgOpts.Options = (int)MQAX200.MQ.MQGMO_SYNCPOINT + (int)MQAX200.MQ.MQGMO_WAIT;
				objGetMsgOpts.WaitInterval = vintPollTimerDelay;
				// Wait a short time
				objRequestQueue.Get(objRequestMsg, objGetMsgOpts, System.Reflection.Missing.Value);

				// Get value from the message
				string strIn = objRequestMsg.MessageData.ToString();
				byte[] bytMessage = (byte[])objRequestMsg.Read(objRequestMsg.MessageLength);
				MemoryStream stMessage = new MemoryStream();
				stMessage.Write(bytMessage, 0, bytMessage.Length);
				strCorrelationId = objRequestMsg.MessageId;
				string strReplyToQueueManager = objRequestMsg.ReplyToQueueManagerName;
				strReplyToQueue = objRequestMsg.ReplyToQueueName;

				// Close Queue
				objRequestQueue.Close();

				// TEMP CODE - support file streaming of this request so we can see each input Soap message
				// TEMP CODE - FileStream fs = new FileStream("C:\\F_" + Guid.NewGuid() + ".txt", FileMode.Create);
				// TEMP CODE - stMessage.Position = 0;
				// TEMP CODE - stMessage.WriteTo(fs);
				// TEMP CODE - fs.Close();
				// TEMP CODE - support file streaming of this request so we can see each input Soap message

				// Process through WSE - this may be a passthru operation
				// if WSE was not used to create the stream

				// Hmmm - we need to see if this is DIME based or not
				// To do this we shall simply see if we can read the stream
				// as a DIME stream - creating an Envelope in any case
				SoapEnvelope env = InputStreamToEnvelope(stMessage);

				// Close stream
				stMessage.Close();

				// Create Pipeline - with default filter collection for input and output
				// (i.e. we are not overriding default behaviour in any way)
				Pipeline objWSEPipe = new Pipeline();
				
				// Here comes the pain baby
				objWSEPipe.ProcessInputMessage(env);

				// Extract the resultant Envelope
				strIn = env.OuterXml;

				// Fake out a response
				strResp = BuildFakeSoapResponseFromString(
					"MQ",
					strIn,
					env.Context,
					strReplyToQueue,
					vstrLocationOfImages);

				// If we have a valid response...use it
				if (strResp.Length > 0)
				{
					// Write the message back, using the response queue we were given...
					objResponseQueue = (MQAX200.MQQueue)objQueueManager.AccessQueue(strReplyToQueue, (int)MQAX200.MQ.MQOO_OUTPUT, string.Empty, string.Empty, string.Empty);
					objResponseMsg = (MQAX200.MQMessage)objMQSession.AccessMessage();
					objResponseMsg.CorrelationId = strCorrelationId;
					objPutMsgOpts = (MQAX200.MQPutMessageOptions)objMQSession.AccessPutMessageOptions();
    
					// set up the contents of the output message
					objResponseMsg.WriteString(strResp);
       
					// finally, put the message
					objResponseQueue.Put(objResponseMsg, objPutMsgOpts);
					// Close the response Queue
					objResponseQueue.Close();
				}
			}
			catch(Exception e)
			{
				// Ignore timeouts as this simply means no queue message was there
				if (e.Message.IndexOf("MQRC_NO_MSG_AVAILABLE") < 0)
				{
					string strMsgForConsole = "Exception [" + e.GetType().ToString() + "] caught in WSAltRouteBEFake[MQ]: " + e.Message.Replace(Environment.NewLine, string.Empty);
					if (vblnIncludeStackTraceOnException == true)
						strMsgForConsole += e.StackTrace;
					TSLog(strMsgForConsole);

					// Now construct a Soap fault like a normal HTTP style service would do for free
					// Note that this is to trap Web Services stack errors like WSE issues etc. -
					// MSMQ and MQ errors are ignored
					strResp = BuildFakeResponseFromFault(e);

					// If we have a valid response...use it
					if (strResp.Length > 0)
					{
						// Write the message back, using the response queue we were given...
						objResponseQueue = (MQAX200.MQQueue)objQueueManager.AccessQueue(strReplyToQueue, (int)MQAX200.MQ.MQOO_OUTPUT, string.Empty, string.Empty, string.Empty);
						objResponseMsg = (MQAX200.MQMessage)objMQSession.AccessMessage();
						objResponseMsg.CorrelationId = strCorrelationId;
						objPutMsgOpts = (MQAX200.MQPutMessageOptions)objMQSession.AccessPutMessageOptions();
	    
						// set up the contents of the output message
						objResponseMsg.WriteString(strResp);
	       
						// finally, put the message
						objResponseQueue.Put(objResponseMsg, objPutMsgOpts);
						// Close the response Queue
						objResponseQueue.Close();
					}
				}
			}
			finally
			{
				// Tidy
				objQueueManager.Commit();
				objQueueManager.Disconnect();
				objQueueManager = null;
			}
		}


		/// <summary>WSAltRouteBEFake.ConsoleDriver.GetMSMQQ</summary>
        /// <author>SGregory</author>
        /// <date>02 January 2003</date>
        /// <remarks>Gets an MSMQ Message Queue given a name</remarks>
        /// <param name="vstrQueueName" type="string">Queue Name</param>
        /// <returns type="System.Messaging.MessageQueue">Queue object</returns>
        /// <preconditions>Valid Queue Name</preconditions>
        /// <postconditions>May create a Queue if required</postconditions>
        static private MessageQueue GetMSMQQ(string vstrQueueName)
		{
			MessageQueue msgQ = null;
			
			// Does the Queue exist?
			if (MessageQueue.Exists(vstrQueueName) == false)
			{
				// No
				// Create the Message Queue
				// Make it transactional
				msgQ = MessageQueue.Create(vstrQueueName, true);
			}
			else
			{
				// The Queue exists already.  So just open it
				msgQ = new MessageQueue(vstrQueueName);
			}

			// Either way, return the Queue object to the caller
			return msgQ;
		}


		/// <summary>WSAltRouteBEFake.BEService.ProcessIPMessages</summary>
		/// <author>sgregory</author>
		/// <date>06 April 2003</date>
		/// <remarks>Thread running IP listener awaiting messages</remarks>
		static private void ProcessIPMessages() 
		{
			string strResp = string.Empty;
			NetworkStream networkStream = null;

			char[] arrTrimChars = new char[1];
			arrTrimChars[0] = Convert.ToChar(0);

			// Read config
			string strLocationOfImages = ConfigurationSettings.AppSettings["LocationOfImages"];
			strLocationOfImages += "\\";
			bool blnIncludeStackTraceOnException = true;
			string strNoTrace = ConfigurationSettings.AppSettings["NoTrace"];
			if (strNoTrace.ToLower() == "true")
				blnIncludeStackTraceOnException = false;
			string strPortToListenOn = ConfigurationSettings.AppSettings["PortToListenOn"];
			int inPortToListenOn = 42000;
			if (strPortToListenOn != null &&
				strPortToListenOn.Length > 0)
				inPortToListenOn = Convert.ToInt32(strPortToListenOn);

			// Create a listener
			TcpListener tcpListener = new TcpListener(inPortToListenOn);

			// Start the listening
			tcpListener.Start();

			for (;;)
			{
				// Wait until we have something...
				while (!tcpListener.Pending()) 
				{   
					Thread.Sleep(100);
				}

				try
				{
					// Listen for a socket inbound connect
					TcpClient objTcpClient = tcpListener.AcceptTcpClient();

					// Read a request
					networkStream = objTcpClient.GetStream();

					byte[] bytMessage = new byte[objTcpClient.ReceiveBufferSize];

					// Reads the NetworkStream into a byte buffer. Default is 8192 bytes.
					networkStream.Read(bytMessage, 0, (int) objTcpClient.ReceiveBufferSize);
					string strIn = new UTF8Encoding().GetString(bytMessage).Trim(arrTrimChars);

					// TEMP CODE - support file streaming of this request so we can see each input Soap message
					// TEMP CODE - FileStream fs = new FileStream("C:\\F_" + Guid.NewGuid() + ".txt", FileMode.Create);
					// TEMP CODE - stMessage.Position = 0;
					// TEMP CODE - stMessage.WriteTo(fs);
					// TEMP CODE - fs.Close();
					// TEMP CODE - support file streaming of this request so we can see each input Soap message

					// Do we hav some special processing for bespoke messages - let's pretend the
					// string is prefixed with "@@"
					if (strIn.IndexOf("@@") == 0)
					{
						strResp = BuildFakeArgosResponseFromString(
							"IP", 
							strIn, 
							tcpListener.LocalEndpoint.ToString().Replace("0.0.0.0", "localhost"));
					}
					else
					{
						// Normal Soap processing
						// Process through WSE - this may be a passthru operation
						// if WSE was not used to create the stream

						// Need it in a stream
						MemoryStream stMessage = new MemoryStream();
						stMessage.Write(bytMessage, 0, bytMessage.Length);

						// Hmmm - we need to see if this is DIME based or not
						// To do this we shall simply see if we can read the stream
						// as a DIME stream - creating an Envelope in any case
						SoapEnvelope env = InputStreamToEnvelope(stMessage);

						// Close stream
						stMessage.Close();

						// Create Pipeline - with default filter collection for input and output
						// (i.e. we are not overriding default behaviour in any way)
						Pipeline objWSEPipe = new Pipeline();
						
						// Here comes the pain baby
						objWSEPipe.ProcessInputMessage(env);

						// Extract the resultant Envelope
						strIn = env.OuterXml;

						// Fake out a response
						strResp = BuildFakeSoapResponseFromString(
							"IP",
							strIn,
							env.Context,
							tcpListener.LocalEndpoint.ToString().Replace("0.0.0.0", "localhost"),
							strLocationOfImages);
					}

					// If we have a valid response...use it
					if (strResp.Length > 0)
					{
						// Write the message back, using the response queue we were given...
						byte[] sendBytes = Encoding.ASCII.GetBytes(strResp);
						networkStream.Write(sendBytes, 0, sendBytes.Length);
					}
				}
				catch(Exception e)
				{
					string strMsgForConsole = "Exception [" + e.GetType().ToString() + "] caught in WSAltRouteBEFake[IP]: " + e.Message.Replace(Environment.NewLine, string.Empty);
					if (blnIncludeStackTraceOnException == true)
						strMsgForConsole += e.StackTrace;
					TSLog(strMsgForConsole);

					// Now construct a Soap fault like a normal HTTP style service would do for free
					// Note that this is to trap Web Services stack errors like WSE issues etc. -
					// MSMQ and MQ errors are ignored
					strResp = BuildFakeResponseFromFault(e);

					// If we have a valid response...use it
					if (strResp.Length > 0)
					{
						byte[] sendBytes = Encoding.ASCII.GetBytes(strResp);
						networkStream.Write(sendBytes, 0, sendBytes.Length);
					}
				}
				finally
				{
					networkStream.Flush();
					networkStream.Close();
				}
			}
		}



		// Common message helpers


		/// <summary>WSAltRouteBEFake.ConsoleDriver.BuildFakeResponseFromBytes</summary>
        /// <author>Cheese</author>
        /// <date>12 January 2003</date>
		/// <remarks>If we can find a marker (HelloWorld / createColour etc.) then return a stock response</remarks>
		/// <param name="strScheme" type="string">Indicates MSMQ vs. MQ etc.</param>
		/// <param name="strIn" type="string">Soap 'request' message</param>
        /// <param name="vobjSoapContext" type="Microsoft.Web.Services.SoapContext">Soap Context</param>
        /// <param name="vstrResponseQueue" type="string">Response Queue (for logging)</param>
        /// <param name="vstrLocationOfImages" type="string">Folder to read / write images from</param>
		/// <returns type="string">Dummy Soap return message</returns>
        static private string BuildFakeResponseFromBytes(
			string vstrScheme,
			byte[] vbytIn,
			Microsoft.Web.Services.SoapContext vobjSoapContext,
			string vstrResponseQueue,
			string vstrLocationOfImages)
		{
			string strResp = string.Empty;
			string vstrIn = new UTF8Encoding().GetString(vbytIn);
			string strWSEIsInvolved = string.Empty;

			string strMedium = (vstrScheme == "IP") ? "Socket" : "Queue";

			// Was a response queue identified?
			if (vstrResponseQueue.Length == 0)
				vstrResponseQueue = "unspecified on inbound objResponseMsg";

			// Try and ascertain if the WSE was involved...
			if (vobjSoapContext != null)
			{
				if (vobjSoapContext.Attachments.Count > 0 ||
					vobjSoapContext.Security.Elements.Count > 0 ||
					vobjSoapContext.Security.Tokens.Count > 0) 
					strWSEIsInvolved = " {WSE}";
			}


			// If we can find a marker (HelloWorld, createProduct, createColour etc.) then return a stock response
			if (vstrIn.IndexOf("createProduct>") >= 0)
			{
				TSLog("  Spotted inbound " + vstrScheme + strWSEIsInvolved + " [createProduct] message");
				TSLog("    --> Returning a default message on " + strMedium + " [" + vstrResponseQueue + "]");
				strResp = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><soapenv:Body>" +
					"<ns1:createProductResponse soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:ns1=\"urn:debtest\"/></soapenv:Body></soapenv:Envelope>";
			}
			else
				if (vstrIn.IndexOf("createProductDaily") >= 0)
			{
				TSLog("  Spotted inbound " + vstrScheme + strWSEIsInvolved + " [createProductDaily] message");
				TSLog("    --> Returning a default message on " + strMedium + " [" + vstrResponseQueue + "]");
				strResp = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><soapenv:Body>" +
					"<ns1:createProductDailyResponse soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:ns1=\"urn:debtest\"/></soapenv:Body></soapenv:Envelope>";
			}
			else
				if (vstrIn.IndexOf("getProduct>") >= 0)
			{
				TSLog("  Spotted inbound " + vstrScheme + strWSEIsInvolved + " [getProduct] message");
				TSLog("    --> Returning a default message on " + strMedium + " [" + vstrResponseQueue + "]");
				strResp = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" +
					"<soapenv:Body><ns1:getProductResponse soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:ns1=\"urn:debtest\"><getProductReturn href=\"#id0\"/></ns1:getProductResponse><multiRef id=\"id0\" soapenc:root=\"0\" soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" xsi:type=\"ns2:Product\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:ns2=\"urn:debtest\">" +
					"<active xsi:type=\"xsd:boolean\">true</active><category1 xsi:type=\"xsd:string\">NEW_PROD category1</category1><category2 xsi:type=\"xsd:string\">NEW_PROD category2</category2><category3 xsi:type=\"xsd:string\">NEW_PROD category3</category3><category4 xsi:type=\"xsd:string\">NEW_PROD category4</category4>" +
					"<category5 xsi:type=\"xsd:string\">NEW_PROD category4</category5><description xsi:type=\"xsd:string\">NEW_PROD description</description><productId xsi:type=\"xsd:string\">NEWPROD</productId><purchasePrice xsi:type=\"xsd:decimal\">10.0</purchasePrice><salesPrice xsi:type=\"xsd:decimal\">1000.0</salesPrice>" +
					"</multiRef></soapenv:Body></soapenv:Envelope>";
			}
			else
				if (vstrIn.IndexOf("getProductDaily") >= 0)
			{
				TSLog("  Spotted inbound " + vstrScheme + strWSEIsInvolved + " [getProductDaily] message");
				TSLog("    --> Returning a default message on " + strMedium + " [" + vstrResponseQueue + "]");
				strResp = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><soapenv:Body>" +
					"<ns1:getProductDailyResponse soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:ns1=\"urn:debtest\"><getProductDailyReturn xsi:type=\"soapenc:Array\" soapenc:arrayType=\"ns1:ProductDaily[2]\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\"><item href=\"#id0\"/>" +
					"<item href=\"#id1\"/></getProductDailyReturn></ns1:getProductDailyResponse><multiRef id=\"id1\" soapenc:root=\"0\" soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" xsi:type=\"ns2:ProductDaily\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:ns2=\"urn:debtest\">" +
					"<availability xsi:type=\"xsd:decimal\">0</availability><date xsi:type=\"xsd:dateTime\">2003-02-04T22:36:23.132Z</date><productId xsi:type=\"xsd:string\">NEWPROD#1</productId><sales xsi:type=\"xsd:decimal\">21</sales><stock xsi:type=\"xsd:decimal\">0</stock></multiRef>" +
					"<multiRef id=\"id0\" soapenc:root=\"0\" soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" xsi:type=\"ns3:ProductDaily\" xmlns:ns3=\"urn:debtest\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\"><availability xsi:type=\"xsd:decimal\">2</availability><date xsi:type=\"xsd:dateTime\">2003-02-05T22:36:23.132Z</date>" +
					"<productId xsi:type=\"xsd:string\">NEWPROD#1</productId><sales xsi:type=\"xsd:decimal\">18</sales><stock xsi:type=\"xsd:decimal\">1</stock></multiRef></soapenv:Body></soapenv:Envelope>";
			}
			else
				if (vstrIn.IndexOf("getAllProducts") >= 0)
			{
				TSLog("  Spotted inbound " + vstrScheme + strWSEIsInvolved + " [getAllProducts] message");
				TSLog("    --> Returning a default message on " + strMedium + " [" + vstrResponseQueue + "]");
				strResp = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><soapenv:Body><ns1:getAllProductsResponse soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:ns1=\"urn:debtest\">" +
					"<getAllProductsReturn xsi:type=\"soapenc:Array\" soapenc:arrayType=\"ns1:Product[2]\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\"><item href=\"#id0\"/><item href=\"#id1\"/></getAllProductsReturn></ns1:getAllProductsResponse><multiRef id=\"id1\" soapenc:root=\"0\" soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" xsi:type=\"ns2:Product\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:ns2=\"urn:debtest\">" +
					"<active xsi:type=\"xsd:boolean\">true</active><category1 xsi:type=\"xsd:string\">Category A1</category1><category2 xsi:type=\"xsd:string\">Category B1</category2><category3 xsi:type=\"xsd:string\">Category C1</category3><category4 xsi:type=\"xsd:string\">Category D1</category4><category5 xsi:type=\"xsd:string\">Category E1</category5><description xsi:type=\"xsd:string\">Updated A new product - 1st one (made cheaper by 5)</description>" +
					"<productId xsi:type=\"xsd:string\">NEWPROD#1</productId><purchasePrice xsi:type=\"xsd:decimal\">40</purchasePrice><salesPrice xsi:type=\"xsd:decimal\">55</salesPrice></multiRef><multiRef id=\"id0\" soapenc:root=\"0\" soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" xsi:type=\"ns3:Product\" xmlns:ns3=\"urn:debtest\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\"><active xsi:type=\"xsd:boolean\">true</active>" +
					"<category1 xsi:type=\"xsd:string\">Category A2</category1><category2 xsi:type=\"xsd:string\">Category B2</category2><category3 xsi:type=\"xsd:string\">Category C2</category3><category4 xsi:type=\"xsd:string\">Category D2</category4><category5 xsi:type=\"xsd:string\">Category E2</category5><description xsi:type=\"xsd:string\">Another new product - 2nd one</description><productId xsi:type=\"xsd:string\">NEWPROD#2</productId>" +
					"<purchasePrice xsi:type=\"xsd:decimal\">13</purchasePrice><salesPrice xsi:type=\"xsd:decimal\">28.5</salesPrice></multiRef></soapenv:Body></soapenv:Envelope>";
			}
			else
				if (vstrIn.IndexOf("updateProduct>") >= 0)
			{
				TSLog("  Spotted inbound " + vstrScheme + strWSEIsInvolved + " [updateProduct] message");
				TSLog("    --> Returning a default message on " + strMedium + " [" + vstrResponseQueue + "]");
				strResp = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><soapenv:Body><ns1:updateProductResponse soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:ns1=\"urn:debtest\"/></soapenv:Body></soapenv:Envelope>";
			}
			else
				if (vstrIn.IndexOf("updateProductDaily") >= 0)
			{
				TSLog("  Spotted inbound " + vstrScheme + strWSEIsInvolved + " [updateProductDaily] message");
				TSLog("    --> Returning a default message on " + strMedium + " [" + vstrResponseQueue + "]");
				strResp = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><soapenv:Body><ns1:updateProductDailyResponse soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:ns1=\"urn:debtest\"/></soapenv:Body></soapenv:Envelope>";
			}
			else
				if (vstrIn.IndexOf("SendImageAsDIMEAttachment") >= 0)
			{
				TSLog("  Spotted inbound " + vstrScheme + strWSEIsInvolved + " [SendImageAsDIMEAttachment] message");
				TSLog("    --> Returning a default message on " + strMedium + " [" + vstrResponseQueue + "]");
				strResp = "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><soap:Body><SendImageAsDIMEAttachmentResponse xmlns=\"http://tempuri.org/\" /></soap:Body></soap:Envelope>";

				// Look for the DIME attachment - there should only be one
				DimeAttachmentCollection colAttachments = vobjSoapContext.Attachments;
			
				// Any?
				if (colAttachments.Count > 0)
				{
					// Get Item Attachment
					// Here is our item - pull out the binary data representing it
					BinaryReader stream = new BinaryReader(colAttachments[0].Stream);
					byte[] bytAttachmentItem = new byte[stream.BaseStream.Length];
					stream.Read(bytAttachmentItem, 0, bytAttachmentItem.Length);
					stream.BaseStream.Close();
					stream.Close();

					// Write the file
					FileStream fs = new FileStream(vstrLocationOfImages + "SendDIMEImage" + vstrScheme + strWSEIsInvolved + ".gif", FileMode.Create);
					fs.Write(bytAttachmentItem, 0, bytAttachmentItem.Length);
					fs.Close();
				}
			}
			else
				if (vstrIn.IndexOf("ReturnColours") >= 0)
			{
				TSLog("  Spotted inbound " + vstrScheme + strWSEIsInvolved + " [ReturnColours] message");
				TSLog("    --> Returning a default message on " + strMedium + " [" + vstrResponseQueue + "]");
				strResp = "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><soap:Body><ReturnColoursResponse xmlns=\"http://tempuri.org/\"><ReturnColoursResult><Colour1><code>RED0" + vstrScheme + "</code><description>Red</description><longdescription>Lucious red</longdescription><isActive>true</isActive><isInProduct>true</isInProduct></Colour1><Colour1><code>RED1" + vstrScheme + "</code><description>Red</description><longdescription>Lucious red</longdescription><isActive>true</isActive><isInProduct>true</isInProduct></Colour1><Colour1><code>RED2" + vstrScheme + "</code><description>Red</description><longdescription>Lucious red</longdescription><isActive>true</isActive><isInProduct>true</isInProduct></Colour1><Colour1><code>RED3" + vstrScheme + "</code><description>Red</description><longdescription>Lucious red</longdescription><isActive>true</isActive><isInProduct>true</isInProduct></Colour1><Colour1><code>RED4" + vstrScheme + strWSEIsInvolved + "</code><description>Red</description><longdescription>Lucious red</longdescription><isActive>true</isActive><isInProduct>true</isInProduct></Colour1></ReturnColoursResult></ReturnColoursResponse></soap:Body></soap:Envelope>";
			}
			else
				if (vstrIn.IndexOf("HelloWorldArr") >= 0)
			{
				TSLog("  Spotted inbound " + vstrScheme + strWSEIsInvolved + " [HelloWorldArr] message");
				TSLog("    --> Returning a default message on " + strMedium + " [" + vstrResponseQueue + "]");
				strResp = "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><soap:Body><HelloWorldArrResponse xmlns=\"http://tempuri.org/\"><HelloWorldArrResult><string>Hello</string><string>World</string><string>of</string><string>Simon" + vstrScheme + "[Arr]" + strWSEIsInvolved + "</string></HelloWorldArrResult></HelloWorldArrResponse></soap:Body></soap:Envelope>";
			}
			else
				if (vstrIn.IndexOf("HelloWorld") >= 0)
			{
				TSLog("  Spotted inbound " + vstrScheme + strWSEIsInvolved + " [HelloWorld] message");
				TSLog("    --> Returning a default message on " + strMedium + " [" + vstrResponseQueue + "]");
				strResp = "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><soap:Body><HelloWorldResponse xmlns=\"http://tempuri.org/\"><HelloWorldResult>Hello World of Simon" + vstrScheme + strWSEIsInvolved + "</HelloWorldResult></HelloWorldResponse></soap:Body></soap:Envelope>";
			}
			else
				if (vstrIn.IndexOf("ReturnImage") >= 0)
			{
				TSLog("  Spotted inbound " + vstrScheme + strWSEIsInvolved + " [ReturnImage] message");
				TSLog("    --> Returning a default message on " + strMedium + " [" + vstrResponseQueue + "]");
				strResp = "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><soap:Body><ReturnImageResponse xmlns=\"http://tempuri.org/\"><ReturnImageResult>";

				byte[] bytImage = null;
				FileStream fs = null;

				// Read a file and convert to base64
				fs = new FileStream(vstrLocationOfImages + "Help.gif", FileMode.Open);
				bytImage = new byte[fs.Length];
				fs.Read(bytImage, 0, bytImage.Length);
				fs.Close();
				string strBase64EncString = Convert.ToBase64String(bytImage);
				strResp += strBase64EncString;
				strResp += "</ReturnImageResult></ReturnImageResponse></soap:Body></soap:Envelope>";
			}
			else
				if (vstrIn.IndexOf("SendImage") >= 0)
			{
				TSLog("  Spotted inbound " + vstrScheme + strWSEIsInvolved + " [SendImage] message");
				TSLog("    --> Returning a default message on " + strMedium + " [" + vstrResponseQueue + "]");
				strResp = "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><soap:Body><SendImageResponse xmlns=\"http://tempuri.org/\" /></soap:Body></soap:Envelope>";
				int intImgStart = vstrIn.IndexOf("<bytImage>")+10;
				int intImgEnd = vstrIn.IndexOf("</bytImage>");
				byte[] b = Convert.FromBase64String(vstrIn.Substring(intImgStart, intImgEnd-intImgStart));
				FileStream fs = new FileStream(vstrLocationOfImages + "SendImage" + vstrScheme + strWSEIsInvolved + ".gif", FileMode.Create);
				fs.Write(b, 0, b.Length);
				fs.Close();
			}
			else
				if (vstrIn.IndexOf("createColour") >= 0)
			{
				TSLog("  Spotted inbound " + vstrScheme + strWSEIsInvolved + " [createColour] message");
				TSLog("    --> Returning a default message on " + strMedium + " [" + vstrResponseQueue + "]");
				// Need to change this soon!!
				strResp = "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><soap:Body><HelloWorldResponse xmlns=\"http://tempuri.org/\"><HelloWorldResult>Hello World of Simon" + vstrScheme + strWSEIsInvolved + "</HelloWorldResult></HelloWorldResponse></soap:Body></soap:Envelope>";
			}
			else
				if (vstrIn.IndexOf("DoesTrinketExistInMySize") >= 0)
			{
				string strSize = "UNKNOWN";
				if (vstrIn.IndexOf("<vintSize>") >= 0)
					strSize = vstrIn.Substring(vstrIn.IndexOf("<vintSize>")+10, 1);
				TSLog("  Spotted inbound " + vstrScheme + strWSEIsInvolved + " [DoesTrinketExistInMySize] message");
				TSLog("    --> Returning a default message on " + strMedium + " [" + vstrResponseQueue + "]");
				strResp = "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><soap:Body><DoesTrinketExistInMySizeResponse xmlns=\"http://tempuri.org/\"><DoesTrinketExistInMySizeResult>Leatherhead, " + strSize + " High St." + vstrScheme + "</DoesTrinketExistInMySizeResult></DoesTrinketExistInMySizeResponse></soap:Body></soap:Envelope>";
			}
			else
			{
				int idxStartSoapBody = vstrIn.IndexOf("<soap:Body");
				if (idxStartSoapBody >= 0)
					TSLog("  *** (BuildFakeResponseFromBytes) Spotted inbound " + vstrScheme + " [UNKNOWN near " + vstrIn.Substring(idxStartSoapBody) + "] message");
				else
					TSLog("  *** (BuildFakeResponseFromBytes) Spotted inbound " + vstrScheme + " [UNKNOWN in message " + vstrIn + "] message");
			}

			// Should we apply WSE on this message response before giving it
			// over to transportation? We can only do this if we have a response
			// message to operate on AND the request was WSE'd
			if (strResp.Length > 0 &&
				strWSEIsInvolved.Length > 0)
			{
				// Yes....Process through WSE

				// Create an Envelope
				SoapEnvelope env = new SoapEnvelope();
				// Get the basic Soap information into it
				env.LoadXml(strResp);

				// Augment request context with WSE goodies
				// This includes:
				//
				//	* Time-to-live of 60s
				//	* User name and password credentials
				//	* Encryption and Signing
				// Add the instance of EncryptedData to the SOAP response.
				WSCommon.SetupSOAPRequestContext(env.Context);

				// Create Pipeline - with default filter collection for input and output
				// (i.e. we are not overriding default behaviour in any way)
				Pipeline objWSEPipe = new Pipeline();
				
				// Here comes the pain baby
				objWSEPipe.ProcessOutputMessage(env);

				// Extract the resultant Envelope
				strResp = env.OuterXml;
			}

			// Give back the response
			return strResp;
		}


		/// <summary>WSAltRouteBEFake.ConsoleDriver.BuildFakeSoapResponseFromString</summary>
		/// <author>SGregory</author>
		/// <date>02 January 2003</date>
		/// <remarks>If we can find a marker (HelloWorld / createColour etc.) then return a stock response</remarks>
		/// <param name="strScheme" type="string">Indicates MSMQ vs. MQ etc.</param>
		/// <param name="strIn" type="string">Soap 'request' message</param>
		/// <param name="vstrResponseQueue" type="string">Response Queue (for logging)</param>
		/// <returns type="string">Dummy Soap return message</returns>
		static private string BuildFakeArgosResponseFromString(
			string vstrScheme,
			string vstrIn,
			string vstrResponseQueue)
		{
			string strResp = string.Empty;
			string strMedium = (vstrScheme == "IP") ? "Socket" : "Unexpected!";

			// Was a response queue identified?
			if (vstrResponseQueue.Length == 0)
				vstrResponseQueue = "unspecified on inbound objResponseMsg";

			// If we can find a marker (HelloWorld, createProduct, createColour etc.) then return a stock response
			if (vstrIn.IndexOf("DoesTrinketExistInMySize2") >= 0)
			{
				string strSize = "UNKNOWN";
				if (vstrIn.IndexOf("#") >= 0)
					strSize = vstrIn.Substring(vstrIn.IndexOf("#")+1, 1);
				TSLog("  Spotted inbound " + vstrScheme + " [DoesTrinketExistInMySize2] message");
				TSLog("    --> Returning a default message on " + strMedium + " [" + vstrResponseQueue + "]");
				strResp = "@@DoesTrinketExistInMySize2#Leatherhead, " + strSize + " High St." + vstrScheme + "-FlatMsg";
			}
			else
			{
				TSLog("  *** (BuildFakeResponseFromBytes) Spotted inbound " + vstrScheme + " [UNKNOWN in message " + vstrIn + "] message");
			}

			// Give back the response
			return strResp;
		}


		/// <summary>WSAltRouteBEFake.ConsoleDriver.BuildFakeSoapResponseFromString</summary>
        /// <author>SGregory</author>
        /// <date>02 January 2003</date>
        /// <remarks>If we can find a marker (HelloWorld / createColour etc.) then return a stock response</remarks>
        /// <param name="strScheme" type="string">Indicates MSMQ vs. MQ etc.</param>
        /// <param name="strIn" type="string">Soap 'request' message</param>
        /// <param name="vobjSoapContext" type="Microsoft.Web.Services.SoapContext">Soap Context</param>
        /// <param name="vstrResponseQueue" type="string">Response Queue (for logging)</param>
        /// <param name="vstrLocationOfImages" type="string">Folder to read / write images from</param>
        /// <returns type="string">Dummy Soap return message</returns>
        static private string BuildFakeSoapResponseFromString(
			string vstrScheme,
			string vstrIn,
			Microsoft.Web.Services.SoapContext vobjSoapContext,
			string vstrResponseQueue,
			string vstrLocationOfImages)
		{
			byte[] bytIn = new UTF8Encoding().GetBytes(vstrIn);
			return BuildFakeResponseFromBytes(
				vstrScheme,
				bytIn,
				vobjSoapContext,
				vstrResponseQueue,
				vstrLocationOfImages);
		}


		/// <summary>WSAltRouteBEFake.BEService.BuildFakeResponseFromFault</summary>
        /// <author>sgregory</author>
        /// <date>05 April 2003</date>
        /// <remarks></remarks>
        /// <param name="e" type="System.Exception">Exception that was caught in mainline code</param>
        /// <returns type="string">Soap fault representing the string, if its something like a security exception - else blank for MSMQ and MQ errors</returns>
        static private string BuildFakeResponseFromFault(Exception e)
		{
			string strRespSoapFault = string.Empty;
			Exception eActual = null;
			if (e.InnerException != null)
				eActual = e.InnerException;
			else
				eActual = e;

			// Is this error a protocol specific one? Or a WSE style one?
			if (eActual.Message.IndexOf("MQRC") < 0 &&
				eActual.GetType().ToString() != "System.Messaging.MessageQueueException")
			{
				// We'll boldly assume a SoapHeader fault here for now - as all our
				// dodgy errors are down to WSE normally
				StringBuilder objSB = new StringBuilder(8192);
				objSB.Append("<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Body><soap:Fault><faultcode>soap:Server</faultcode><faultstring>System.Web.Services.Protocols.SoapHeaderException: Server unavailable, please try later ---&gt; ");
				objSB.Append(eActual.GetType().ToString());
				objSB.Append(": ");
				objSB.Append(eActual.Message);
				objSB.Append(Environment.NewLine);
				objSB.Append(eActual.StackTrace);
				objSB.Append(Environment.NewLine);
				objSB.Append("  --- End of inner exception stack trace ---");
				objSB.Append("</faultstring><faultactor>WSAltRouteBEFake.exe</faultactor></soap:Fault></soap:Body></soap:Envelope>");
				strRespSoapFault = objSB.ToString();
			}

			return strRespSoapFault;
		}


		// Helper functions


		/// <summary>WSAltRouteBEFake.BEService.InputStreamToEnvelope</summary>
        /// <author>Simon G</author>
        /// <date>25 February 2003</date>
        /// <remarks>
        /// Given a stream, attempt to read the Soap envelope from it.
        /// Note that the stream may contain either a traditional Soap payload
        /// or one or more DIME records containing both a Soap envelope and
        /// multiple DIME attachments.
        /// The job of the method is to set up a SoapEnvelope and optionally
        /// information in the associated Context referring to DIME attachments.
        /// </remarks>
        /// <param name="vstInputMessage" type="System.IO.Stream">Input stream from Queue</param>
        /// <returns type="Microsoft.Web.Services.SoapEnvelope">Envelope and associated context</returns>
        /// <preconditions>Stream is valid</preconditions>
        /// <postconditions>Envelope is set up optionally along with DIME attachments</postconditions>
        static private SoapEnvelope InputStreamToEnvelope(
			Stream vstInputMessage)
		{
			SoapEnvelope env = new SoapEnvelope();

			// Rewind stream - if we can
			if (vstInputMessage != null &&
				vstInputMessage.CanSeek)
				vstInputMessage.Position = 0;

			try
			{
				// Create reader for DIME message
				DimeReader dr = new DimeReader(vstInputMessage);

				// Try to read record containing SOAP message.
				// If this fails with a DIME version error, the
				// stream was most probably not a DIME one
				DimeRecord rec = dr.ReadRecord();

				// Read Soap message from DIME record
				env.Load(rec.BodyStream);

				// Now add any Attachments we find in the stream
				while (rec != null)
				{
					// Read the next record
					rec = dr.ReadRecord();

					// Did we?
					if (rec != null)
					{
						// Here is our item - pull out the binary data representing it
						BinaryReader stream = new BinaryReader(rec.BodyStream);
						byte[] bytAttachmentItem = new byte[rec.ContentLength];
						stream.Read(bytAttachmentItem, 0, bytAttachmentItem.Length);
						stream.Close();

						// And store in a new stream
						MemoryStream stNew = new MemoryStream();
						stNew.Write(bytAttachmentItem, 0, bytAttachmentItem.Length);
						stNew.Position = 0;

						// ... which we will attach to the Soap Context
						DimeAttachment objBin = new DimeAttachment(rec.Id, rec.Type, rec.TypeFormat, stNew);
						env.Context.Attachments.Add(objBin);
					}
				}
			}
			catch(Exception)
			{
				// if we get an exception here, assume this stream was not DIMEd
				// So, rewind again first
				if (vstInputMessage != null &&
					vstInputMessage.CanSeek)
					vstInputMessage.Position = 0;

				// Now just load the whole stream into an array of bytes
				byte[] bufIn = new Byte[vstInputMessage.Length];
				vstInputMessage.Read(bufIn, 0, (int)vstInputMessage.Length);

				// ...and from there into the Soap envelope
				env.LoadXml(new UTF8Encoding().GetString(bufIn));
			}

			return env;
		}




		/// <summary>WSAltRouteBEFake.ConsoleDriver.TSLog</summary>
        /// <author>SGregory</author>
        /// <date>02 January 2003</date>
        /// <remarks>Logs to Console with a timestamp</remarks>
        /// <param name="vstrMsg" type="string">Message to log</param>
        static private void TSLog(
			string strMsg)
		{
			m_intMsgProcessed++;
			Console.WriteLine(m_intMsgProcessed.ToString("0000: ") + DateTime.Now.ToString("dd MMM yyyy, HH:mm:ss") + ":  " + strMsg);
		}




		// Private data members
		private static int m_intMsgProcessed = 0;

		private static Thread m_ipMsgProcessor;
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Simon Gregory
Web Developer
United Kingdom United Kingdom
I am the Technical Director for Myphones.com, which specialises in developing integrated VoIP products and services for the consumer and SME markets. Technology-wise, we are heavily into the 2nd generation WS stack atop .NET, and basically most things Microsoft, as well as C++ on Linux.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.150224.1 | Last Updated 31 May 2003
Article Copyright 2003 by Simon Gregory
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid