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:      Soap2ArgosExtension.cs
// Author:      sgregory
// Date:        08 April 2003
// Description:   
// --------------------------------------------------------------------------------
// $Archive: <VSS Path To File>/Soap2ArgosExtension.cs $
// $Revision: 1 $ changed on $Date: 08 April 2003 15:51 $
// Last changed by $Author: sgregory $
// --------------------------------------------------------------------------------
using System;
using System.IO;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Xsl;
using System.Text;
using System.Reflection;
using System.Web.Services;
using System.Web.Services.Protocols;


namespace ArgosAPIExtensions
{
	/// <summary>ArgosAPIExtensions.TransformDirection</summary>
    /// <remarks></remarks>
    /// <values>
    /// 		Argos2Soap : Transforms Argos flat file to SOAP
    /// 		Soap2Argos : Transforms SOAP to Argos flat file
    /// </values>
    enum TransformDirection
	{
		Argos2Soap,
		Soap2Argos
	};

	/// <author>SGregory</author>
	/// <date>18 February 2002</date>
	/// <summary>Derived SoapExtension class</summary>
	/// <remarks>
	/// This class is derived from the framework class, SoapExtension
	///	which allows us to tap into the raw SOAP message XML by chaining
	///	ourselves into the Soap XML persistence / depersistence process.
	///	We are then able to manipulate the text within the XML representing
	///	the API. This allows us to transform Soap to a fixed column format.
	/// </remarks>
    public class Soap2ArgosExtension : SoapExtension
	{ 
		// Constants

		// Private member variables
		Stream oldStream = null;				// Original Stream
		Stream newStream = null;				// Our replacement Stream

		public override object GetInitializer(
			LogicalMethodInfo methodInfo, 
			SoapExtensionAttribute attribute) 
		{
			return attribute;
		}


		public override object GetInitializer(
			Type t) 
		{
			return typeof(Soap2ArgosExtension);
		}


		public override void Initialize(
			object initializer) 
		{
			// Lets cast the object as an attribute
			Soap2ArgosExtensionAttribute attribute = (Soap2ArgosExtensionAttribute)initializer;
		}


		public override void ProcessMessage(
			SoapMessage message) 
		{
			// Here, we are interested in capturing the stream after the
			// SOAP call has been serialised into XML ("client-side").
			// We care not about other points in the process.
			//
			// Hence, for capture we hook:
			//
			//		SoapMessageStage.AfterSerialize (only ever run at the Client)
			//
			switch (message.Stage) 
			{
				case SoapMessageStage.BeforeSerialize:
					break;

				case SoapMessageStage.AfterSerialize:
					// Transform Soap to Argos API
					TransformSoap2Argos(message);
					break;

				case SoapMessageStage.BeforeDeserialize:
					// Transform Soap to Argos API
					TransformArgos2Soap(message);
					break;

				case SoapMessageStage.AfterDeserialize:
					break;

				default:
					throw new ArgumentException("Invalid SoapMsgCaptureExtension Soap Message stage [" + message.Stage + "]", "message");
			}
		}


		public override Stream ChainStream(
			Stream stream) 
		{
			// Store old
			oldStream = stream;

			// Create new stream
			newStream = new MemoryStream();

			// Return new stream
			return newStream;
		}
	 

		private void TransformSoap2Argos(
			SoapMessage message) 
		{
			// Rewind the source stream
			newStream.Position = 0;

			// Instead of using traditional XSL transforms, let's use
			// an XmlReader...
			TransformUsingReader(TransformDirection.Soap2Argos);
			// Pass it off as the actual stream
			Copy(newStream, oldStream);
			//TransformUsingXSLT(TransformDirection.Soap2Argos);
		}

	
		private void TransformArgos2Soap(
			SoapMessage message) 
		{
			// Rewind the source stream
			oldStream.Position = 0;

			// Instead of using traditional XSL transforms, let's use
			// an XmlReader...
			TransformUsingReader(TransformDirection.Argos2Soap);
			//TransformUsingXSLT(TransformDirection.Soap2Argos);
		}


		void Copy(
			Stream from, 
			Stream to) 
		{
			if (from.CanSeek == true)
				from.Position = 0;
			if (to.CanSeek == true)
				to.Position = 0;
			TextReader reader = new StreamReader(from);
			TextWriter writer = new StreamWriter(to);
			writer.WriteLine(reader.ReadToEnd());
			writer.Flush();
			if (to.CanSeek == true)
				to.Position = 0;
		}


		
		
		// Transformation functions



		/// <summary>ArgosAPIExtensions.Soap2ArgosExtension.TransformUsingReader</summary>
        /// <author>sgregory</author>
        /// <date>16 April 2003</date>
        /// <remarks>Uses XML Text Reader / Writer to process </remarks>
        /// <param name="vtdDir" type="ArgosAPIExtensions.TransformDirection"></param>
        /// <preconditions></preconditions>
        /// <postconditions></postconditions>
        void TransformUsingReader(
			TransformDirection vtdDir)
		{
			// Which way are we going?
			if (vtdDir == TransformDirection.Soap2Argos)
			{
				// Handle the construction of the outbound call to Argos
				// Here we manipulate the Soap to become a flat message format
				bool blnAPICallBuilt = false;
				XmlTextReader objReader = new XmlTextReader(newStream);
				StringBuilder objFlatAPICall = new StringBuilder(1024);

				// Append a nice marker so the other end knows what to expect
				objFlatAPICall.Append("@@");

				while (objReader.Read())
				{
					if (blnAPICallBuilt == false)
					{
						// Pick out the stuff we like, based on the depth.
						// NOTE:
						//
						//	<soap:Envelope> is at depth 0
						//	<soap:Body> is at depth 1
						//	<<METHOD>> is at depth 2
						//	<<PARM>> is at depth 3
						//	<<VALUE>> is at depth 4 (or at least hangs off 3)
						//
						switch (objReader.Depth)
						{
							case 2:		// Method Name
								objFlatAPICall.Append(objReader.Name);
								objFlatAPICall.Append("#");
								break;

								//					case 3:		// Parameter Name
								//						objFlatAPICall.Append(objReader.Name);
								//						objFlatAPICall.Append("#");
								//						break;

							case 4:		// Parameter Value
								objFlatAPICall.Append(objReader.Value);
								blnAPICallBuilt = true;
								break;
							default:
								break;
						}
					}
				}

				// Extract resultant flat thang
				byte[] bytNewFormat = new UTF8Encoding().GetBytes(objFlatAPICall.ToString());
					
				// to return it
				newStream = new MemoryStream();
				newStream.Write(bytNewFormat, 0, bytNewFormat.Length);
			}
			else
			{
				// Handle the response from the call to Argos - here we need to convert
				// flat file back to Soap XML
				byte[] bytArgosFormat = new Byte[oldStream.Length];
				oldStream.Read(bytArgosFormat, 0, bytArgosFormat.Length);
				string strArgosFormat = new UTF8Encoding().GetString(bytArgosFormat);

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

				// Assume the name of the API response starts at character 2, and the value of the response starts after the #
				string strAPICallName = strArgosFormat.Substring(2, strArgosFormat.IndexOf("#") - 2);
				string strAPICallResp = strArgosFormat.Substring(strArgosFormat.IndexOf("#") + 1).Trim(bytTrimChars);

				StringBuilder objFlatAPICallResponse = new StringBuilder();
				objFlatAPICallResponse.Append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
				objFlatAPICallResponse.Append("<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><");
				objFlatAPICallResponse.Append(strAPICallName);
				objFlatAPICallResponse.Append("Response xmlns=\"http://tempuri.org/\"><");
				objFlatAPICallResponse.Append(strAPICallName);
				objFlatAPICallResponse.Append("Result>");
				objFlatAPICallResponse.Append(strAPICallResp);
				objFlatAPICallResponse.Append("</");
				objFlatAPICallResponse.Append(strAPICallName);
				objFlatAPICallResponse.Append("Result></");
				objFlatAPICallResponse.Append(strAPICallName);
				objFlatAPICallResponse.Append("Response></soap:Body></soap:Envelope>");
				string strBuiltResponse = objFlatAPICallResponse.ToString();
				// Extract resultant flat thang
				byte[] bytNewFormat = new UTF8Encoding().GetBytes(strBuiltResponse);
					
				// to return it
				newStream.Write(bytNewFormat, 0, strBuiltResponse.Length);
				newStream.Position = 0;
			}
		}


		/// <summary>ArgosAPIExtensions.Soap2ArgosExtension.TransformUsingXSLT</summary>
        /// <author>sgregory</author>
        /// <date>08 April 2003</date>
        /// <remarks>Uses XSLT to transform the serialised API call between Argos and Soap</remarks>
        /// <param name="vtdDir" type="ArgosAPIExtensions.TransformDirection">Direction of translation</param>
        void TransformUsingXSLT(
			TransformDirection vtdDir)
		{
			XslTransform xslt = null;
			XPathDocument xmlPathEventDoc = null;
			string strCurrentFolder = string.Empty;

			// Determine the XSL stylesheet
			Assembly assCurrent = Assembly.GetExecutingAssembly();
			switch(vtdDir)
			{
				case TransformDirection.Soap2Argos:
					strCurrentFolder = assCurrent.Location.Substring(0, assCurrent.Location.LastIndexOf("\\")+1) + "Soap2Argos.xslt";
					break;
				case TransformDirection.Argos2Soap:
					break;
				default:
					throw new ArgumentException("An invalid Direction was passed when trying to transform the data using XSL.", "vtdDir");
			}

			// Load the stylesheet from off disk into a Processor
			xslt = new XslTransform();
			xslt.Load(strCurrentFolder);

			// Load the streamed XML into an XPathDocument
			xmlPathEventDoc = new XPathDocument(new XmlTextReader(newStream));

			// Transform the document into a String output
			StringWriter stWriter = new StringWriter();

			xslt.Transform(
				xmlPathEventDoc, 
				null, 
				stWriter);

			// And strip out any unwanted gumph
			byte[] bytArgosFormat = new UTF8Encoding().GetBytes(stWriter.GetStringBuilder().ToString().Replace(" encoding=\"utf-16\"", string.Empty).Replace(" xmlns=\"\"", string.Empty));

			// to return it
			newStream = new MemoryStream();
			newStream.Write(bytArgosFormat, 0, bytArgosFormat.Length);
		}
	}
}

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
Web02 | 2.8.141220.1 | Last Updated 31 May 2003
Article Copyright 2003 by Simon Gregory
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid