static void

AppDomain CreateDomain

An example of running a assembly in another AppDomain. Here we're using a runner class (it must inherit MarshalByRefObject) which loads itself in the other domain and executes the code. Depenedencies are assumed to be in the same folder, and are resolved using AssemblyResolve handler. Creating a new domain allows you to use an App.config (even for a dll). There's a hack for swapping config files in the same domain too.

using System;
using System.Configuration;
using System.IO;
using System.Reflection;
namespace Library.Reflection
    /// <summary>
    /// Run a type in an assembly - call static <see cref="RunInNewDomain"/>
    /// </summary>
    /// <remarks>
    /// Note this has to inherit from MarshalByRefObject.
    /// <para/>
    /// Calls a static method named Run.
    /// </remarks>
    /// <example>
    /// <code>
    ///     string typeName = "TestMe.RunMe";
    ///     string assemblyPath = @"C:\TestMe\bin\Debug\TestMe.dll";
    ///     AssemblyRunner.RunInNewDomain(typeName, assemblyPath);
    ///     //calls TestMe.RunMe.Run();
    /// </code>
    /// </example>
    public class AssemblyRunner : MarshalByRefObject
        /// <summary>
        /// Runs the specified type name in a new domain.
        /// </summary>
        /// <param name="assemblyPath">The assembly path.</param>
        /// <param name="typeName">Name of the type.</param>
        public static void RunInNewDomain(string assemblyPath, string typeName)
            if (!File.Exists(assemblyPath))
                throw new FileNotFoundException("File not found", assemblyPath);
            //create a new domain with a config
            var setup = new AppDomainSetup();
            //directory where the dll and dependencies are
            setup.ApplicationBase = Path.GetDirectoryName(assemblyPath);
            //try to load a configuration file
            if (File.Exists(assemblyPath + ".config"))
                setup.ConfigurationFile = assemblyPath + ".config";
            setup.ApplicationName = "AssemblyRunner";
            //Create the new domain
            var domain = AppDomain.CreateDomain("AssemblyRunner", null, setup);
                //load this assembly/ type into the new domain
                var runner =
                //other instance of this class in new domain loads dll
                runner.LoadDll(assemblyPath, typeName);
                //unload domain
        private string _oldConfigPath;
        /// <summary>
        /// Loads the DLL (this should be run in a different domain)
        /// </summary>
        /// <param name="filePath">The file path.</param>
        /// <param name="typeName">Name of the type.</param>
        public void LoadDll(string filePath, string typeName)
            if (!File.Exists(filePath)) return;
            string location = Path.GetDirectoryName(filePath);
            //resolve any dependencies
            AppDomain.CurrentDomain.AssemblyResolve +=
                delegate(object sender, ResolveEventArgs args)
                    string findName = args.Name;
                    string simpleName = new AssemblyName(findName).Name;
                    string assemblyPath = Path.Combine(location, simpleName) + ".dll";
                    if (File.Exists(assemblyPath))
                        return Assembly.LoadFrom(assemblyPath);
                    //can't find it
                    return null;
            //load the assembly into bytes and load it
            byte[] assemblyBytes = File.ReadAllBytes(filePath);
            Assembly a = Assembly.Load(assemblyBytes);
            //find the type in the assembly
            Type t = a.GetType(typeName, true);
            //find the method "Run"
            var run = t.GetMethod("Run");
                //run it (static method, no arguments)
                run.Invoke(null, new object[0]);
        private void RestoreConfig()
            //remember to revert to original config file
            if (!string.IsNullOrEmpty(_oldConfigPath))
        private void CheckForConfig(string filePath)
            //if this is called in the current domain, the config will be wrong
            string configFile = filePath + ".config";
            if (File.Exists(configFile))
                var existingConfig = AppDomain.CurrentDomain.GetData("APP_CONFIG_FILE").ToString();
                if (!configFile.Equals(existingConfig, StringComparison.OrdinalIgnoreCase))
                    _oldConfigPath = existingConfig;
        private static void SwapConfigFile(string configFile)
            AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", configFile);
            //reset the private state flag in ConfigurationManager
            FieldInfo fiInit = typeof(ConfigurationManager).GetField(
                BindingFlags.NonPublic | BindingFlags.Static);
            if (fiInit != null)
                fiInit.SetValue(null, 0);