【问题标题】:c# Load assemblies into child domainc# 将程序集加载到子域中
【发布时间】:2014-03-06 15:22:46
【问题描述】:
    /// <summary>
    /// This function loads a list of assemblies based on their file paths.
    /// This function is intended to load the assemblies into another application domain than the main
    /// one so that the assemblies can be unloaded when the application domain is unloaded.
    /// 
    /// See below to understand how this function achieves loading assemblies into a domain other than
    /// the current one.
    /// 
    /// FIRST a new domain is created ---
    ///     - load the assembly into a child domain of the domain which will execute any code from a plugin.
    /// NEXT the current assembly is loaded into the child domain ---
    ///     - this is MUCH easier than dealing another assembly into a child domain
    ///     - this assembly owns the definition of this PluginLoader class which will take full advantage of
    /// NEXT get a PluginLoader instance from the child domain you just created ---
    ///     - since this instance is from the child domain anything you do with it will affect the child
    ///       domain and not the current one
    ///         - we want to load assemblies into the child domain so this is exactly what we want.
    /// NEXT load the plugin assemblies into the child domain
    ///     - we leverage Assembly.LoadFrom which is MUCH easier to make use of than AppDomain.Load
    ///         - Assembly.Load* is the preferred method of loading assemblies and this is made abundantly
    ///           clear in any attempt to use AppDomain.Load in a generic fashion.
    ///     
    /// CRITICAL KNOWLEDGE
    ///     - PluginLoader MUST derive from MarshalByRefObject or this will WILL NOT WORK.
    /// </summary>
    /// <param name="pathsToAssemblies"></param>
    /// <param name="plugInfo"></param>
    /// <returns></returns>
    static public bool LoadPluginAssemblies(string pluginName, List<string> pathsToAssemblies, out PluginInformation plugInfo)
    {
        try
        {
            string parentAssemblyName = Assembly.GetExecutingAssembly().FullName;

            #region Create child domain and setup tracking for it

            AppDomainSetup ads = new AppDomainSetup();

            ads.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
            ads.PrivateBinPath = "Assemblies";
            //ads.PrivateBinPathProbe = "pluto_is_not_a_planet";

            plugInfo = new PluginInformation(pluginName, AppDomain.CreateDomain(pluginName,null,ads));

            #endregion //Create child domain and setup tracking for it

            #region Load executing assembly into child domain

            plugInfo.ChildDomain.Load(parentAssemblyName);

            #endregion //Load executing assembly into child domain

            #region Get PluginLoader from child domain

            PluginLoader plugLoader =
                (PluginLoader)plugInfo.ChildDomain.CreateInstanceAndUnwrap(parentAssemblyName, "DynamicAssemblyLoadTester.PluginLoader");

            #endregion //Get PluginLoader from child domain

            #region Load assemblies into child domain

            foreach (string assemblyPath in pathsToAssemblies)
            { plugInfo.m_assembliesInDomain.Add(plugLoader._loadAssemblyIntoChildDomain(assemblyPath)); }//end for

            #endregion //Load assemblies into child domain
        }
        catch (System.Exception ex)
        {
            Console.WriteLine("Plugin Load Failure: " + ex.Message);
            plugInfo = null;
            return false;
        }//end try-catch

        return true;
    }//end function

    private Assembly _loadAssemblyIntoChildDomain(string assemblyPath)
    {
        try
        {
            return Assembly.LoadFrom(assemblyPath);
        }
        catch (System.Exception ex)
        {
            Console.WriteLine("Failed to load assembly into child domain:  " + ex.Message);
            return null;
        }//end try-catch
    }//end function

我正在尝试将一些程序集加载到单独的 AppDomain 中,以便以后能够卸载它们。

我发布了带有第一个函数的 cmets,希望它能解释我正在尝试做的事情。第二个函数是从子 AppDomain 调用的,希望在那里加载程序集。

这不起作用。

将 CreateInstanceAndUnWrap 的返回值强制转换为我需要的类型是否意味着我需要将程序集加载到父域和子域中?如果是这样,我不会那样做。

我尝试设置 PrivateBinPath,但是当我尝试沿该路径加载程序集时,我怀疑它从未被探测过。我基于异常告诉我的内容。引发异常,指示找不到程序集。异常中提到的路径始终是附加了我的程序集名称的基本目录。

我会喜欢学习如何解决这个问题以及我做错了什么。我祈求开悟……说真的……我跪了。

编辑

我对异常消息的看法不正确。它列出了程序集所在的路径。该路径在基目录的子目录中解析。我最好的理论仍然是我没有正确设置对基目录的子目录的探测。

【问题讨论】:

  • 你说的这行不通是什么意思。您是否收到错误、异常或程序集根本没有加载到您的新域中?您可以尝试设置一个代理对象 - 它本身 - 除了在他的对象上下文中加载程序集之外什么都不做。请注意,跨越 AppDomain 边界的对象(由CreateInstanceAndUnWrap 创建的对象)需要派生自MarshalByRefObject
  • PluginLoader 确实派生自 MarshalByRefObject。这是我看到的错误。 ... 无法加载文件或程序集 'file:///O:\HP_WORK2\I...\Assemblies\MyAssembly.dll' 或其依赖项之一。系统找不到指定的文件。
  • 程序集 MyAssembly 不会加载到子域中。在第二个函数中抛出异常。这是当我尝试通过跨越 AppDomain 边界的对象将程序集加载到子域中时。所有代码都属于 PluginLoader。 TPluginLoader 是对子域内对象的引用。我无法使用 PluginLoader 将程序集加载到我想要的子域中。
  • 如果没有,就知道出了什么问题。下一个最佳途径是什么?

标签: c# .net-3.5 load .net-assembly appdomain


【解决方案1】:

尽管我尽了最大努力,但我无法从基目录以外的任何地方加载程序集。我将程序集复制到基目录,使用卷影副本将它们加载到缓存中,然后立即从我的基目录中删除它们。这很混乱,还有其他问题,但这是我认为目前我能做到的最好的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-23
    • 1970-01-01
    • 2013-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多