AppDomain

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");
            }
        }
        
    }
    
}
原文地址:https://www.cnblogs.com/wesson2019-blog/p/13948150.html