简体   繁体   中英

c# Load assemblies into child domain

    /// <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

I am trying to load some assemblies into a separate AppDomain so that I would be able to unload them later.

I posted comments with the first function in the hope it explains what I'm attempting to do. The second function is called from the child AppDomain with the hope that the assemblies will be loaded there.

This doesn't work.

Does casting the return of CreateInstanceAndUnWrap to the Type I need implicitly mean I need to load the assembly into both the parent and child domain? If so, I won't do that.

I have attempted to set the PrivateBinPath but when I attempt to load an assembly along that path I am suspecting it is never probed. I base this on what an exceptions tells me. An exception is thrown indicating the assembly cannot be found. The path mentioned in the exception is always the base directory with the name of my assembly appended to it.

I would enjoy learning both how to fix this and how what I did was wrong. I beg for enlightenment...seriously...I'm on my knees.

edit

I was incorrect about the exception message. It lists the path is say the assembly is in. That path resolves in a child directory of the base directory. My best theory is still that that I have not setup the probing for child directories of the base directory correctly.

Despite my best efforts I cannot load an assembly from anywhere but the base directory. I will copy assemblies to the base directory, load them into a cache using shadow copy, and immediately delete them from my base directory. This is messy and has other issues but it's the best I think I can manage at the moment.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM