Example #1
0
        public static Task <int> ExecuteAsync(string[] args)
        {
            var enableTrace = Environment.GetEnvironmentVariable(EnvironmentNames.Trace) == "1";

#if ASPNET50
            // TODO: Make this pluggable and not limited to the console logger
            if (enableTrace)
            {
                var listener = new ConsoleTraceListener();
                Trace.Listeners.Add(listener);
                Trace.AutoFlush = true;
            }
#endif
            var app = new CommandLineApplication(throwOnUnexpectedArg: false);
            app.Name = Constants.BootstrapperExeName;

            // RuntimeBootstrapper doesn't need to consume '--appbase' option because
            // klr/klr.cpp consumes the option value before invoking RuntimeBootstrapper
            // This is only for showing help info and swallowing useless '--appbase' option
            var optionAppbase = app.Option("--appbase <PATH>", "Application base directory path",
                                           CommandOptionType.SingleValue);
            var optionLib = app.Option("--lib <LIB_PATHS>", "Paths used for library look-up",
                                       CommandOptionType.MultipleValue);
            app.HelpOption("-?|-h|--help");
            app.VersionOption("--version", GetVersion());

            // Options below are only for help info display
            // They will be forwarded to Microsoft.Framework.ApplicationHost
            var optionsToForward = new[]
            {
                app.Option("--watch", "Watch file changes", CommandOptionType.NoValue),
                app.Option("--packages <PACKAGE_DIR>", "Directory containing packages", CommandOptionType.SingleValue),
                app.Option("--configuration <CONFIGURATION>", "The configuration to run under", CommandOptionType.SingleValue),
                app.Option("--port <PORT>", "The port to the compilation server", CommandOptionType.SingleValue)
            };

            app.Execute(args);

            // Help information was already shown because help option was specified
            if (app.IsShowingInformation)
            {
                return(Task.FromResult(0));
            }

            // Show help information if no subcommand/option was specified
            if (!app.IsShowingInformation && !app.RemainingArguments.Any())
            {
                app.ShowHelp();
                return(Task.FromResult(2));
            }

            // Some options should be forwarded to Microsoft.Framework.ApplicationHost
            var appHostName  = "Microsoft.Framework.ApplicationHost";
            var appHostIndex = app.RemainingArguments.FindIndex(s =>
                                                                string.Equals(s, appHostName, StringComparison.OrdinalIgnoreCase));
            foreach (var option in optionsToForward)
            {
                if (option.HasValue())
                {
                    if (appHostIndex < 0)
                    {
                        Console.WriteLine("The option '--{0}' can only be used with {1}", option.LongName, appHostName);
                        return(Task.FromResult(1));
                    }

                    if (option.OptionType == CommandOptionType.NoValue)
                    {
                        app.RemainingArguments.Insert(appHostIndex + 1, "--" + option.LongName);
                    }
                    else if (option.OptionType == CommandOptionType.SingleValue)
                    {
                        app.RemainingArguments.Insert(appHostIndex + 1, "--" + option.LongName);
                        app.RemainingArguments.Insert(appHostIndex + 2, option.Value());
                    }
                    else if (option.OptionType == CommandOptionType.MultipleValue)
                    {
                        foreach (var value in option.Values)
                        {
                            app.RemainingArguments.Insert(appHostIndex + 1, "--" + option.LongName);
                            app.RemainingArguments.Insert(appHostIndex + 2, value);
                        }
                    }
                }
            }

            // Resolve the lib paths
            string[] searchPaths = ResolveSearchPaths(optionLib.Values, app.RemainingArguments);

            Func <string, Assembly> loader     = _ => null;
            Func <Stream, Assembly> loadStream = _ => null;
            Func <string, Assembly> loadFile   = _ => null;

            Func <AssemblyName, Assembly> loaderCallback = assemblyName =>
            {
                string name = assemblyName.Name;

                // Skip resource assemblies
                if (name.EndsWith(".resources"))
                {
                    return(null);
                }

                // If the assembly was already loaded use it
                Assembly assembly;
                if (_assemblyCache.TryGetValue(name, out assembly))
                {
                    return(assembly);
                }

                var loadLock = _assemblyLoadLocks.GetOrAdd(name, new object());
                try
                {
                    // Concurrently loading the assembly might result in two distinct instances of the same assembly
                    // being loaded. This was observed when loading via Assembly.LoadStream. Prevent this by locking on the name.
                    lock (loadLock)
                    {
                        if (_assemblyCache.TryGetValue(name, out assembly))
                        {
                            // This would succeed in case the thread was previously waiting on the lock when assembly
                            // load was in progress
                            return(assembly);
                        }

                        assembly = loader(name) ?? ResolveHostAssembly(loadFile, searchPaths, name);

                        if (assembly != null)
                        {
#if ASPNETCORE50
                            ExtractAssemblyNeutralInterfaces(assembly, loadStream);
#endif
                            _assemblyCache[name] = assembly;
                        }
                    }
                }
                finally
                {
                    _assemblyLoadLocks.TryRemove(name, out loadLock);
                }

                return(assembly);
            };
#if ASPNETCORE50
            var loaderImpl = new DelegateAssemblyLoadContext(loaderCallback);
            loadStream = assemblyStream => loaderImpl.LoadStream(assemblyStream, assemblySymbols: null);
            loadFile   = path => loaderImpl.LoadFile(path);

            AssemblyLoadContext.InitializeDefaultContext(loaderImpl);

            if (loaderImpl.EnableMultiCoreJit())
            {
                loaderImpl.StartMultiCoreJitProfile("startup.prof");
            }
#else
            var loaderImpl = new LoaderEngine();
            loadStream = assemblyStream => loaderImpl.LoadStream(assemblyStream, assemblySymbols: null);
            loadFile   = path => loaderImpl.LoadFile(path);

            ResolveEventHandler handler = (sender, a) =>
            {
                var appDomain   = (AppDomain)sender;
                var afterPolicy = appDomain.ApplyPolicy(a.Name);
                if (afterPolicy != a.Name)
                {
                    return(Assembly.Load(afterPolicy));
                }

                return(loaderCallback(new AssemblyName(afterPolicy)));
            };

            AppDomain.CurrentDomain.AssemblyResolve += handler;
            AppDomain.CurrentDomain.AssemblyLoad    += (object sender, AssemblyLoadEventArgs loadedArgs) =>
            {
                // Skip loading interfaces for dynamic assemblies
                if (loadedArgs.LoadedAssembly.IsDynamic)
                {
                    return;
                }

                ExtractAssemblyNeutralInterfaces(loadedArgs.LoadedAssembly, loadStream);
            };
#endif

            try
            {
                var assembly = Assembly.Load(new AssemblyName(Constants.BootstrapperHostName));

                // Loader impl
                // The following code is doing:
                // var loaderContainer = new kre.host.LoaderContainer();
                // var cachedAssemblyLoader = new kre.host.CachedAssemblyLoader(_assemblyCache);
                // var libLoader = new kre.host.PathBasedAssemblyLoader(searchPaths);
                // loaderContainer.AddLoader(cachedAssemblyLoader);
                // loaderContainer.AddLoader(libLoader);
                // var bootstrapper = new kre.host.Bootstrapper(loaderContainer);
                // bootstrapper.Main(bootstrapperArgs);

                var loaderContainerType      = assembly.GetType(Constants.BootstrapperHostName + ".LoaderContainer");
                var cachedAssemblyLoaderType = assembly.GetType(Constants.BootstrapperHostName + ".CachedAssemblyLoader");
                var pathBasedLoaderType      = assembly.GetType(Constants.BootstrapperHostName + ".PathBasedAssemblyLoader");

                var loaderContainer      = Activator.CreateInstance(loaderContainerType);
                var cachedAssemblyLoader = Activator.CreateInstance(cachedAssemblyLoaderType, new object[] { _assemblyCache });
                var libLoader            = Activator.CreateInstance(pathBasedLoaderType, new object[] { searchPaths });

                MethodInfo addLoaderMethodInfo = loaderContainerType.GetTypeInfo().GetDeclaredMethod("AddLoader");
                var        disposable1         = (IDisposable)addLoaderMethodInfo.Invoke(loaderContainer, new[] { cachedAssemblyLoader });
                var        disposable2         = (IDisposable)addLoaderMethodInfo.Invoke(loaderContainer, new[] { libLoader });

                var disposable = new CombinedDisposable(disposable1, disposable2);

                var loaderContainerLoadMethodInfo = loaderContainerType.GetTypeInfo().GetDeclaredMethod("Load");

                loader = (Func <string, Assembly>)loaderContainerLoadMethodInfo.CreateDelegate(typeof(Func <string, Assembly>), loaderContainer);

                var bootstrapperType = assembly.GetType(Constants.BootstrapperHostName + ".Bootstrapper");
                var mainMethod       = bootstrapperType.GetTypeInfo().GetDeclaredMethod("Main");
                var bootstrapper     = Activator.CreateInstance(bootstrapperType, loaderContainer);

                try
                {
                    var bootstrapperArgs = new object[]
                    {
                        app.RemainingArguments.ToArray()
                    };

                    var task = (Task <int>)mainMethod.Invoke(bootstrapper, bootstrapperArgs);

                    return(task.ContinueWith(async(t, state) =>
                    {
                        // Dispose the host
                        ((IDisposable)state).Dispose();

#if ASPNET50
                        AppDomain.CurrentDomain.AssemblyResolve -= handler;
#endif
                        return await t;
                    },
                                             disposable).Unwrap());
                }
                catch
                {
                    // If we throw synchronously then dispose then rethtrow
                    disposable.Dispose();
                    throw;
                }
            }
            catch
            {
#if ASPNET50
                AppDomain.CurrentDomain.AssemblyResolve -= handler;
#endif
                throw;
            }
        }
Example #2
0
        public static Task <int> ExecuteAsync(string[] args)
        {
            var enableTrace = Environment.GetEnvironmentVariable("KRE_TRACE") == "1";

#if ASPNET50
            // TODO: Make this pluggable and not limited to the console logger
            if (enableTrace)
            {
                var listener = new ConsoleTraceListener();
                Trace.Listeners.Add(listener);
                Trace.AutoFlush = true;
            }
#endif
            var app = new CommandLineApplication(throwOnUnexpectedArg: false);
            app.Name = "klr";
            var optionLib = app.Option("--lib <LIB_PATHS>", "Paths used for library look-up",
                                       CommandOptionType.MultipleValue);
            app.HelpOption("-?|-h|--help");
            app.VersionOption("--version", GetVersion());
            app.Execute(args);

            // Help information was already shown because help option was specified
            if (app.IsShowingInformation)
            {
                return(Task.FromResult(0));
            }

            // Show help information if no subcommand/option was specified
            if (!app.IsShowingInformation && !app.RemainingArguments.Any())
            {
                app.ShowHelp();
                return(Task.FromResult(2));
            }

            // Resolve the lib paths
            string[] searchPaths = ResolveSearchPaths(optionLib.Values, app.RemainingArguments);

            Func <string, Assembly> loader     = _ => null;
            Func <Stream, Assembly> loadStream = _ => null;
            Func <string, Assembly> loadFile   = _ => null;

            Func <AssemblyName, Assembly> loaderCallback = assemblyName =>
            {
                string name = assemblyName.Name;

                // Skip resource assemblies
                if (name.EndsWith(".resources"))
                {
                    return(null);
                }

                // If the assembly was already loaded use it
                Assembly assembly;
                if (_assemblyCache.TryGetValue(name, out assembly))
                {
                    return(assembly);
                }

                var loadLock = _assemblyLoadLocks.GetOrAdd(name, new object());
                try
                {
                    // Concurrently loading the assembly might result in two distinct instances of the same assembly
                    // being loaded. This was observed when loading via Assembly.LoadStream. Prevent this by locking on the name.
                    lock (loadLock)
                    {
                        if (_assemblyCache.TryGetValue(name, out assembly))
                        {
                            // This would succeed in case the thread was previously waiting on the lock when assembly
                            // load was in progress
                            return(assembly);
                        }

                        assembly = loader(name) ?? ResolveHostAssembly(loadFile, searchPaths, name);

                        if (assembly != null)
                        {
#if ASPNETCORE50
                            ExtractAssemblyNeutralInterfaces(assembly, loadStream);
#endif
                            _assemblyCache[name] = assembly;
                        }
                    }
                }
                finally
                {
                    _assemblyLoadLocks.TryRemove(name, out loadLock);
                }

                return(assembly);
            };
#if ASPNETCORE50
            var loaderImpl = new DelegateAssemblyLoadContext(loaderCallback);
            loadStream = assemblyStream => loaderImpl.LoadStream(assemblyStream, assemblySymbols: null);
            loadFile   = path => loaderImpl.LoadFile(path);

            AssemblyLoadContext.InitializeDefaultContext(loaderImpl);

            if (loaderImpl.EnableMultiCoreJit())
            {
                loaderImpl.StartMultiCoreJitProfile("startup.prof");
            }
#else
            var loaderImpl = new LoaderEngine();
            loadStream = assemblyStream => loaderImpl.LoadStream(assemblyStream, assemblySymbols: null);
            loadFile   = path => loaderImpl.LoadFile(path);

            ResolveEventHandler handler = (sender, a) =>
            {
                // Special case for retargetable assemblies on desktop
                if (a.Name.EndsWith("Retargetable=Yes"))
                {
                    return(Assembly.Load(a.Name));
                }

                return(loaderCallback(new AssemblyName(a.Name)));
            };

            AppDomain.CurrentDomain.AssemblyResolve += handler;
            AppDomain.CurrentDomain.AssemblyLoad    += (object sender, AssemblyLoadEventArgs loadedArgs) =>
            {
                // Skip loading interfaces for dynamic assemblies
                if (loadedArgs.LoadedAssembly.IsDynamic)
                {
                    return;
                }

                ExtractAssemblyNeutralInterfaces(loadedArgs.LoadedAssembly, loadStream);
            };
#endif

            try
            {
                var assembly = Assembly.Load(new AssemblyName("klr.host"));

                // Loader impl
                // The following code is doing:
                // var loaderContainer = new klr.host.LoaderContainer();
                // var assemblyNeutralInterfaceCache = new klr.host.AssemblyNeutralInterfaceCache(_assemblyNeutralInterfaces);
                // var cachedAssemblyLoader = new klr.host.CachedAssemblyLoader(_assemblyCache);
                // var libLoader = new klr.host.PathBasedAssemblyLoader(searchPaths);
                // loaderContainer.AddLoader(cachedAssemblyLoader);
                // loaderContainer.AddLoader(libLoader);
                // var bootstrapper = new klr.host.Bootstrapper(loaderContainer, assemblyNeutralInterfaceCache);
                // bootstrapper.Main(bootstrapperArgs);

                var loaderContainerType = assembly.GetType("klr.host.LoaderContainer");
                var assemblyNeutralInterfaceCacheType = assembly.GetType("klr.host.AssemblyNeutralInterfaceCache");
                var cachedAssemblyLoaderType          = assembly.GetType("klr.host.CachedAssemblyLoader");
                var pathBasedLoaderType = assembly.GetType("klr.host.PathBasedAssemblyLoader");

                var loaderContainer = Activator.CreateInstance(loaderContainerType);
                var assemblyNeutralInterfaceCache = Activator.CreateInstance(assemblyNeutralInterfaceCacheType, new object[] { _assemblyNeutralInterfaces });
                var cachedAssemblyLoader          = Activator.CreateInstance(cachedAssemblyLoaderType, new object[] { _assemblyCache });
                var libLoader = Activator.CreateInstance(pathBasedLoaderType, new object[] { searchPaths });

                MethodInfo addLoaderMethodInfo = loaderContainerType.GetTypeInfo().GetDeclaredMethod("AddLoader");
                var        disposable1         = (IDisposable)addLoaderMethodInfo.Invoke(loaderContainer, new[] { cachedAssemblyLoader });
                var        disposable2         = (IDisposable)addLoaderMethodInfo.Invoke(loaderContainer, new[] { libLoader });

                var disposable = new CombinedDisposable(disposable1, disposable2);

                var loaderContainerLoadMethodInfo = loaderContainerType.GetTypeInfo().GetDeclaredMethod("Load");

                loader = (Func <string, Assembly>)loaderContainerLoadMethodInfo.CreateDelegate(typeof(Func <string, Assembly>), loaderContainer);

                var bootstrapperType = assembly.GetType("klr.host.Bootstrapper");
                var mainMethod       = bootstrapperType.GetTypeInfo().GetDeclaredMethod("Main");
                var bootstrapper     = Activator.CreateInstance(bootstrapperType, loaderContainer, assemblyNeutralInterfaceCache);

                try
                {
                    var bootstrapperArgs = new object[]
                    {
                        app.RemainingArguments.ToArray()
                    };

                    var task = (Task <int>)mainMethod.Invoke(bootstrapper, bootstrapperArgs);

                    return(task.ContinueWith(async(t, state) =>
                    {
                        // Dispose the host
                        ((IDisposable)state).Dispose();

#if ASPNET50
                        AppDomain.CurrentDomain.AssemblyResolve -= handler;
#endif
                        return await t;
                    },
                                             disposable).Unwrap());
                }
                catch
                {
                    // If we throw synchronously then dispose then rethtrow
                    disposable.Dispose();
                    throw;
                }
            }
            catch
            {
#if ASPNET50
                AppDomain.CurrentDomain.AssemblyResolve -= handler;
#endif
                throw;
            }
        }
Example #3
0
        public static Task<int> ExecuteAsync(string[] args)
        {
            var enableTrace = Environment.GetEnvironmentVariable(EnvironmentNames.Trace) == "1";
            #if ASPNET50
            // TODO: Make this pluggable and not limited to the console logger
            if (enableTrace)
            {
                var listener = new ConsoleTraceListener();
                Trace.Listeners.Add(listener);
                Trace.AutoFlush = true;
            }
            #endif
            var app = new CommandLineApplication(throwOnUnexpectedArg: false);
            app.Name = Constants.BootstrapperExeName;

            // RuntimeBootstrapper doesn't need to consume '--appbase' option because
            // klr/klr.cpp consumes the option value before invoking RuntimeBootstrapper
            // This is only for showing help info and swallowing useless '--appbase' option
            var optionAppbase = app.Option("--appbase <PATH>", "Application base directory path",
                CommandOptionType.SingleValue);
            var optionLib = app.Option("--lib <LIB_PATHS>", "Paths used for library look-up",
                CommandOptionType.MultipleValue);
            app.HelpOption("-?|-h|--help");
            app.VersionOption("--version", GetVersion());

            // Options below are only for help info display
            // They will be forwarded to Microsoft.Framework.ApplicationHost
            var optionsToForward = new[]
            {
                app.Option("--watch", "Watch file changes", CommandOptionType.NoValue),
                app.Option("--packages <PACKAGE_DIR>", "Directory containing packages", CommandOptionType.SingleValue),
                app.Option("--configuration <CONFIGURATION>", "The configuration to run under", CommandOptionType.SingleValue),
                app.Option("--port <PORT>", "The port to the compilation server", CommandOptionType.SingleValue)
            };

            app.Execute(args);

            // Help information was already shown because help option was specified
            if (app.IsShowingInformation)
            {
                return Task.FromResult(0);
            }

            // Show help information if no subcommand/option was specified
            if (!app.IsShowingInformation && !app.RemainingArguments.Any())
            {
                app.ShowHelp();
                return Task.FromResult(2);
            }

            // Some options should be forwarded to Microsoft.Framework.ApplicationHost
            var appHostName = "Microsoft.Framework.ApplicationHost";
            var appHostIndex = app.RemainingArguments.FindIndex(s =>
                string.Equals(s, appHostName, StringComparison.OrdinalIgnoreCase));
            foreach (var option in optionsToForward)
            {
                if (option.HasValue())
                {
                    if (appHostIndex < 0)
                    {
                        Console.WriteLine("The option '--{0}' can only be used with {1}", option.LongName, appHostName);
                        return Task.FromResult(1);
                    }

                    if (option.OptionType == CommandOptionType.NoValue)
                    {
                        app.RemainingArguments.Insert(appHostIndex + 1, "--" + option.LongName);
                    }
                    else if (option.OptionType == CommandOptionType.SingleValue)
                    {
                        app.RemainingArguments.Insert(appHostIndex + 1, "--" + option.LongName);
                        app.RemainingArguments.Insert(appHostIndex + 2, option.Value());
                    }
                    else if (option.OptionType == CommandOptionType.MultipleValue)
                    {
                        foreach (var value in option.Values)
                        {
                            app.RemainingArguments.Insert(appHostIndex + 1, "--" + option.LongName);
                            app.RemainingArguments.Insert(appHostIndex + 2, value);
                        }
                    }
                }
            }

            // Resolve the lib paths
            string[] searchPaths = ResolveSearchPaths(optionLib.Values, app.RemainingArguments);

            Func<string, Assembly> loader = _ => null;
            Func<Stream, Assembly> loadStream = _ => null;
            Func<string, Assembly> loadFile = _ => null;

            Func<AssemblyName, Assembly> loaderCallback = assemblyName =>
            {
                string name = assemblyName.Name;

                // Skip resource assemblies
                if (name.EndsWith(".resources"))
                {
                    return null;
                }

                // If the assembly was already loaded use it
                Assembly assembly;
                if (_assemblyCache.TryGetValue(name, out assembly))
                {
                    return assembly;
                }

                var loadLock = _assemblyLoadLocks.GetOrAdd(name, new object());
                try
                {
                    // Concurrently loading the assembly might result in two distinct instances of the same assembly
                    // being loaded. This was observed when loading via Assembly.LoadStream. Prevent this by locking on the name.
                    lock (loadLock)
                    {
                        if (_assemblyCache.TryGetValue(name, out assembly))
                        {
                            // This would succeed in case the thread was previously waiting on the lock when assembly
                            // load was in progress
                            return assembly;
                        }

                        assembly = loader(name) ?? ResolveHostAssembly(loadFile, searchPaths, name);

                        if (assembly != null)
                        {
            #if ASPNETCORE50
                            ExtractAssemblyNeutralInterfaces(assembly, loadStream);
            #endif
                            _assemblyCache[name] = assembly;
                        }
                    }
                }
                finally
                {
                    _assemblyLoadLocks.TryRemove(name, out loadLock);
                }

                return assembly;
            };
            #if ASPNETCORE50
            var loaderImpl = new DelegateAssemblyLoadContext(loaderCallback);
            loadStream = assemblyStream => loaderImpl.LoadStream(assemblyStream, assemblySymbols: null);
            loadFile = path => loaderImpl.LoadFile(path);

            AssemblyLoadContext.InitializeDefaultContext(loaderImpl);

            if (loaderImpl.EnableMultiCoreJit())
            {
                loaderImpl.StartMultiCoreJitProfile("startup.prof");
            }
            #else
            var loaderImpl = new LoaderEngine();
            loadStream = assemblyStream => loaderImpl.LoadStream(assemblyStream, assemblySymbols: null);
            loadFile = path => loaderImpl.LoadFile(path);

            ResolveEventHandler handler = (sender, a) =>
            {
                var appDomain = (AppDomain)sender;
                var afterPolicy = appDomain.ApplyPolicy(a.Name);
                if (afterPolicy != a.Name)
                {
                    return Assembly.Load(afterPolicy);
                }

                return loaderCallback(new AssemblyName(afterPolicy));
            };

            AppDomain.CurrentDomain.AssemblyResolve += handler;
            AppDomain.CurrentDomain.AssemblyLoad += (object sender, AssemblyLoadEventArgs loadedArgs) =>
            {
                // Skip loading interfaces for dynamic assemblies
                if (loadedArgs.LoadedAssembly.IsDynamic)
                {
                    return;
                }

                ExtractAssemblyNeutralInterfaces(loadedArgs.LoadedAssembly, loadStream);
            };
            #endif

            try
            {
                var assembly = Assembly.Load(new AssemblyName(Constants.BootstrapperHostName));

                // Loader impl
                // The following code is doing:
                // var loaderContainer = new kre.host.LoaderContainer();
                // var cachedAssemblyLoader = new kre.host.CachedAssemblyLoader(_assemblyCache);
                // var libLoader = new kre.host.PathBasedAssemblyLoader(searchPaths);
                // loaderContainer.AddLoader(cachedAssemblyLoader);
                // loaderContainer.AddLoader(libLoader);
                // var bootstrapper = new kre.host.Bootstrapper(loaderContainer);
                // bootstrapper.Main(bootstrapperArgs);

                var loaderContainerType = assembly.GetType(Constants.BootstrapperHostName + ".LoaderContainer");
                var cachedAssemblyLoaderType = assembly.GetType(Constants.BootstrapperHostName + ".CachedAssemblyLoader");
                var pathBasedLoaderType = assembly.GetType(Constants.BootstrapperHostName + ".PathBasedAssemblyLoader");

                var loaderContainer = Activator.CreateInstance(loaderContainerType);
                var cachedAssemblyLoader = Activator.CreateInstance(cachedAssemblyLoaderType, new object[] { _assemblyCache });
                var libLoader = Activator.CreateInstance(pathBasedLoaderType, new object[] { searchPaths });

                MethodInfo addLoaderMethodInfo = loaderContainerType.GetTypeInfo().GetDeclaredMethod("AddLoader");
                var disposable1 = (IDisposable)addLoaderMethodInfo.Invoke(loaderContainer, new[] { cachedAssemblyLoader });
                var disposable2 = (IDisposable)addLoaderMethodInfo.Invoke(loaderContainer, new[] { libLoader });

                var disposable = new CombinedDisposable(disposable1, disposable2);

                var loaderContainerLoadMethodInfo = loaderContainerType.GetTypeInfo().GetDeclaredMethod("Load");

                loader = (Func<string, Assembly>)loaderContainerLoadMethodInfo.CreateDelegate(typeof(Func<string, Assembly>), loaderContainer);

                var bootstrapperType = assembly.GetType(Constants.BootstrapperHostName + ".Bootstrapper");
                var mainMethod = bootstrapperType.GetTypeInfo().GetDeclaredMethod("Main");
                var bootstrapper = Activator.CreateInstance(bootstrapperType, loaderContainer);

                try
                {
                    var bootstrapperArgs = new object[]
                    {
                        app.RemainingArguments.ToArray()
                    };

                    var task = (Task<int>)mainMethod.Invoke(bootstrapper, bootstrapperArgs);

                    return task.ContinueWith(async (t, state) =>
                    {
                        // Dispose the host
                        ((IDisposable)state).Dispose();

            #if ASPNET50
                        AppDomain.CurrentDomain.AssemblyResolve -= handler;
            #endif
                        return await t;
                    },
                    disposable).Unwrap();
                }
                catch
                {
                    // If we throw synchronously then dispose then rethtrow
                    disposable.Dispose();
                    throw;
                }
            }
            catch
            {
            #if ASPNET50
                AppDomain.CurrentDomain.AssemblyResolve -= handler;
            #endif
                throw;
            }
        }