Click here to Skip to main content
15,886,518 members
Articles / Programming Languages / C#

Using Web Services for Remoting over the Internet.

Rate me:
Please Sign up or sign in to vote.
4.76/5 (38 votes)
15 Feb 2002CPOL8 min read 371.5K   4.2K   222  
This article describes a design and implementation (C#) of the Remoting over Internet using the Web Service as a gateway into the Remoting infrastructure.
//======================================================================================================
//	The Web service IMessage/SoapMessage Gateway.
//	(C) Copyright 2002, Roman Kiss (rkiss@pathcom.com)
//	All rights reserved.
//	The code and information is provided "as-is" without waranty of any kind, either expresed or implied.
//------------------------------------------------------------------------------------------------------
//	History:
//			22-01-2002	RK	Initial Release	
//======================================================================================================
//
using System;
using System.Threading;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Web;
using System.Web.Services;
using System.Xml.Serialization;
using System.Text;
using System.IO;
//
using System.Reflection;
using System.Messaging;
//
using System.Runtime.Remoting;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Contexts;
using System.Runtime.Remoting.Proxies;
using System.Runtime.Remoting.Channels;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization.Formatters.Soap;

namespace RKiss.WebServiceListener
{
	[Serializable]
	public class User : ILogicalThreadAffinative 
	{
		private string FirstName;
		private string LastName;
		public string lastname{ get{ return LastName; } set{LastName = value;}
		} 
		public string firstname{ get{ return FirstName; } set{FirstName = value;}
		} 
	}

	public class Service : System.Web.Services.WebService
	{
		public Service()
		{
			//CODEGEN: This call is required by the ASP.NET Web Services Designer
			InitializeComponent();
		}

		#region Component Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{

		}
		#endregion

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
		}
		[WebMethod]
		public string Echo(string msg)
		{	
			return string.Format("{0}, {1}", DateTime.Now, msg);
		}
		[WebMethod]
		public string SyncProcessMessage(string request)
		{
			// Request: decoding and deserializing  
			byte[] reqbyteArray = Convert.FromBase64String(request);
			MemoryStream reqstream = new MemoryStream();
			reqstream.Write(reqbyteArray, 0, reqbyteArray.Length);
			reqstream.Position = 0;
			BinaryFormatter bf = new BinaryFormatter();
			IMessage reqmsg = (IMessage)bf.Deserialize(reqstream);
			reqmsg.Properties["__Uri"] = reqmsg.Properties["__Uri2"];			// work around!!
			reqstream.Close();
			
			// Action: invoke the Remote Methode 
			string[] stype = reqmsg.Properties["__TypeName"].ToString().Split(new Char[]{','}); // split typename
			Assembly asm = Assembly.Load(stype[1].TrimStart(new char[]{' '}));	 // load type of the remote object
			Type objectType = asm.GetType(stype[0]);							 // type
			string objectUrl = reqmsg.Properties["__Uri"].ToString();			 // endpoint
			object ro = RemotingServices.Connect(objectType, objectUrl);		 // create proxy
			TraceIMessage(reqmsg);
			IMessage rspmsg = RemotingServices.ExecuteMessage((MarshalByRefObject)ro, (IMethodCallMessage)reqmsg);
			TraceIMessage(rspmsg);

			// Response: encoding and serializing  
			MemoryStream rspstream = new MemoryStream();
			bf.Serialize(rspstream, rspmsg);
			rspstream.Position = 0;
			string response = Convert.ToBase64String(rspstream.ToArray());
			rspstream.Close();

			return response;
		}
		
		[WebMethod]
		public string SyncProcessSoapMessage(string request)
		{
			IMessage retMsg = null;
			string response;

			try
			{
				Trace.WriteLine(request);
				
                // Request: deserialize string into the SoapMessage
				SoapFormatter sf = new SoapFormatter();
				sf.TopObject = new SoapMessage();
				StreamWriter rspsw = new StreamWriter(new MemoryStream());
				rspsw.Write(request);
				rspsw.Flush();
				rspsw.BaseStream.Position = 0;
				ISoapMessage soapmsg = (ISoapMessage)sf.Deserialize(rspsw.BaseStream);
				rspsw.Close();

				// Action: invoke the Remote Methode 
				object[] values = soapmsg.ParamValues;
				string[] stype = values[2].ToString().Split(new Char[]{','});
				Assembly asm = Assembly.Load(stype[1].TrimStart(new char[]{' '}));
				Type objectType = asm.GetType(stype[0]);
				string objectUrl = values[0].ToString(); 
				RealProxyWrapper rpw = new RealProxyWrapper(objectType, objectUrl, soapmsg.ParamValues[4]);
				object ro = rpw.GetTransparentProxy();
				MethodInfo mi = objectType.GetMethod(values[1].ToString());
				object retval = mi.Invoke(ro, values[3] as object[]);
				retMsg = rpw.ReturnMessage;
			}
			catch(Exception ex) 
			{
				retMsg = new ReturnMessage((ex.InnerException == null) ? ex : ex.InnerException, null);
			}
			finally 
			{
				// Response: serialize IMessage into string
				Stream rspstream = new MemoryStream();
				SoapFormatter sf = new SoapFormatter();
				RemotingSurrogateSelector rss = new RemotingSurrogateSelector();
				rss.SetRootObject(retMsg);
				sf.SurrogateSelector = rss;
				sf.AssemblyFormat = FormatterAssemblyStyle.Full;
				sf.TypeFormat = FormatterTypeStyle.TypesAlways;
				sf.TopObject = new SoapMessage();
				sf.Serialize(rspstream, retMsg);
				rspstream.Position = 0;
				StreamReader sr = new StreamReader(rspstream);
				response = sr.ReadToEnd();
				rspstream.Close();
				sr.Close();
			}
			
			Trace.WriteLine(response);
			return response;
		}

		// helper
		private void TraceIMessage(IMessage msg) 
		{
			try 
			{
				if(msg is IMethodCallMessage)
					Trace.WriteLine("IMethodCallMessage");

				if(msg is IMethodReturnMessage)
					Trace.WriteLine("IMethodReturnMessage");

				Trace.WriteLine(string.Format(" Message Type: {0}", msg.GetType().FullName));

				Trace.WriteLine(" Message Properties:");
				IDictionary d = msg.Properties;
				IDictionaryEnumerator e = (IDictionaryEnumerator) d.GetEnumerator();

				while(e.MoveNext())
				{
					object val = e.Value;
					object key = e.Key;
					string keyName = key.ToString();

					Trace.WriteLine(string.Format("  {0} : {1}", keyName, val));
					if((keyName == "__Args")  ||
					  (keyName == "__OutArgs") || 
					  ((keyName == "__MethodSignature") && (null != val)))

					{
						int ii = 0;
						foreach(object arg in val as object[]) 
						{
							if(arg == null) 
								Trace.WriteLine(string.Format("    arg[{0}] = null", ii++));
							else
								Trace.WriteLine(string.Format("    arg[{0}] = {1}, {2}", ii++, arg, arg.GetType()));
						}
					}
					
					if((keyName == "__CallContext") && (null != val))
					{
						LogicalCallContext logicallContext = (LogicalCallContext)val;

						// retrieve a Call ID into the CallContext
						object cid = logicallContext.GetData("__CallID");
						if(null != cid)
						{
							Trace.WriteLine(string.Format("     __CallID: {0}", cid.ToString()));
						}
					}
				}
			}
			catch(Exception ex) 
			{
				Trace.WriteLine(ex.Message);
			}
		}
	}//Service

	public class RealProxyWrapper : RealProxy
	{
		string				_url;
		string				_objectURI;
		IMessageSink		_messageSink;
		IMessage			_msgRsp;
		LogicalCallContext	_lcc;

		public IMessage ReturnMessage { get { return  _msgRsp; }}
		public RealProxyWrapper(Type type, string url, object lcc)	: base(type)
		{
			_url = url;
			_lcc = lcc as LogicalCallContext;
		
			foreach(IChannel channel in ChannelServices.RegisteredChannels)
			{
				if(channel is IChannelSender)
				{
					IChannelSender channelSender = (IChannelSender)channel;
					_messageSink = channelSender.CreateMessageSink(_url, null, out _objectURI);
					if(_messageSink != null)
						break;
				}
			}

			if(_messageSink == null)
			{
				throw new Exception("A supported channel could not be found for url:"+ _url);
			}
		}
		public override IMessage Invoke(IMessage msg)
		{
			msg.Properties["__Uri"] = _url;					// endpoint
			msg.Properties["__CallContext"] = _lcc;			// caller's callcontext
			_msgRsp = _messageSink.SyncProcessMessage(msg);
		
			return _msgRsp;
		}
	}// RealProxyWrapper

}

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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions