private static AssemblyLoadContext CreateLoadContext( string baseDir, PluginConfig config, Type[] sharedTypes) { var depsJsonFile = Path.Combine(baseDir, config.MainAssembly.Name + ".deps.json"); var builder = new AssemblyLoadContextBuilder(); if (File.Exists(depsJsonFile)) { builder.AddDependencyContext(depsJsonFile); } builder.SetBaseDirectory(baseDir); foreach (var ext in config.PrivateAssemblies) { builder.PreferLoadContextAssembly(ext); } if (sharedTypes != null) { foreach (var type in sharedTypes) { builder.PreferDefaultLoadContextAssembly(type.Assembly.GetName()); } } var runtimeConfigFile = Path.Combine(baseDir, config.MainAssembly.Name + ".runtimeconfig.json"); builder.TryAddAdditionalProbingPathFromRuntimeConfig(runtimeConfigFile, includeDevConfig: true, out _); return(builder.Build()); }
private static AssemblyLoadContext CreateLoadContext(string assemblyPath, Core.ILogger logger = null) { var validatedPath = ValidateFilePath(assemblyPath, logger); if (validatedPath == null) { return(null); } var mainAssemblyName = Path.GetFileNameWithoutExtension(validatedPath); var builder = new AssemblyLoadContextBuilder(); // Set base directory. var baseDir = Path.GetDirectoryName(validatedPath); builder.SetBaseDirectory(baseDir); logger?.LogTrace($"Base directory: '{baseDir}'"); // Add deps file as a source for finding dependencies. var depsJsonFile = Path.Combine(baseDir, $"{mainAssemblyName}.deps.json"); if (File.Exists(depsJsonFile)) { builder.AddDependencyContext(depsJsonFile); logger?.LogTrace($"Added '{depsJsonFile}' as a deps file dependency"); } // Add runtimeconfig file as a source for finding dependencies. var pluginRuntimeConfigFile = Path.Combine(baseDir, $"{mainAssemblyName}.runtimeconfig.json"); builder.TryAddAdditionalProbingPathFromRuntimeConfig(pluginRuntimeConfigFile, includeDevConfig: true, out _); return(builder.Build()); }
/// <summary> /// Creates a new <see cref="LoadContext"/> for individual mods/plugins. /// </summary> public static LoadContext BuildModLoadContext(string assemblyPath, bool isUnloadable, Type[] sharedTypes, AssemblyLoadContext defaultContext = null) { var builder = new AssemblyLoadContextBuilder() .SetMainAssemblyPath(assemblyPath) .IsLazyLoaded(true); if (defaultContext != null) { builder.SetDefaultContext(defaultContext); } if (isUnloadable) { builder.EnableUnloading(); } foreach (var type in sharedTypes) { builder.PreferDefaultLoadContextAssembly(type.Assembly.GetName()); } var context = builder.Build(); return(new LoadContext(context, assemblyPath)); }
private static AssemblyLoadContext CreateLoadContext(PluginConfig config) { var builder = new AssemblyLoadContextBuilder(); builder.SetMainAssemblyPath(config.MainAssemblyPath); foreach (var ext in config.PrivateAssemblies) { builder.PreferLoadContextAssembly(ext); } if (config.PreferSharedTypes) { builder.PreferDefaultLoadContext(true); } if (config.IsUnloadable) { builder.EnableUnloading(); } foreach (var assemblyName in config.SharedAssemblies) { builder.PreferDefaultLoadContextAssembly(assemblyName); } builder.SetupSharedAssemblyPrefix(config.SharedAssemblyPrefixes); return(builder.Build()); }
private static AssemblyLoadContextBuilder CreateLoadContextBuilder(PluginConfig config) { var builder = new AssemblyLoadContextBuilder(); builder.SetMainAssemblyPath(config.MainAssemblyPath); foreach (var ext in config.PrivateAssemblies) { builder.PreferLoadContextAssembly(ext); } if (config.PreferSharedTypes) { builder.PreferDefaultLoadContext(true); } #if FEATURE_UNLOAD if (config.IsUnloadable || config.EnableHotReload) { builder.EnableUnloading(); } if (config.EnableHotReload) { builder.PreloadAssembliesIntoMemory(); } #endif foreach (var assemblyName in config.SharedAssemblies) { builder.PreferDefaultLoadContextAssembly(assemblyName); } #if !FEATURE_NATIVE_RESOLVER // In .NET Core 3.0, this code is unnecessary because the API, AssemblyDependencyResolver, handles parsing these files. var baseDir = Path.GetDirectoryName(config.MainAssemblyPath); var assemblyFileName = Path.GetFileNameWithoutExtension(config.MainAssemblyPath); var depsJsonFile = Path.Combine(baseDir, assemblyFileName + ".deps.json"); if (File.Exists(depsJsonFile)) { builder.AddDependencyContext(depsJsonFile); } var pluginRuntimeConfigFile = Path.Combine(baseDir, assemblyFileName + ".runtimeconfig.json"); builder.TryAddAdditionalProbingPathFromRuntimeConfig(pluginRuntimeConfigFile, includeDevConfig: true, out _); // Always include runtimeconfig.json from the host app. // in some cases, like `dotnet test`, the entry assembly does not actually match with the // runtime config file which is why we search for all files matching this extensions. foreach (var runtimeconfig in Directory.GetFiles(AppContext.BaseDirectory, "*.runtimeconfig.json")) { builder.TryAddAdditionalProbingPathFromRuntimeConfig(runtimeconfig, includeDevConfig: true, out _); } #endif return(builder); }
private static AssemblyLoadContextBuilder CreateLoadContextBuilder(PluginConfig config) { var builder = new AssemblyLoadContextBuilder(); builder.SetMainAssemblyPath(config.MainAssemblyPath); builder.SetDefaultContext(config.DefaultContext); foreach (var ext in config.PrivateAssemblies) { builder.PreferLoadContextAssembly(ext); } if (config.PreferSharedTypes) { builder.PreferDefaultLoadContext(true); } if (config.IsUnloadable || config.EnableHotReload) { builder.EnableUnloading(); } if (config.LoadInMemory) { builder.PreloadAssembliesIntoMemory(); builder.ShadowCopyNativeLibraries(); } builder.IsLazyLoaded(config.IsLazyLoaded); foreach (var assemblyName in config.SharedAssemblies) { builder.PreferDefaultLoadContextAssembly(assemblyName); } var baseDir = Path.GetDirectoryName(config.MainAssemblyPath); var assemblyFileName = Path.GetFileNameWithoutExtension(config.MainAssemblyPath); if (baseDir == null) { throw new InvalidOperationException("Could not determine which directory to watch. " + "Please set MainAssemblyPath to an absolute path so its parent directory can be discovered."); } var pluginRuntimeConfigFile = Path.Combine(baseDir, assemblyFileName + ".runtimeconfig.json"); builder.TryAddAdditionalProbingPathFromRuntimeConfig(pluginRuntimeConfigFile, includeDevConfig: true, out _); // Always include runtimeconfig.json from the host app. // in some cases, like `dotnet test`, the entry assembly does not actually match with the // runtime config file which is why we search for all files matching this extensions. foreach (var runtimeconfig in Directory.GetFiles(AppContext.BaseDirectory, "*.runtimeconfig.json")) { builder.TryAddAdditionalProbingPathFromRuntimeConfig(runtimeconfig, includeDevConfig: true, out _); } return(builder); }
private static AssemblyLoadContext CreateLoadContext( string baseDir, PluginConfig config, Type[] sharedTypes, PluginLoaderOptions loaderOptions) { var depsJsonFile = Path.Combine(baseDir, config.MainAssembly.Name + ".deps.json"); var builder = new AssemblyLoadContextBuilder(); if (File.Exists(depsJsonFile)) { builder.AddDependencyContext(depsJsonFile); } builder.SetBaseDirectory(baseDir); foreach (var ext in config.PrivateAssemblies) { builder.PreferLoadContextAssembly(ext); } if (loaderOptions.HasFlag(PluginLoaderOptions.PreferSharedTypes)) { builder.PreferDefaultLoadContext(true); } #if FEATURE_UNLOAD if (loaderOptions.HasFlag(PluginLoaderOptions.IsUnloadable)) { builder.EnableUnloading(); } #endif if (sharedTypes != null) { foreach (var type in sharedTypes) { builder.PreferDefaultLoadContextAssembly(type.Assembly.GetName()); } } var pluginRuntimeConfigFile = Path.Combine(baseDir, config.MainAssembly.Name + ".runtimeconfig.json"); builder.TryAddAdditionalProbingPathFromRuntimeConfig(pluginRuntimeConfigFile, includeDevConfig: true, out _); // Always include runtimeconfig.json from the host app. // in some cases, like `dotnet test`, the entry assembly does not actually match with the // runtime config file which is why we search for all files matching this extensions. foreach (var runtimeconfig in Directory.GetFiles(AppContext.BaseDirectory, "*.runtimeconfig.json")) { builder.TryAddAdditionalProbingPathFromRuntimeConfig(runtimeconfig, includeDevConfig: true, out _); } return(builder.Build()); }
/// <summary> /// Initialize an instance of <see cref="PluginLoader" /> /// </summary> /// <param name="config">The configuration for the plugin.</param> public PluginLoader(PluginConfig config) { _config = config ?? throw new ArgumentNullException(nameof(config)); _contextBuilder = CreateLoadContextBuilder(config); _context = (ManagedLoadContext)_contextBuilder.Build(); if (config.EnableHotReload) { StartFileWatcher(); } }
public void ItUpgradesTypesInContext() { var samplePath = TestResources.GetTestProjectAssembly("XunitSample"); var context = new AssemblyLoadContextBuilder() .AddProbingPath(samplePath) .AddDependencyContext(Path.Combine(Path.GetDirectoryName(samplePath), "XunitSample.deps.json")) .PreferDefaultLoadContext(true) .Build(); Assert.Same(typeof(TheoryData).Assembly, LoadAssembly(context, "xunit.core")); }
public void ContextsHavePrivateVersionsByDefault() { var samplePath = TestResources.GetTestProjectAssembly("XunitSample"); var context = new AssemblyLoadContextBuilder() .SetMainAssemblyPath(samplePath) .AddProbingPath(samplePath) .Build(); Assert.NotSame(typeof(TheoryData).Assembly, LoadAssembly(context, "xunit.core")); }
public void ItUpgradesTypesInContext() { var samplePath = TestResources.GetTestProjectAssembly("XunitSample"); var context = new AssemblyLoadContextBuilder() .SetMainAssemblyPath(samplePath) .AddProbingPath(samplePath) .PreferDefaultLoadContext(true) .Build(); Assert.Same(typeof(TheoryData).Assembly, LoadAssembly(context, "xunit.core")); }
public void ContextsHavePrivateVersionsByDefault() { var samplePath = TestResources.GetTestProjectAssembly("XunitSample"); var context = new AssemblyLoadContextBuilder() .AddProbingPath(samplePath) .AddDependencyContext(Path.Combine(Path.GetDirectoryName(samplePath), "XunitSample.deps.json")) .Build(); Assert.NotSame(typeof(TheoryData).Assembly, LoadAssembly(context, "xunit.core")); }
/// <summary> /// Initialize an instance of <see cref="PluginLoader" /> /// </summary> /// <param name="config">The configuration for the plugin.</param> public PluginLoader(PluginConfig config) { _config = config ?? throw new ArgumentNullException(nameof(config)); _contextBuilder = CreateLoadContextBuilder(config); _context = _contextBuilder.Build(); #if FEATURE_UNLOAD if (config.EnableHotReload) { StartFileWatcher(); } #endif }
public static AssemblyLoadContextBuilder AddDependencyContextWithCompileDeps(this AssemblyLoadContextBuilder builder, string depsFilePath) { var reader = new DependencyContextJsonReader(); using (var file = File.OpenRead(depsFilePath)) { var deps = reader.Read(file); builder.SetBaseDirectory(Path.GetDirectoryName(depsFilePath)); builder.AddDependencyContext(deps); builder.AddCompileDependencies(deps); } return(builder); }
/// <summary> /// Creates a new empty Shared <see cref="LoadContext"/> used for storing plugin shared interfaces. /// </summary> public static LoadContext BuildSharedLoadContext() { var loaderFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); var interFacesAsmName = typeof(IModLoader).Assembly.GetName(); var interFacesAsmFile = Path.Combine(loaderFolder, $"{interFacesAsmName.Name}.dll"); var builder = new AssemblyLoadContextBuilder() .IsLazyLoaded(true) .PreferDefaultLoadContextAssembly(interFacesAsmName) .SetMainAssemblyPath(interFacesAsmFile); var context = builder.Build(); return(new LoadContext(context, interFacesAsmFile)); }
/// <summary> /// Based on https://github.com/natemcmaster/DotNetCorePlugins/blob/master/src/Plugins/PluginLoader.cs /// </summary> public static AssemblyLoadContext CreateLoadContext(string baseDir, AssemblyName mainAssemblyName, PluginLoaderOptions loaderOptions = PluginLoaderOptions.None, IEnumerable <AssemblyName> preferDefaultLoadContextForAssemblies = null, IEnumerable <AssemblyName> privateAssemblies = null) { var depsJsonFile = Path.Combine(baseDir, mainAssemblyName.Name + ".deps.json"); var builder = new AssemblyLoadContextBuilder(); if (File.Exists(depsJsonFile)) { builder.AddDependencyContextWithCompileDeps(depsJsonFile); } builder.SetBaseDirectory(baseDir); if (privateAssemblies != null) { foreach (var ext in privateAssemblies) { builder.PreferLoadContextAssembly(ext); } } if (loaderOptions.HasFlag(PluginLoaderOptions.PreferSharedTypes)) { builder.PreferDefaultLoadContext(true); } if (preferDefaultLoadContextForAssemblies != null) { foreach (var assemblyName in preferDefaultLoadContextForAssemblies) { builder.PreferDefaultLoadContextAssembly(assemblyName); } } var pluginRuntimeConfigFile = Path.Combine(baseDir, mainAssemblyName.Name + ".runtimeconfig.json"); builder.TryAddAdditionalProbingPathFromRuntimeConfig(pluginRuntimeConfigFile, true, out _); foreach (var runtimeconfig in Directory.GetFiles(AppContext.BaseDirectory, "*.runtimeconfig.json")) { builder.TryAddAdditionalProbingPathFromRuntimeConfig(runtimeconfig, true, out _); } return(builder.Build()); }
public static void AddCompileDependencies(this AssemblyLoadContextBuilder builder, DependencyContext dependencyContext) { foreach (var library in dependencyContext.CompileLibraries.Where(cl => !dependencyContext.RuntimeLibraries.Any(rl => cl.Name.Equals(rl.Name)))) { foreach (var libraryAssembly in library.Assemblies.Where(a => a.StartsWith("lib", StringComparison.OrdinalIgnoreCase))) { var managedLibrary = ManagedLibrary.CreateFromPackage(library.Name, library.Version, libraryAssembly); try { builder.AddManagedLibrary(managedLibrary); } catch (Exception ex) { Console.WriteLine(ex.Message); } } } }
public void ItCanDowngradeUnifiedTypes() { var samplePath = TestResources.GetTestProjectAssembly("NetCoreApp2App"); var defaultLoader = new AssemblyLoadContextBuilder() .SetMainAssemblyPath(samplePath) .AddProbingPath(samplePath) .PreferDefaultLoadContext(false) .Build(); var unifedLoader = new AssemblyLoadContextBuilder() .SetMainAssemblyPath(samplePath) .AddProbingPath(samplePath) .PreferDefaultLoadContext(true) .Build(); Assert.Equal(new Version("2.0.0.0"), LoadAssembly(defaultLoader, "Test.Referenced.Library").GetName().Version); Assert.Equal(new Version("1.0.0.0"), LoadAssembly(unifedLoader, "Test.Referenced.Library").GetName().Version); }
public void ItCanDowngradeUnifiedTypes() { var samplePath = TestResources.GetTestProjectAssembly("NetCoreApp20App"); var defaultLoader = new AssemblyLoadContextBuilder() .AddProbingPath(samplePath) .PreferDefaultLoadContext(false) .AddDependencyContext(Path.Combine(Path.GetDirectoryName(samplePath), "NetCoreApp20App.deps.json")) .Build(); var unifedLoader = new AssemblyLoadContextBuilder() .AddProbingPath(samplePath) .PreferDefaultLoadContext(true) .AddDependencyContext(Path.Combine(Path.GetDirectoryName(samplePath), "NetCoreApp20App.deps.json")) .Build(); Assert.Equal(new Version("2.0.0.0"), LoadAssembly(defaultLoader, "Test.Referenced.Library").GetName().Version); Assert.Equal(new Version("1.0.0.0"), LoadAssembly(unifedLoader, "Test.Referenced.Library").GetName().Version); }
static AssemblyLoadContext GetAssemblyLoadContext(string assemblyPath, string depsPath, bool enableUnloading) { var builder = new AssemblyLoadContextBuilder() .SetMainAssemblyPath(assemblyPath) .PreferDefaultLoadContext(true) .AddDependencyContext(depsPath) .AddProbingPath(Path.GetDirectoryName(assemblyPath)) .PreferDefaultLoadContextAssembly(typeof(IPlatformStartup).Assembly.GetName()) .PreferDefaultLoadContextAssembly(typeof(IServiceCollection).Assembly.GetName()) .PreferDefaultLoadContextAssembly(typeof(IServiceCollectionBusConfigurator).Assembly.GetName()) .PreferDefaultLoadContextAssembly(typeof(ILogger).Assembly.GetName()) .PreferDefaultLoadContextAssembly(typeof(IBus).Assembly.GetName()) .PreferDefaultLoadContextAssembly(typeof(IRabbitMqBusFactoryConfigurator).Assembly.GetName()) .PreferDefaultLoadContextAssembly(typeof(IActiveMqBusFactoryConfigurator).Assembly.GetName()) .PreferDefaultLoadContextAssembly(typeof(IAmazonSqsBusFactoryConfigurator).Assembly.GetName()) .PreferDefaultLoadContextAssembly(typeof(IServiceBusBusFactoryConfigurator).Assembly.GetName()); if (enableUnloading) { builder = builder.EnableUnloading(); } return(builder.Build()); }