diff --git a/ServerHost/AppDomainSetupUtils.cs b/ServerHost/AppDomainSetupUtils.cs
new file mode 100644
index 0000000..b33b108
--- /dev/null
+++ b/ServerHost/AppDomainSetupUtils.cs
@@ -0,0 +1,95 @@
+using System;
+using System.Globalization;
+using System.IO;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.Remoting;
+
+namespace Server.Host
+{
+ public static class AppDomainSetupUtils
+ {
+ private static readonly object[] NoArgs = new object[0];
+
+ ///
+ /// Create a new instance of the trace listener in the specified app domain.
+ ///
+ /// The type of object to be created.
+ /// The AppDomain where the "far" tracer object should be created.
+ /// An instance of the remote trace instance.
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal static T CreateObjectInstanceInAppDomain(
+ AppDomain appDomain,
+ object[] args = null)
+ where T : class
+ {
+ string appDomainName = appDomain.FriendlyName;
+ string className = typeof(T).GetTypeInfo().FullName;
+ string assemblyFilePath = typeof(T).GetTypeInfo().Assembly.Location;
+
+ if (string.IsNullOrEmpty(className))
+ {
+ throw new ArgumentNullException("Cannot determine class name for " + typeof(T));
+ }
+ if (string.IsNullOrEmpty(assemblyFilePath))
+ {
+ throw new ArgumentNullException("Cannot determine assembly location for " + typeof(T));
+ }
+
+ // Create instance of the class in the "far" app domain.
+
+ ObjectHandle remoteObjRef = appDomain.CreateInstanceFrom(
+ assemblyFilePath,
+ className,
+ false,
+ BindingFlags.Default,
+ null,
+ args ?? NoArgs,
+ CultureInfo.CurrentCulture,
+ NoArgs);
+
+ object remoteObj = remoteObjRef.Unwrap();
+
+ if (remoteObj == null)
+ {
+ throw new ArgumentNullException(
+ $"Could not create remote object instance {className}"
+ + $" from assembly {assemblyFilePath}"
+ + $" in AppDomain {appDomainName}");
+ }
+
+ T remoteTracer = remoteObj as T;
+
+ if (remoteTracer == null)
+ {
+ Type type1 = remoteObj.GetType();
+ Type type2 = typeof(T);
+ string codebase1 = type1.GetTypeInfo().Assembly.CodeBase;
+ string codebase2 = type2.GetTypeInfo().Assembly.CodeBase;
+
+ throw new InvalidCastException(
+ $"Cannot cast server object {type1} from assembly {codebase1} to type {type2} from assembly {codebase2}");
+ }
+
+ return remoteTracer;
+ }
+
+ ///
+ /// Construct AppDomain configuration metadata based on the current execution environment.
+ ///
+ /// AppDomainSetup info for creating an new child AppDomain.
+ public static AppDomainSetup GetAppDomainSetupInfo()
+ {
+ AppDomain currentAppDomain = AppDomain.CurrentDomain;
+
+ return new AppDomainSetup
+ {
+ ApplicationBase = Directory.GetCurrentDirectory(),
+ ConfigurationFile = currentAppDomain.SetupInformation.ConfigurationFile,
+ ShadowCopyFiles = currentAppDomain.SetupInformation.ShadowCopyFiles,
+ ShadowCopyDirectories = currentAppDomain.SetupInformation.ShadowCopyDirectories,
+ CachePath = currentAppDomain.SetupInformation.CachePath
+ };
+ }
+ }
+}
diff --git a/ServerHost/ServerHost.cs b/ServerHost/ServerHost.cs
index 723a1d6..83c50d8 100644
--- a/ServerHost/ServerHost.cs
+++ b/ServerHost/ServerHost.cs
@@ -4,7 +4,6 @@
using System;
using System.Collections.Concurrent;
using System.Diagnostics.CodeAnalysis;
-using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
@@ -54,7 +53,7 @@ public static ServerHostHandle LoadServerInNewAppDomain(
}
}
- AppDomainSetup setup = GetAppDomainSetupInfo();
+ AppDomainSetup setup = AppDomainSetupUtils.GetAppDomainSetupInfo();
AppDomain appDomain = AppDomain.CreateDomain(serverName, null, setup);
LoadedAppDomains[serverName] = appDomain;
@@ -62,25 +61,9 @@ public static ServerHostHandle LoadServerInNewAppDomain(
// The server class must have a public constructor which
// accepts single parameter of server name.
var args = new object[] { serverName };
- var noActivationAttributes = new object[0];
- object serverObj = appDomain.CreateInstanceFromAndUnwrap(
- serverAssembly, serverTypeName, false,
- BindingFlags.Default, null, args, CultureInfo.CurrentCulture,
- noActivationAttributes);
-
- TServer server = serverObj as TServer;
-
- if (server == null)
- {
- Type type1 = serverObj.GetType();
- Type type2 = typeof(TServer);
- string codebase1 = type1.GetTypeInfo().Assembly.CodeBase;
- string codebase2 = serverType.GetTypeInfo().Assembly.CodeBase;
-
- throw new InvalidCastException(
- $"Cannot cast server object {type1} from assembly {codebase1} to type {type2} from assembly {codebase2}");
- }
+ TServer server = AppDomainSetupUtils
+ .CreateObjectInstanceInAppDomain(appDomain, args);
appDomain.UnhandledException += ReportUnobservedException;
@@ -160,24 +143,6 @@ public static void UnloadAllServers()
}
}
- ///
- /// Construct AppDomain configuration metadata based on the current execution environment.
- ///
- /// AppDomainSetup info for creating an new child AppDomain.
- public static AppDomainSetup GetAppDomainSetupInfo()
- {
- AppDomain currentAppDomain = AppDomain.CurrentDomain;
-
- return new AppDomainSetup
- {
- ApplicationBase = Directory.GetCurrentDirectory(),
- ConfigurationFile = currentAppDomain.SetupInformation.ConfigurationFile,
- ShadowCopyFiles = currentAppDomain.SetupInformation.ShadowCopyFiles,
- ShadowCopyDirectories = currentAppDomain.SetupInformation.ShadowCopyDirectories,
- CachePath = currentAppDomain.SetupInformation.CachePath
- };
- }
-
///
/// Event handle method to report any unhandled exceptions in a newly created AppDomain.
///
diff --git a/ServerHost/ServerHostFixture.cs b/ServerHost/ServerHostFixture.cs
index 14d8453..93c36af 100644
--- a/ServerHost/ServerHostFixture.cs
+++ b/ServerHost/ServerHostFixture.cs
@@ -30,7 +30,7 @@ public ServerHostFixture()
_log = LogManager.GetLogger(_className);
- _log.InfoFormat("{0} - Initialize", _className);
+ _log.Info($"{_className} - Initialize");
}
///
@@ -51,7 +51,7 @@ protected virtual void Dispose(bool disposing)
ReleaseUnmanagedResources();
if (disposing)
{
- _log.InfoFormat("{0} - Dispose", _className);
+ _log.Info($"{_className} - Dispose");
// TODO release managed resources here
}
@@ -68,7 +68,7 @@ protected virtual void Dispose(bool disposing)
[SuppressMessage("ReSharper", "MemberCanBeMadeStatic.Local")]
private void ReleaseUnmanagedResources()
{
- _log.InfoFormat("{0} - ReleaseUnmanagedResources", _className);
+ _log.Info($"{_className} - ReleaseUnmanagedResources");
// TODO release unmanaged resources here
}
diff --git a/Tests/TestServer/App.config b/Tests/TestServer/App.config
new file mode 100644
index 0000000..6238316
--- /dev/null
+++ b/Tests/TestServer/App.config
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Tests/TestServer/Program.cs b/Tests/TestServer/Program.cs
index 21a1ff7..9e62a80 100644
--- a/Tests/TestServer/Program.cs
+++ b/Tests/TestServer/Program.cs
@@ -3,6 +3,7 @@
using System;
using System.Reflection;
+using JetBrains.Annotations;
using log4net;
using log4net.Config;
@@ -11,6 +12,7 @@
namespace Server.Host.Tests.TestServer
{
+ [PublicAPI]
public static class Program
{
private static readonly ILog Log = LogManager.GetLogger("TestServer");
@@ -19,15 +21,17 @@ public static void Main(string[] args)
{
const string serverName = "MyTestServer";
+ string progName = Assembly.GetEntryAssembly().GetName().Name;
+
Server server = new Server(serverName);
- Log.InfoFormat("Initializing Server {0} with args = {1}", serverName, string.Join(", ", args));
+ Log.Info($"Initializing Server {serverName} with args = " + string.Join(", ", args));
server.InitServer();
Log.Info("Running Server");
int rc = server.Run();
- Log.InfoFormat("{0}.exe finished with rc={1}", Assembly.GetEntryAssembly().GetName().Name, rc);
+ Log.Info($"{progName}.exe finished with rc={rc}");
Environment.Exit(rc);
}
}
diff --git a/Tests/TestServer/Server.cs b/Tests/TestServer/Server.cs
index f17ede2..18ae272 100644
--- a/Tests/TestServer/Server.cs
+++ b/Tests/TestServer/Server.cs
@@ -2,7 +2,9 @@
// Licensed with Apache 2.0 https://github.com/jthelin/ServerHost/blob/master/LICENSE
using System;
+using System.Diagnostics;
using log4net;
+using log4net.Config;
namespace Server.Host.Tests.TestServer
{
@@ -12,12 +14,17 @@ public class Server : MarshalByRefObject
public Server(string serverName)
{
- Log.InfoFormat("Server - {0}", serverName);
+ // Initialize log4net logging.
+ XmlConfigurator.Configure();
+
+ Log.Info($"Server - {serverName}");
}
public void InitServer()
{
- Log.Info("InitServer!");
+ Log.Info("InitServer - log4net");
+ Debug.WriteLine("InitServer - Debug.WriteLine");
+ Trace.TraceInformation("InitServer - Trace.TraceInformation");
}
public int Run()
diff --git a/Tests/TestServer/TestServer.csproj b/Tests/TestServer/TestServer.csproj
index ccc8a5d..fed3c76 100644
--- a/Tests/TestServer/TestServer.csproj
+++ b/Tests/TestServer/TestServer.csproj
@@ -8,6 +8,9 @@
+
+ all
+
\ No newline at end of file
diff --git a/Tests/Tests.Net46/App.config b/Tests/Tests.Net46/App.config
new file mode 100644
index 0000000..6238316
--- /dev/null
+++ b/Tests/Tests.Net46/App.config
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+