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

.NET Remoting Customization Made Easy: Custom Sinks

Rate me:
Please Sign up or sign in to vote.
4.86/5 (77 votes)
20 May 200320 min read 210.9K   2.2K   97  
.NET Remoting customization – it doesn't have to be so hard!
//
// Written by Motti Shaked
//
// motti@wincode.net
//
// Version: 1.0.0.0
//
// DISCLAIMER:
//
// You may use this code as you please.
// You may modify and share it freely.
// You may NOT hold me liable for any damage
// caused to you, your company, your neighbors,
// or anyone else as a result of using this code,
// taking ideas from it, dreaming of it,
// or any other use you may find it suitable for.
// Whatever you do with this code is at 
// your own risk.
//
// Enjoy!
// 

using System;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Messaging;
using System.Collections;
using System.Reflection;

namespace CustomSinks
{
	public class CustomServerSinkProvider : BaseCustomSinkProvider, IServerChannelSinkProvider
	{
		private IServerChannelSinkProvider nextProvider;

		public CustomServerSinkProvider(IDictionary properties, ICollection providerData)
			: base(properties, providerData)
		{
		}

		public IServerChannelSinkProvider Next
		{
			get {return this.nextProvider; }
			set {this.nextProvider = value;}
		}

		public IServerChannelSink CreateSink(IChannelReceiver channel) 
		{
			BaseCustomSink customSinkObject = null;
			bool keepCreatingInstance = false;

			// the custom sink must be provided the perProviderState object.
			// passing this object after construction is too late, because the sink
			// may need it in its constructor.
			// however, I did not want to affect the signature of every
			// possible sink constructor (and wanted to
			// allow writing basic custom sinks without explicitly writing a constructor).
			// so I pass it through the CallContext.
			CallContext.SetData("perProviderState", this.perProviderState);

			// try to instantiate the custom sink
			// with a constructor that takes ServerSinkCreationData (or SinkCreationData)
			object [] par = {new ServerSinkCreationData(this.data, channel)};
			try
			{
				customSinkObject = (BaseCustomSink)Activator.CreateInstance(this.customSinkType, par);
			}
			catch (MissingMethodException)
			{
				// do nothing - try to create using a parameterless constructor
				keepCreatingInstance = true;
			}
			catch (Exception e)
			{
				ExamineConstructionException(e);
			}

			// if there is no constructor that takes ServerSinkCreationData or SinkCreationData,
			// look for a parameterless constructor
			if (keepCreatingInstance)
			{
				try
				{
					customSinkObject = (BaseCustomSink)Activator.CreateInstance(customSinkType);
				}
				catch (Exception e)
				{
					ExamineConstructionException(e);
				}
			}

			// create next sink in the chain
			IServerChannelSink next = nextProvider.CreateSink(channel);

			if (customSinkObject != null)
			{
				customSinkObject.SetNextSink(next);
				return customSinkObject;
			}
			else
			{
				return next;
			}
		}

		public void GetChannelData(IChannelDataStore channelData)
		{
		}

		// this method has to examine the exception thrown from
		// a derived class' constructor and act accordingly
		private void ExamineConstructionException(Exception e)
		{
			if (!(e.InnerException is ExcludeMeException))
			{
				if (e is TargetInvocationException)
				{
					throw new CustomSinkException(
						string.Format("Could not create instance of {0}. {1} was thrown during construction. Message: {2}", 
						this.customSinkType.ToString(), e.InnerException.GetType().ToString(),
						e.InnerException.Message), e);
				}
				else
				{
					throw new CustomSinkException(
						string.Format("Could not create instance of {0}.", 
						this.customSinkType.ToString()), e);
				}
			}
		}
	}
}

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
Software Developer (Senior)
Canada Canada
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions