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

Using Web Services for Remoting over the Internet.

, 15 Feb 2002
This article describes a design and implementation (C#) of the Remoting over Internet using the Web Service as a gateway into the Remoting infrastructure.
remotingoverinternet_src.zip
ConsoleClient
bin
Debug
ConsoleClient.exe
ConsoleClient.pdb
MyRemoteObject.dll
MyRemoteObject.pdb
ConsoleClient.csproj.user
obj
Debug
ConsoleClient.exe
ConsoleClient.exe.incr
ConsoleClient.pdb
temp
TempPE
ConsoleServer
bin
Debug
ConsoleServer.exe
ConsoleServer.pdb
ConsoleServer.csproj.user
obj
Debug
ConsoleServer.exe
ConsoleServer.exe.incr
ConsoleServer.pdb
temp
TempPE
MyRemoteObject
bin
Debug
MyRemoteObject.dll
MyRemoteObject.pdb
MyRemoteObject.csproj.user
MyRemoteObject.snk
obj
Debug
MyRemoteObject.dll
MyRemoteObject.dll.incr
MyRemoteObject.pdb
temp
TempPE
WebServiceChannelLib
bin
Debug
WebServiceChannelLib.dll
WebServiceChannelLib.pdb
obj
Debug
Service.resources
temp
TempPE
WebServiceChannelLib.dll
WebServiceChannelLib.dll.incr
WebServiceChannelLib.pdb
WebServiceChannelLib.csproj.user
WebServiceChannelLib.snk
WebServiceListener
bin
WebServiceListener.dll
WebServiceListener.pdb
Global.asax
WebServiceListener.csproj.webinfo
WebServiceListener.vsdisco
//======================================================================================================
//	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)

Share

About the Author

Roman Kiss
Software Developer (Senior)
United States United States
No Biography provided

| Advertise | Privacy | Mobile
Web02 | 2.8.140922.1 | Last Updated 15 Feb 2002
Article Copyright 2002 by Roman Kiss
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid