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

Using Web Services for Remoting over the Internet.

, 15 Feb 2002 CPOL
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 library for Custom Remoting via Web Service channel (Sender).
//	(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.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Messaging;
using System.Collections;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization.Formatters.Soap;
using System.Xml;
using System.Xml.Serialization;
using System.Reflection;
using System.Messaging;
using System.Runtime.InteropServices;


namespace RKiss.WebServiceChannelLib
{
	public delegate void delegateAsyncWorker(IMessage msgReq, IMessageSink replySink); 

	// Sender
	public class Sender : IChannelSender
	{	
		// these are a hardcoded default values
		const int PATH_MINNUMOFFIELDS = 4;
		public const string DEFAULT_CHANNELMODE = "Binary";
		public const string DEFAULT_CHANNELNAME = "ws";
		public const int    DEFAULT_CHANNELPRIORITY = 1;
		//
		private string m_ChannelName;
		private int m_ChannelPriority;
		private string m_ChannelMode;

	
		// Sender
		public Sender() : 
			this(DEFAULT_CHANNELNAME, DEFAULT_CHANNELMODE, DEFAULT_CHANNELPRIORITY) {}
		public Sender(string channelName) : 
			this(channelName, DEFAULT_CHANNELMODE, DEFAULT_CHANNELPRIORITY) {}
		public Sender(string channelName, string mode) : 
			this(channelName, mode, DEFAULT_CHANNELPRIORITY) {}
		
		public Sender(string channelName, string mode, int priority)
		{
			Init(channelName, mode, priority);
		}
		public Sender(IDictionary properties, IServerChannelSinkProvider serverSinkProvider) 
		{
			string channelName = DEFAULT_CHANNELNAME;
			int channelPriority = DEFAULT_CHANNELPRIORITY;
			string channelMode = DEFAULT_CHANNELMODE;

			// administratively setup the config values (xxx.exe.config file)
			if(properties.Contains("name")) 
				channelName = properties["name"].ToString();
			if(properties.Contains("priority")) 
				channelPriority = Convert.ToInt32(properties["priority"]);
			if(properties.Contains("mode")) 
				channelMode = properties["mode"].ToString().ToUpper();
		
			Init(channelName, channelMode, channelPriority);
		}
		public void Init(string channelName, string mode, int priority)
		{
			m_ChannelName = channelName;
			m_ChannelPriority = priority;
			m_ChannelMode = mode;
			Trace.WriteLine(string.Format("SenderChannel[{0}] has been initiated.", m_ChannelName));
		}
		// IChannelSender
		public string ChannelName	{ get { return m_ChannelName; } 
		}
		public int ChannelPriority	{ get { return m_ChannelPriority; }	
		}
		public string Parse(string url, out string objectURI) { return objectURI = null; }

		// IChannelSender (activation)
		public virtual IMessageSink CreateMessageSink(String url, Object data, out string objectURI)
		{
			objectURI = null;
			string[] gtwpath = url.Split(new Char[]{';'});					// split gateway/RemoteObject
			string[] s = gtwpath[0].Split(new Char[]{'/'});

			if(s.Length < PATH_MINNUMOFFIELDS || m_ChannelName + ":" != s[0])
				return null;												// this is not correct channel
			
			string outpath = gtwpath[0].Replace(m_ChannelName, "http");		// web service
			objectURI = gtwpath[1].TrimStart(new char[]{' '});				// remote object
			WSMessageSink msgsink = new WSMessageSink(m_ChannelMode, objectURI, outpath);

			Trace.WriteLine(string.Format("SenderChannel[{0}] initiated the WSMessageSink for {1}.", m_ChannelName, objectURI));

			return msgsink;			
		}
	}//Sender



	// MSMQMessageSink
	public class WSMessageSink : IMessageSink, IDictionary
	{
		private string			m_ObjectUri;
		private string			m_outpath;
		private string			m_mode;
		
		// MSMQMessageSink
		public WSMessageSink(string mode, string objuri, string outpath) 
		{
			m_mode = mode;
			m_ObjectUri = objuri;
			m_outpath = outpath;
		}
		// helper
		// handler of the AsyncProcessMessage worker
		private void handlerAsyncWorker(IMessage msgReq, IMessageSink replySink) 
		{
			AsyncResult ar = replySink.NextSink as AsyncResult;
			// call Remote Method and wait for its Return Value 
			IMessage msgRsp = SyncProcessMessage(msgReq);
			// update AsyncResult state (_replyMsg, IsCompleted, waitstate, etc.)
			replySink.SyncProcessMessage(msgRsp);
		}
	
		// IMessageSink (MethodCall)
		public virtual IMessage SyncProcessMessage(IMessage msgReq)
		{	
			IMessage msgRsp = null;
			
			try 
			{
				msgReq.Properties["__Uri"] = m_ObjectUri;
				Service webservice = new Service(m_outpath); 
			
				if(m_mode == "SOAP") 
				{
					// serialize IMessage into the stream (SoapMessage)
					MemoryStream reqstream = new MemoryStream();
					SoapFormatter sf = new SoapFormatter();
					RemotingSurrogateSelector rss = new RemotingSurrogateSelector();
					rss.SetRootObject(msgReq);
					sf.SurrogateSelector = rss;
					sf.AssemblyFormat = FormatterAssemblyStyle.Full;
					sf.TypeFormat = FormatterTypeStyle.TypesAlways;
					sf.TopObject = new SoapMessage();
					sf.Serialize(reqstream, msgReq);
					ISoapMessage sm = sf.TopObject;
					reqstream.Position = 0;
					StreamReader sr = new StreamReader(reqstream);
					string request = sr.ReadToEnd();
					reqstream.Close();
					sr.Close();

					// call web service
					string respond = webservice.SyncProcessSoapMessage(request);

					// return messages
					StreamWriter rspsw = new StreamWriter(new MemoryStream());
					rspsw.Write(respond);
					rspsw.Flush();
					rspsw.BaseStream.Position = 0;
					ISoapMessage rspsoapmsg = (ISoapMessage)sf.Deserialize(rspsw.BaseStream);
					rspsw.Close();

					if(rspsoapmsg.ParamValues[0] is Exception) 
					{
						throw rspsoapmsg.ParamValues[0] as Exception;
					}
					else 
					{
						object returnVal = rspsoapmsg.ParamValues[4];
						object[] OutArgs = rspsoapmsg.ParamValues[5] as object[];
						LogicalCallContext lcc = rspsoapmsg.ParamValues[6] as LogicalCallContext;
						ReturnMessage rm = new ReturnMessage(
								returnVal,								//Object return
								OutArgs,								//Object[] outArgs
								OutArgs.Length,							//int outArgsCount
								lcc,									//LogicalCallContext callCtx
								msgReq as IMethodCallMessage			//IMethodCallMessage mcm
								);
						msgRsp = rm as IMessage;
					}
				}
				else 
				{
					msgReq.Properties["__Uri2"] = m_ObjectUri;			// workaround! 
					// serialize and encode IMessage
					BinaryFormatter bf = new BinaryFormatter();
					MemoryStream reqstream = new MemoryStream();
					bf.Serialize(reqstream, msgReq);
					reqstream.Position = 0;
					string request = Convert.ToBase64String(reqstream.ToArray());
					reqstream.Close();
				
					// call Web Service
					string respond = webservice.SyncProcessMessage(request);

					// decode and deserialize IMessage
					byte[] rspbyteArray = Convert.FromBase64String(respond);
					MemoryStream rspstream = new MemoryStream();
					rspstream.Write(rspbyteArray, 0, rspbyteArray.Length);
					rspstream.Position = 0;
					msgRsp = (IMessage)bf.Deserialize(rspstream);
					rspstream.Close();
				}
			}
			catch(Exception ex) 
			{
				Trace.WriteLine(string.Format("Client:SyncProcessMessage error = {0}", ex.Message));
				msgRsp = new ReturnMessage(ex, (IMethodCallMessage)msgReq);
			}
			
			return msgRsp;
		}

		public virtual IMessageCtrl AsyncProcessMessage(IMessage msgReq, IMessageSink replySink)
		{
			IMessageCtrl imc = null;

			if(replySink == null)										// OneWayAttribute
			{	
				Trace.WriteLine("Client-[OneWay]Async:CALL");
				SyncProcessMessage(msgReq);
			}
			else
			{
				Trace.WriteLine("Client-Async:CALL");
				// spawn thread (delegate work)
				delegateAsyncWorker daw = new delegateAsyncWorker(handlerAsyncWorker);
				daw.BeginInvoke(msgReq, replySink, null, null);
			}
			
			return imc;
		}
		        
		// IDictionary (not implemented)
		public virtual IMessageSink NextSink {	get { return null; }}
		public virtual bool Contains(Object key) { return false; }
		public virtual void Add(Object key, Object value){}
		public virtual void Remove(Object key){}
		public virtual void Clear()	{}
		public virtual IDictionaryEnumerator GetEnumerator() { return null;	}
		IEnumerator IEnumerable.GetEnumerator()	{ return null; }
		public int Count { get { return 0; }}
		public void CopyTo(Array array, int index){}
		public ICollection Keys { get { return null; }}
		public ICollection Values { get { return null; }}
		public Object SyncRoot { get { return null; }}
		public  bool IsReadOnly { get { return true; }}
		public  bool IsFixedSize { get { return true; }}
		public bool IsSynchronized { get { return true;	}}
		public Object this[Object key] { get { return null; } set {}}
	}// WSMessageSink
}//namespace RKiss.WebServiceChannelLib



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 | Terms of Use | Mobile
Web03 | 2.8.141223.1 | Last Updated 15 Feb 2002
Article Copyright 2002 by Roman Kiss
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid