Skip to content

Instantly share code, notes, and snippets.

@DevJohnC
Created November 7, 2013 18:48
Show Gist options
  • Select an option

  • Save DevJohnC/7359810 to your computer and use it in GitHub Desktop.

Select an option

Save DevJohnC/7359810 to your computer and use it in GitHub Desktop.
//
// Author: John Carruthers (johnc@frag-labs.com)
//
// Copyright (C) 2013 John Carruthers
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Remoting;
namespace FragLabs.AdjutantOS.API.Modules.Domains
{
/// <summary>
/// Provides common functionality in each domain.
/// </summary>
public class DomainController : DomainShareObject
{
/// <summary>
/// Gets the current DomainController for the current AppDomain.
/// </summary>
public static DomainController Current { get; protected set; }
/// <summary>
/// Invoked before the DomainController is destroyed in preperation for the appdomain to be unloaded.
/// </summary>
public event EventHandler<EventArgs> BeforeDestroy;
protected virtual void OnBeforeDestroy()
{
var handler = BeforeDestroy;
if (handler != null) handler(this, EventArgs.Empty);
}
/// <summary>
/// Gets the DomainManager responsible for the DomainController.
/// </summary>
public DomainManager Manager { get; protected set; }
/// <summary>
/// Registered assemblies for type resolution.
/// </summary>
private readonly List<Assembly> _assemblies = new List<Assembly>();
/// <summary>
/// Gets the appdomain the DomainController instance is loaded in.
/// </summary>
public AppDomain AppDomain { get { return AppDomain.CurrentDomain; } }
/// <summary>
/// Is main domain?
/// </summary>
internal bool IsMainDomain { get; set; }
/// <summary>
/// Creates a new instance of DomainController.
/// </summary>
public DomainController()
{
IsMainDomain = true;
Current = this;
Manager = DomainManager.Current;
Manager.Add(this);
}
/// <summary>
/// Creates a new instance of DomainController with a specific DomainManager.
/// </summary>
/// <param name="manager">DomainManager responsible for the DomainController.</param>
public DomainController(DomainManager manager)
{
IsMainDomain = true;
Current = this;
Manager = manager;
Manager.Add(this);
}
/// <summary>
/// Destroys the domain controller in preperation for unloading the domain.
/// </summary>
public void Destroy()
{
OnBeforeDestroy();
}
/// <summary>
/// Initialize.
/// </summary>
public void Initialize(DomainManager manager)
{
DomainManager.Current = manager;
DomainManager.Initialized = true;
IsMainDomain = false;
}
/// <summary>
/// Add an assembly for type resolution.
/// </summary>
/// <param name="asm"></param>
public void AddAssembly(Assembly asm)
{
_assemblies.Add(asm);
}
/// <summary>
/// Loads an assembly into the domain.
/// </summary>
/// <param name="filePath"></param>
/// <param name="addToResolutionAssemblies"></param>
public void LoadAssembly(string filePath, bool addToResolutionAssemblies = true)
{
var asm = Assembly.LoadFile(filePath);
if (addToResolutionAssemblies)
AddAssembly(asm);
}
/// <summary>
/// Creates a new instance of an object and marshals the object across appdomains.
/// </summary>
/// <param name="domainType"></param>
/// <param name="ctorArgs"></param>
/// <returns></returns>
public object CreateMarshalledReference(DomainType domainType, params object[] ctorArgs)
{
return CreateMarshalledReference(domainType.Controller, domainType, ctorArgs);
}
/// <summary>
/// Creates a new instance of an object and marshals the object across appdomains.
/// </summary>
/// <param name="controller"></param>
/// <param name="domainType"></param>
/// <param name="ctorArgs"></param>
/// <returns></returns>
public object CreateMarshalledReference(DomainController controller, DomainType domainType, params object[] ctorArgs)
{
var objRef = controller.CreateInstance(domainType, ctorArgs);
return RemotingServices.Unmarshal(objRef);
}
/// <summary>
/// Creates an ObjRef for an object in the foreign AppDomain.
/// </summary>
/// <param name="domainType"></param>
/// <param name="ctorArgs"></param>
/// <returns></returns>
public ObjRef CreateInstance(DomainType domainType, params object[] ctorArgs)
{
if (!domainType.Type.IsSubclassOf(typeof(MarshalByRefObject)))
throw new Exception("Type must be subclass of MarshalByRefObject");
var obj = Activator.CreateInstance(domainType.Type, ctorArgs) as MarshalByRefObject;
return RemotingServices.Marshal(obj);
}
/// <summary>
/// Attempts to resolve a domain type.
/// </summary>
/// <param name="typeName"></param>
/// <returns></returns>
public DomainType ResolveType(string typeName)
{
var type = Type.GetType(typeName);
if (type != null)
return type.GetDomainType();
foreach (var asm in _assemblies)
{
type = asm.GetType(typeName);
if (type != null)
return type.GetDomainType();
}
return null;
}
/// <summary>
/// Attempts to get a DomainType definition for an object.
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public DomainType GetDomainType(object obj)
{
if (RemotingServices.IsTransparentProxy(obj))
return null;
return obj.GetType().GetDomainType();
}
/// <summary>
/// Searches the domain for subtypes of the provided parent type.
/// </summary>
/// <param name="parentType"></param>
/// <returns></returns>
public DomainType[] FindSubTypes(Type parentType)
{
var ret = new List<DomainType>();
foreach (var asm in _assemblies)
{
foreach (var type in asm.GetTypes())
{
if (type.IsSubclassOf(parentType))
{
ret.Add(new DomainType(type));
}
}
}
return ret.ToArray();
}
/// <summary>
/// Searches the domain for types that implement a given interface type.
/// </summary>
/// <param name="interfaceType"></param>
/// <returns></returns>
public DomainType[] FindTypesThatImplement(Type interfaceType)
{
var ret = new List<DomainType>();
foreach (var asm in _assemblies)
{
foreach (var type in asm.GetTypes())
{
foreach (var iface in type.GetInterfaces())
{
if (iface.Equals(interfaceType))
{
ret.Add(new DomainType(type));
}
if (iface.IsGenericType)
{
var genericType = iface.GetGenericTypeDefinition();
if (genericType.Equals(interfaceType))
{
ret.Add(new DomainType(type));
}
}
}
}
}
return ret.ToArray();
}
/// <summary>
/// Invokes an Action delegate on the main application domain.
/// <para>If the delegate is not in a library loaded in the main application domain the Action should be made domain safe with a DomainCallback.</para>
/// </summary>
/// <param name="action"></param>
public void InvokeAction(Action action)
{
action();
}
/// <summary>
/// Invokes an Action delegate on the main application domain.
/// <para>If the delegate is not in a library loaded in the main application domain the Action should be made domain safe with a DomainCallback.</para>
/// </summary>
/// <typeparam name="T1"></typeparam>
/// <param name="action"></param>
/// <param name="arg1"></param>
public void InvokeAction<T1>(Action<T1> action, T1 arg1)
{
action(arg1);
}
/// <summary>
/// Invokes an Action delegate on the main application domain.
/// <para>If the delegate is not in a library loaded in the main application domain the Action should be made domain safe with a DomainCallback.</para>
/// </summary>
/// <typeparam name="T1"></typeparam>
/// <typeparam name="T2"></typeparam>
/// <param name="action"></param>
/// <param name="arg1"></param>
/// <param name="arg2"></param>
public void InvokeAction<T1, T2>(Action<T1, T2> action, T1 arg1, T2 arg2)
{
action(arg1, arg2);
}
/// <summary>
/// Invokes an Action delegate on the main application domain.
/// <para>If the delegate is not in a library loaded in the main application domain the Action should be made domain safe with a DomainCallback.</para>
/// </summary>
/// <typeparam name="T1"></typeparam>
/// <typeparam name="T2"></typeparam>
/// <typeparam name="T3"></typeparam>
/// <param name="action"></param>
/// <param name="arg1"></param>
/// <param name="arg2"></param>
/// <param name="arg3"></param>
public void InvokeAction<T1, T2, T3>(Action<T1, T2, T3> action, T1 arg1, T2 arg2, T3 arg3)
{
action(arg1, arg2, arg3);
}
/// <summary>
/// Invokes a Func delegate on the main application domain.
/// <para>If the delegate is not in a library loaded in the main application domain the Action should be made domain safe with a DomainCallback.</para>
/// </summary>
/// <typeparam name="TResult"></typeparam>
/// <param name="func"></param>
public TResult InvokeFunc<TResult>(Func<TResult> func)
{
return func();
}
/// <summary>
/// Invokes a Func delegate on the main application domain.
/// <para>If the delegate is not in a library loaded in the main application domain the Action should be made domain safe with a DomainCallback.</para>
/// </summary>
/// <typeparam name="TResult"></typeparam>
/// <typeparam name="T1"></typeparam>
/// <param name="func"></param>
public TResult InvokeFunc<T1, TResult>(Func<T1, TResult> func, T1 arg1)
{
return func(arg1);
}
/// <summary>
/// Invokes a Func delegate on the main application domain.
/// <para>If the delegate is not in a library loaded in the main application domain the Action should be made domain safe with a DomainCallback.</para>
/// </summary>
/// <typeparam name="TResult"></typeparam>
/// <typeparam name="T1"></typeparam>
/// <typeparam name="T2"></typeparam>
/// <param name="func"></param>
public TResult InvokeFunc<T1, T2, TResult>(Func<T1, T2, TResult> func, T1 arg1, T2 arg2)
{
return func(arg1, arg2);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment