[Mono-dev] mono-service can't run services with AppDomains anymore

Jörg Rosenkranz joerg.rosenkranz at gmail.com
Mon Mar 12 12:11:32 EDT 2007


Hi all,

I have tried to run a service using mono-service on Mono 1.2.3 and
Mono SVN. The service creates a new AppDomain and runs its code inside
of this. This had been working before without problems. Now I get an
exception "Ambiguous matching in method resolution" inside the cross
AppDomain remoting code.

Are there any changes in the AppDomain/Remoting code which could cause
this? I haven't tested our service with Mono for some time so I can't
say when it happend...

I've tracked it down to System.Reflection.Binder+Default.SelectMethod.
There it tries to find an exact match of two parameter lists. Both
contain System.Int32 as only parameter but the comparison result is
false which leads to this exception. Maybe both types are in different
AppDomains and that's why aren't equal?

You can try the attached test case which demonstrates this behaviour.
It writes a Test.log file in it's directory.

# Compile the service
mcs -r:System.ServiceProcess -r:System.Configuration.Install TestService.cs

# Run it standalone -> works
mono TestService.exe -standalone

# Run it in the service wrapper
rm -f test.lock ; mono-service -l:test.lock TestService.exe

In the log file you will find following error:
2007-03-12 16:58:02 - Ambiguous matching in method resolution
  at System.Reflection.Binder+Default.GetBetterMethod
(System.Reflection.MethodBase m1, System.Reflection.MethodBase m2,
System.Type[] types) [0x00000]
  at System.Reflection.Binder+Default.SelectMethod (BindingFlags
bindingAttr, System.Reflection.MethodBase[] match, System.Type[]
types, System.Reflection.Pa
rameterModifier[] modifiers) [0x00000]
  at System.MonoType.GetMethodImpl (System.String name, BindingFlags
bindingAttr, System.Reflection.Binder binder, CallingConventions
callConvention, System.
Type[] types, System.Reflection.ParameterModifier[] modifiers) [0x00000]
  at System.Type.GetMethod (System.String name, BindingFlags
bindingAttr, System.Reflection.Binder binder, CallingConventions
callConvention, System.Type[] t
ypes, System.Reflection.ParameterModifier[] modifiers) [0x00000]
  at System.Type.GetMethod (System.String name, System.Type[] types) [0x00000]
  at System.Runtime.Serialization.Formatters.Binary.CodeGenerator.EmitWrite
(System.Reflection.Emit.ILGenerator gen, System.Type type) [0x00000]
  at System.Runtime.Serialization.Formatters.Binary.CodeGenerator.EmitWritePrimitiveValue
(System.Reflection.Emit.ILGenerator gen, System.Type type) [0x00000
]
  at System.Runtime.Serialization.Formatters.Binary.CodeGenerator.GenerateMetadataType
(System.Type type, StreamingContext context) [0x00000]
  at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.CreateMemberTypeMetadata
(System.Type type) [0x00000]
  at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.GetObjectData
(System.Object obj,
System.Runtime.Serialization.Formatters.Binary.TypeMetadat
a& metadata, System.Object& data) [0x00000]
  at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.WriteObject
(System.IO.BinaryWriter writer, Int64 id, System.Object obj) [0x00000]
  at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.WriteObjectInstance
(System.IO.BinaryWriter writer, System.Object obj, Boolean
isValueObject
) [0x00000]
  at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.WriteQueuedObjects
(System.IO.BinaryWriter writer) [0x00000]
  at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.WriteObjectGraph
(System.IO.BinaryWriter writer, System.Object obj,
System.Runtime.Remoting.
Messaging.Header[] headers) [0x00000]
  at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize
(System.IO.Stream serializationStream, System.Object graph,
System.Runtime.Remo
ting.Messaging.Header[] headers) [0x00000]
  at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize
(System.IO.Stream serializationStream, System.Object graph) [0x00000]
  at System.Runtime.Remoting.Channels.CADSerializer.SerializeObject
(System.Object obj) [0x00000]
  at System.Runtime.Remoting.Messaging.CADMethodCallMessage..ctor
(IMethodCallMessage callMsg) [0x00000]
  at System.Runtime.Remoting.Messaging.CADMethodCallMessage.Create
(IMessage callMsg) [0x00000]
  at System.Runtime.Remoting.Channels.CrossAppDomainSink.SyncProcessMessage
(IMessage msgRequest) [0x00000]



Thanks for your help,
Joerg.
-------------- next part --------------
using System;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.ServiceProcess;
using System.IO;
using System.Threading;
using System.Reflection;
using System.Text;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Messaging;
using System.Configuration.Install;

namespace Log.Write
{
	public class TestService : System.ServiceProcess.ServiceBase
	{
		/// <summary> 
		/// Required designer variable.
		/// </summary>
		private System.ComponentModel.Container components = null;

		private AppDomain	_subDomain = null;
		private ServiceRunner	_runner = null;

		public TestService()
		{
			// This call is required by the Windows.Forms Component Designer.
			InitializeComponent();
		}

		// The main entry point for the process
		static void Main(string [] args)
		{
			if ( args.Length == 1 && args[0] == "-standalone" )
			{
				TestService svc = new TestService();

				svc.OnStart(null);

				Thread.Sleep(3000);

				svc.OnStop();
			}
			else
			{
				System.ServiceProcess.ServiceBase[] ServicesToRun;
	
				// More than one user Service may run within the same process. To add
				// another service to this process, change the following line to
				// create a second service object. For example,
				//
				//   ServicesToRun = new System.ServiceProcess.ServiceBase[] {new TestService(), new MySecondUserService()};
				//
				ServicesToRun = new System.ServiceProcess.ServiceBase[] { new TestService() };

				System.ServiceProcess.ServiceBase.Run(ServicesToRun);
			}
		}

		/// <summary> 
		/// Required method for Designer support - do not modify 
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			components = new System.ComponentModel.Container();
			this.ServiceName = "TestService";
		}

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if (components != null) 
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		/// <summary>
		/// Set things in motion so your service can do its work.
		/// </summary>
		protected override void OnStart(string[] args)
		{
			try
			{
				Log.Write("Creating AppDomain...");
				AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;

				_subDomain = AppDomain.CreateDomain("Test", null, setup);

				if ( _subDomain == null )
					throw new NullReferenceException("Created AppDomain is null.");

				Log.Write("Getting ServiceRunner...");
				ObjectHandle oHandle = _subDomain.CreateInstance("Log.Write", "Log.Write.ServiceRunner");	

				if ( oHandle == null )
					throw new NullReferenceException("Retrieved handle is null.");

				_runner = (ServiceRunner) oHandle.Unwrap();

				Log.Write("Starting Runner...");
				_runner.Start();				

				Log.Write("Done.");
			}
			catch ( Exception ex )
			{
				Log.Write(ex);
			}
		}
 
		/// <summary>
		/// Stop this service.
		/// </summary>
		protected override void OnStop()
		{
			try
			{
				if ( _runner != null )	
				{
					Log.Write("Stopping Runner...");
					_runner.Dispose();
					_runner = null;
					Log.Write("Done.");
				}


				if ( _subDomain != null )
				{
					Log.Write("Unloading AppDomain...");
					AppDomain.Unload(_subDomain);
					_subDomain = null;
					Log.Write("Done.");
				}
			}				
			catch ( Exception ex )
			{
				Log.Write(ex);
			}
		}

		

	}

	public class ServiceRunner : MarshalByRefObject, IDisposable
	{
		private bool	_end = false;
		private Thread	_mainLoop = null;

		public ServiceRunner()
		{}

		public void Start()
		{
			Log.Write("Starting Service...");

			_end = false;
			_mainLoop = new Thread(new ThreadStart(_MainLoop));
			_mainLoop.Start();

			Log.Write("Done.");
		}

		public void Stop()
		{
			if ( _mainLoop != null )
			{
				Log.Write("Stopping Service...");

				_end = true;
				_mainLoop.Join();
				_mainLoop = null;

				Log.Write("Done.");
			}
		}

		#region IDisposable Members

		public void Dispose()
		{
			Stop();
		}

		#endregion

		private void _MainLoop()
		{
			while ( ! _end )
			{
				Log.Write("I'm still alive...");
				Thread.Sleep(2000);
			}
		}
	}

	public sealed class Log
	{
		private static string _logPath;

		static Log()
		{
			_logPath = Path.Combine(
				Path.GetDirectoryName(typeof(Log).Assembly.Location),
				"Test.log");
		}

		public static void Write(string msg)
		{
			using ( FileStream fs = new FileStream(_logPath, FileMode.Append, FileAccess.Write, FileShare.ReadWrite) )
			using ( StreamWriter w = new StreamWriter(fs, System.Text.Encoding.Default) )
			{
				w.WriteLine("{0:yyyy-MM-dd HH:mm:ss} - {1}", DateTime.Now, msg);
				w.Flush();
			}
		}

		public static void Write(Exception ex)
		{
			StringBuilder message = new StringBuilder();
			StringBuilder stacktrace = new StringBuilder();

			for ( Exception e = ex; e != null; e = e.InnerException )
			{
				if ( message.Length > 0 )
					message.Append(Environment.NewLine);

				message.Append(e.Message);

				if ( stacktrace.Length > 0 )
				{
					stacktrace.Append(Environment.NewLine);
					stacktrace.Append("----");
				}
				stacktrace.Append(e.StackTrace);
			}

			Write(message.ToString() + Environment.NewLine + stacktrace.ToString());
		}
	}



	[RunInstaller(true)]
	public class ProjectInstaller : System.Configuration.Install.Installer
	{
		private System.ServiceProcess.ServiceProcessInstaller serviceProcessInstaller1;
		private System.ServiceProcess.ServiceInstaller serviceInstaller1;
		/// <summary>
		/// Required designer variable.
		/// </summary>
		private System.ComponentModel.Container components = null;

		public ProjectInstaller()
		{
			// This call is required by the Designer.
			InitializeComponent();
		}

		/// <summary> 
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if(components != null)
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}


		#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()
		{
			this.serviceProcessInstaller1 = new System.ServiceProcess.ServiceProcessInstaller();
			this.serviceInstaller1 = new System.ServiceProcess.ServiceInstaller();
			// 
			// serviceProcessInstaller1
			// 
			this.serviceProcessInstaller1.Password = null;
			this.serviceProcessInstaller1.Username = null;
			// 
			// serviceInstaller1
			// 
			this.serviceInstaller1.DisplayName = "Test Service";
			this.serviceInstaller1.ServiceName = "Log.Write";
			// 
			// ProjectInstaller
			// 
			this.Installers.AddRange(new System.Configuration.Install.Installer[] {
																					  this.serviceProcessInstaller1,
																					  this.serviceInstaller1});

		}
		#endregion
	}
}


More information about the Mono-devel-list mailing list