AppDomain与mscoree
using mscoree;
private void DeleteAppDomain(string friendName)
{
UnloadAppDomain(friendName);
}
public static void UnloadAppDomain(string friendName)
{
var domain = GetAppDomain(friendName);
AppDomain.Unload(domain);
}
public static AppDomain GetAppDomain(string friendName)
{
var domains = GetAppDomains();
return domains.FirstOrDefault(s => s.FriendlyName == friendName);
}
public static AppDomain GetMainAppDomain()
{
IntPtr ptr = IntPtr.Zero;
var host = new CorRuntimeHost();
try
{
host.EnumDomains(out ptr);
object domain = null;
while (true)
{
host.NextDomain(ptr, out domain);
if (domain == null)
{
return null;
}
if (!System.Runtime.Remoting.RemotingServices.IsTransparentProxy(domain))
{
break;
}
}
return (AppDomain)domain;
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
return null;
}
finally
{
host.CloseEnum(ptr);
Marshal.ReleaseComObject(host);
}
}
public static IList<AppDomain> GetAppDomains()
{
IList<AppDomain> rslt = new List<AppDomain>();
IntPtr ptr = IntPtr.Zero;
var host = new CorRuntimeHost();
try
{
host.EnumDomains(out ptr);
object domain = null;
while (true)
{
host.NextDomain(ptr, out domain);
if (domain == null)
{
break;
}
rslt.Add((AppDomain)domain);
}
return rslt;
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
return new List<AppDomain>();
}
finally
{
host.CloseEnum(ptr);
Marshal.ReleaseComObject(host);
}
}
跨域加载
/// <summary>
/// 跨域加载
/// </summary>
/// <param name="friendlyName"></param>
/// <param name="assemblyName"></param>
/// <returns></returns>
public static ProxyDomainObject CrossDomainLoad(string friendlyName, string assemblyName)
{
ProxyDomainObject proxy = null;
try
{
AppDomain domain = ProxyDomainObject.GetSiblingDomain(friendlyName);
if (domain == null)
{
Console.WriteLine(".................当前域不存在,创建新应用程序域,并加载dll");
domain = ProxyDomainObject.BuildSiblingDomain(AppDomain.CurrentDomain, friendlyName);
domain.AssemblyLoad += ChildDomain_AssemblyLoad;
proxy = (ProxyDomainObject)domain.CreateInstanceFromAndUnwrap(AppDomain.CurrentDomain.SetupInformation.ApplicationBase + AppDomain.CurrentDomain.SetupInformation.ApplicationName, typeof(ProxyDomainObject).FullName);
proxy.SetDomainDelegate(domain, AppDomain.CurrentDomain);
proxy.LoadAssembly(assemblyName);
}
else
{
Console.WriteLine(".................当前域存在,直接加载dll");
proxy = (ProxyDomainObject)domain.CreateInstanceFromAndUnwrap(AppDomain.CurrentDomain.SetupInformation.ApplicationBase + AppDomain.CurrentDomain.SetupInformation.ApplicationName, typeof(ProxyDomainObject).FullName);
proxy.LoadAssembly(assemblyName);
}
Console.WriteLine(".................childDomain: " + domain.Id + "_" + domain.SetupInformation.ApplicationName + "_" + domain.FriendlyName);
}
catch (Exception ex)
{
Console.WriteLine(".................CrossDomainLoad: " + ex.Message);
}
return proxy;
}
private static void ChildDomain_AssemblyLoad(object sender, AssemblyLoadEventArgs args)
{
Console.WriteLine("==========================" + args.LoadedAssembly.Location + ": " + args.LoadedAssembly.FullName);
}
ProxyDomainObject
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Security.Policy;
using System.Threading.Tasks;
using System.Windows;
public class ProxyDomainObject : MarshalByRefObject
{
/// <summary>
/// 默认应用程序域
/// </summary>
public static AppDomain MainAppDomain { get; set; }
/// <summary>
/// 当前代理应用程序域
/// </summary>
public static AppDomain CurrentAppDomain { get; set; }
/// <summary>
/// 默认应用程序域的代理
/// </summary>
public static ProxyDomainObject MainProxy
{
get
{
AppDomain domain;
if (MainAppDomain == null)
{
domain = AppDomain.CurrentDomain;
}
else
{
domain = MainAppDomain;
}
return (ProxyDomainObject)domain.CreateInstanceFromAndUnwrap(domain.SetupInformation.ApplicationBase + domain.SetupInformation.ApplicationName, typeof(ProxyDomainObject).FullName);
}
}
private static readonly Dictionary<string, AppDomain> _pairAppDomains = new Dictionary<string, AppDomain>();
private Assembly _assembly;
public ProxyDomainObject()
{
_assembly = null;
}
public override object InitializeLifetimeService()
{
//return base.InitializeLifetimeService(); //实例的内部对象会在5分钟内被runtime释放
return null; //将对象的租用周期改变为无限
}
public void LoadAssembly(string assemblyName = null)
{
if (string.IsNullOrEmpty(assemblyName))
{
return;
}
try
{
if (_assembly == null)
{
var assRef = AssemblyName.GetAssemblyName(assemblyName);
_assembly = Assembly.Load(assRef);
Console.WriteLine($"{CurrentAppDomain.Id}.................assembly NULL,执行加载dll");
}
else
{
Console.WriteLine($"{CurrentAppDomain.Id}.................assembly有,不加载dll");
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public object CreateInstance(string fullName, params object[] args)
{
if (_assembly == null)
{
return null;
}
return _assembly.CreateInstance(fullName, true, BindingFlags.Instance | BindingFlags.CreateInstance | BindingFlags.Public, Type.DefaultBinder, args, null, null);
}
public object Invoke(string className, string methodName, params object[] args)
{
if (_assembly == null)
{
return null;
}
var type = _assembly.GetType(className);
if (type == null)
{
return null;
}
var method = type.GetMethod(methodName);
if (method == null)
{
return null;
}
var obj = Activator.CreateInstance(type);
return method.Invoke(obj, args);
}
public void SetDomainDelegate(AppDomain domain, AppDomain parentDomain)
{
CurrentAppDomain = domain;
MainAppDomain = parentDomain;
var crossAppDomainDelegate = new CrossAppDomainDelegate(MyCallBack);
domain.UnhandledException += Domain_UnhandledException; ;
domain.DoCallBack(crossAppDomainDelegate);
}
private void Domain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
if (e.ExceptionObject is Exception ex)
{
LocalParking.LogFactory.Error(ex.Message, ex);
}
}
private void MyCallBack()
{
Application.Current.DispatcherUnhandledException += Current_DispatcherUnhandledException;
}
private void Current_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
}
/// <summary>
/// 是否已有指定名称的应用程序域
/// True 有
/// </summary>
/// <param name="friendlyName"></param>
/// <returns></returns>
private static bool IsContainsAppDomain(string friendlyName)
{
return _pairAppDomains.ContainsKey(friendlyName);
}
public static AppDomain GetSiblingDomain(string friendlyName)
{
if (string.IsNullOrEmpty(friendlyName))
{
return null;
}
if (IsContainsAppDomain(friendlyName))
{
return _pairAppDomains[friendlyName];
}
return null;
}
/// <summary>
/// 创建其他应用程序域
/// </summary>
/// <param name="parentDomain">当前应用程序域,一般是当前默认程序域</param>
/// <param name="siblingDomainName">其他应用程序域名称</param>
/// <returns></returns>
public static AppDomain BuildSiblingDomain(AppDomain parentDomain, string siblingDomainName = null)
{
if (string.IsNullOrEmpty(siblingDomainName))
{
siblingDomainName = Guid.NewGuid().ToString();
}
if (IsContainsAppDomain(siblingDomainName))
{
return _pairAppDomains[siblingDomainName];
}
var evidence = new Evidence(parentDomain.Evidence);
AppDomainSetup ads = new AppDomainSetup
{
ApplicationName = "Shadow",
//应用程序根目录
ApplicationBase = parentDomain.BaseDirectory,
};
//子目录(相对形式)在AppDomainSetup中加入外部程序集的所在目录,多个目录用分号间隔
//ads.PrivateBinPath = assemblyPlugs;
//设置缓存目录
ads.CachePath = ads.ApplicationBase;
//获取或设置指示影像复制是打开还是关闭
ads.ShadowCopyFiles = "true";
//获取或设置目录的名称,这些目录包含要影像复制的程序集
ads.ShadowCopyDirectories = ads.ApplicationBase;
ads.DisallowBindingRedirects = false;
ads.DisallowCodeDownload = true;
ads.ConfigurationFile = parentDomain.SetupInformation.ConfigurationFile;
var domain = AppDomain.CreateDomain(siblingDomainName, evidence, ads);
_pairAppDomains.Add(siblingDomainName, domain);
return domain;
}
public void RemoveSiblingDomain(string siblingDomainName)
{
Console.WriteLine("所有域:" + _pairAppDomains.Count);
foreach (var item in _pairAppDomains)
{
Console.WriteLine(item.Key);
}
Console.WriteLine(".................卸载当前域" + siblingDomainName);
if (_pairAppDomains.ContainsKey(siblingDomainName))
{
Console.WriteLine(".................卸载当前域 exist " + siblingDomainName);
var rslt = _pairAppDomains[siblingDomainName];
_pairAppDomains.Remove(siblingDomainName);
Console.WriteLine(".................卸载当前域 Remove " + siblingDomainName);
try
{
AppDomain.Unload(rslt);
Console.WriteLine(".................卸载当前域 Unload " + siblingDomainName);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Task.Yield().GetAwaiter().GetResult();
Console.WriteLine(ex.Message);
AppDomain.Unload(rslt); // again
Console.WriteLine(ex.Message);
}
finally
{
Console.WriteLine($"{(CurrentAppDomain == null ? 0 : CurrentAppDomain.Id)}.................siblingDomainName");
}
}
}
}