Click here to Skip to main content
15,885,278 members
Articles / Programming Languages / C#

.NET Remoting – Basic Maneuvers

,
Rate me:
Please Sign up or sign in to vote.
4.46/5 (51 votes)
6 Oct 200313 min read 191.2K   9.9K   126  
A tutorial on .NET Remoting
using System;

using System.Runtime.Remoting;				//General remoting support.

using System.Runtime.Remoting.Messaging;	//For [OneWay] attribute.
using System.Runtime.Remoting.Activation;	//For UrlAttribute

using System.Runtime.Remoting.Channels;		//Programmatic channel registration.
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Channels.Http;

using System.Threading;

using nsCRemoteObj;			 
using nsCRemoteObjInterface; //Referencing the interface assembly only.

namespace nsCRemoteObjClient
{ //nsCRemoteObjClient

	
	
	class CRemoteObjClient
	{ //CRemoteObjClient

		//(a) Delegate to CRemoteObj.SetupUser():
		//(b) Signateure: public string SetupUser(string sname, string spasswd, out string sTime)
		//(c) Refer to <BLOCK 1-C>
		public delegate string SetupUserDelegate(string string1, string string2, out string string3);

	
		[STAThread]
		static void Main(string[] args)
		{ //Main()

			//Miscellaneous: 
			Console.WriteLine("CRemoteObjClient started. Time:{0}", System.DateTime.Now.ToString() );
			Console.WriteLine();
			
			//There're two ways to publish a remote object:
			//			* Scenario 1: server-activated remote object
			//			* Scenario 2: client-activated remote object
			

			//*****************************************************//
			//Scenario 1: If the remote object is published as "server-activated" object (wellknown object), use Activator.GetObject()
			//			  If so, client only need to reference interface assembly CRemoteObjInterface - there's no need to reference the remote object assembly (CRemoteObj).
			
			//<BLOCK 1>
			try
			{ //try-A
			
				//<BLOCK 1-A> Retrieve interface/proxy:

				//Register channel:
				ChannelServices.RegisterChannel( new HttpChannel() );
				
				//NOTE:
				//(1) We also illustrates how to use interface class of remote object class, as opposed to the remote object class itself.
				//(2) You can also call RemotingConfiguration.Configure("cremoteobjclient.config") instead of Activator.GetObject. 
				//	  In that case, config file name: "/config file/cremoteobjclient(wellknown).config" 
				IRemoteObj obj = (IRemoteObj) Activator.GetObject(
					typeof(IRemoteObj),
					"http://localhost:8085/CRemoteObjURI"
					);

				//<BLOCK 1-A END>
					

				//******************* Do something with your proxy "obj" ***********************
				//<BLOCK 1-B>
				//	* Invoke method on remote object through interface.
				//	* LeaseTime
				
				
				//NOTE: Since obj is of type: IRemoteObj (it's an interface), we can't do this:
				//		obj.evStatus += event_delegate;
				//		But working with interface instead of the remote class itself allows greater separation between provider and client.
				for(int i=0; i<100; i++)
				{ //for-loop-A
					//ATTENTION:
					//(1) If you publish your remote object with mode=SingleCall, everytime you call AuthenticateLoser, you get a new instance of the remote object.
					//This can be seen from server side console - pay attention to object ID: a different instance/objID every time the method is invoked.
					//(2) To see the effect of mode=Singleton (WellKnownObjectMode enum), modify server side config file: "cremoteobjserver(wellknown).config" <lifetime> tag, set:
					//		leaseTime="100MS" sponsorshipTimeout="0MS" renewOnCallTime="100MS" leaseManagerPollTime="10MS"
					//	  Default LeaseTime = 100 millisecond, meaning, your Singleton obj will be marked ready-to-dispose 100 milli-sec after last time you invoke a method on the remote object.
					//	  Invoke AuthenticateLoser after that, you will get a different instance of the remote object.
					//	  MSDN Reference: "Lifetime Leases"
					//(3) We've hard coded a few user/passwd in our remote object class, CRemoteObj.
					//	  The data is packaged in a HashTable object inside CRemoteObj.AuthenticateLoser() - key: user name; values: password.
					Console.WriteLine("i: {0}; Authentication result: {1}",
						i.ToString(),
						obj.AuthenticateLoser("Dexter", "AceInTheOpen")
						);

					Thread.Sleep(101); //To see the effect of LeaseTime on remote object's lifetime, Sleep for 100 milli-seconds + a little more. 
										  //Pay attention to server console and objID.

					
				} //for-loop-A
				
				//<BLOCK 1-B END>
				

				//<BLOCK 1-C> Asynchronous programming/remoting
				/*
				//(1) Objectives:
				//		(a) Invoke method on remote object asynchronously.
				//		(b) Retrieve return and output value.
				//(2) MSDN reference, .NET Framework Developer's Guide:
				//		(a) "Asynchronous Delegates Programming Sample" 
				//		(b) "Asynchronous Remoting"
				//		(c) "Asynchronous Programming Overview"
				//			MSDN online: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpovrasynchronousprogrammingoverview.asp
				//(3) Quote from MSDN:
				//		"Asynchronous programming in a remoting scenario is identical to asynchronous programming in a single application domain or context."
				//
				//	  Prequisite: Relevant framework facility: IAsyncResult, WaitHandle, WaitOne, Delegates, BeginInvoke, EndInvoke.
				//	  If you're not familiar with asynchronous programming in general, read this sample first.
							
				SetupUserDelegate d = new SetupUserDelegate(obj.SetupUser);
				
				//Invoke CRemoteObj.SetupUser
				string sTime;
				IAsyncResult ar = d.BeginInvoke(
					"Dexter",
					"AceInOpen",
					out sTime,
					null,
					null
					);

				//Blocks the current thread until obj.AuthenticateLoser completes.
				ar.AsyncWaitHandle.WaitOne(); 

				if(ar.IsCompleted)
				{
					//Retrieve (a) output sTime, (b) return value.
					string ret = d.EndInvoke(out sTime, ar);

					Console.WriteLine("obj.SetupUser return. sTime: {0} {1}return value: {2}", sTime, Environment.NewLine, ret);
					Console.WriteLine();
				}
				
				//Passing custom object to/from remote object:
				Console.WriteLine("Invoking CRemoteObj.UpdateProfile. Passing custom object to method.");
				CProfile p = new CProfile("John", "Kennedy", "JFK", "ace");
				CProfile p2 = obj.UpdateProfile(p);
				Console.WriteLine("UpdateProfile completed. return p2 passwd: {0}", p2.passwd);

				*/
				//<BLOCK 1-C END>
								

			} //try-A
			catch(Exception err)
			{
				Console.WriteLine("Error parsing configuration file: {0}", err.ToString());
			}
			//<BLOCK 1 END>
			



			//<BLOCK 2>
			//*****************************************************//
			//Scenario 2: if the remote object is published as client-activated 
			try
			{ //try-B

				//<BLOCK 2-A>
				//OPTION 2a: Use configuration file, then use "new" keyword to instantiate client-activated object.
				//		     Disadvantage of this option is that it requires the client to reference CRemoteObj (server class) assembly - instead of just the interface assembly CRemoteObjInterface.

				//NOTE:
				//(1) Configure remoting channel and stuff with config file instead.
				//   File name: "/config file/cremoteobjclient(client).config --> Just rename it to "cremoteobjclient.config" and put it beside the executatble "CRemoteObjClient.exe".
				//(2) If you wish to specify security setting in config file, file name of config file must be "application_name.exe.config"
				
				/*
				RemotingConfiguration.Configure("cremoteobjclient.config");
				CRemoteObj obj = new CRemoteObj();
				*/

				//<BLOCK 2-A END>

				
				//<BLOCK 2-B>
				/*
				//OPTION 2b: client activated remote object
				ChannelServices.RegisterChannel( new TcpChannel(6792) );

				object[] attrs = { new UrlAttribute("tcp://localhost:8086/CRemoteObjServer") };
				ObjectHandle handle = (ObjectHandle) Activator.CreateInstance("CRemoteObj", "nsCRemoteObj.CRemoteObj", attrs);
				CRemoteObj obj = (CRemoteObj) handle.Unwrap(); //Hey, no need to reference remote object assembly unless we use "new" to instantiate the remote object.
															   //BUT, since you need to play with events, you can't cast "obj" to "IRemoteObj":
															   //		obj.evStatus += event_delegate; 
				*/
				//<BLOCK 2-B END>
				

				//<BLOCK 2-C>
				/*
				
				//******************* Do something with your proxy "obj" ***********************
				CStatusEventSink esStatusEvSink = new CStatusEventSink();
				StatusEvent event_delegate = new StatusEvent(esStatusEvSink.StatusHandler);
				obj.evStatus += event_delegate; //Register sink delegate handler with proxy's event.

				for(int i=0; i<5; i++)
				{
					Console.WriteLine("i: {0}; Authentication result: {1}",
						i.ToString(),
						obj.AuthenticateLoser("Paul", "12345")
						);
				}
				*/

				//<BLOCK 2-C END>

			} //try-B
			catch(Exception err)
			{
				Console.WriteLine("Error CRemoteObjClient: {0}", err.ToString());
			}
			//<BLOCK 2 END>


		} //Main()

	} //CRemoteObjClient

} //nsCRemoteObjClient

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


Written By
Hong Kong Hong Kong
Me too, I'm a developer.

Written By
Web Developer
Hong Kong Hong Kong
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions