diff --git a/TechTalk.SpecFlow.Generator/Plugins/GeneratorPluginLoader.cs b/TechTalk.SpecFlow.Generator/Plugins/GeneratorPluginLoader.cs index 31108f3c9..8f0bad18b 100644 --- a/TechTalk.SpecFlow.Generator/Plugins/GeneratorPluginLoader.cs +++ b/TechTalk.SpecFlow.Generator/Plugins/GeneratorPluginLoader.cs @@ -8,7 +8,6 @@ namespace TechTalk.SpecFlow.Generator.Plugins { public class GeneratorPluginLoader : IGeneratorPluginLoader { - public IGeneratorPlugin LoadPlugin(PluginDescriptor pluginDescriptor) { Assembly pluginAssembly; @@ -17,7 +16,7 @@ public IGeneratorPlugin LoadPlugin(PluginDescriptor pluginDescriptor) #if NETCOREAPP var absolutePath = Path.GetFullPath(pluginDescriptor.Path); - pluginAssembly = System.Runtime.Loader.AssemblyLoadContext.GetLoadContext(typeof(GeneratorPluginLoader).Assembly).LoadFromAssemblyPath(absolutePath); + pluginAssembly = PluginAssemblyResolver.Load(absolutePath); #else pluginAssembly = Assembly.LoadFrom(pluginDescriptor.Path); #endif diff --git a/TechTalk.SpecFlow.Generator/Plugins/PluginAssemblyResolver.cs b/TechTalk.SpecFlow.Generator/Plugins/PluginAssemblyResolver.cs new file mode 100644 index 000000000..3b6518e16 --- /dev/null +++ b/TechTalk.SpecFlow.Generator/Plugins/PluginAssemblyResolver.cs @@ -0,0 +1,79 @@ +#if NETCOREAPP + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.Loader; +using Microsoft.Extensions.DependencyModel; +using Microsoft.Extensions.DependencyModel.Resolution; + +namespace TechTalk.SpecFlow.Generator.Plugins +{ + internal sealed class PluginAssemblyResolver + { + private readonly ICompilationAssemblyResolver _assemblyResolver; + private readonly DependencyContext _dependencyContext; + private readonly AssemblyLoadContext _loadContext; + + public Assembly Assembly { get; } + + public PluginAssemblyResolver(string path) + { + _loadContext = AssemblyLoadContext.GetLoadContext(typeof(PluginAssemblyResolver).Assembly); + Assembly = _loadContext.LoadFromAssemblyPath(path); + _dependencyContext = DependencyContext.Load(Assembly); + + _assemblyResolver = new CompositeCompilationAssemblyResolver(new ICompilationAssemblyResolver[] + { + new AppBaseCompilationAssemblyResolver(Path.GetDirectoryName(path)), + new ReferenceAssemblyPathResolver(), + new PackageCompilationAssemblyResolver() + }); + + _loadContext.Resolving += OnResolving; + _loadContext.Unloading += OnUnloading; + } + + private void OnUnloading(AssemblyLoadContext context) + { + _loadContext.Resolving -= OnResolving; + _loadContext.Unloading -= OnUnloading; + } + + private Assembly OnResolving(AssemblyLoadContext context, AssemblyName name) + { + var library = _dependencyContext.RuntimeLibraries.FirstOrDefault( + runtimeLibrary => string.Equals(runtimeLibrary.Name, name.Name, StringComparison.OrdinalIgnoreCase)); + + if (library != null) + { + var wrapper = new CompilationLibrary( + library.Type, + library.Name, + library.Version, + library.Hash, + library.RuntimeAssemblyGroups.SelectMany(g => g.AssetPaths), + library.Dependencies, + library.Serviceable); + + var assemblies = new List(); + _assemblyResolver.TryResolveAssemblyPaths(wrapper, assemblies); + + if (assemblies.Count > 0) + { + return _loadContext.LoadFromAssemblyPath(assemblies[0]); + } + } + + return null; + } + + public static Assembly Load(string absolutePath) + { + return new PluginAssemblyResolver(absolutePath).Assembly; + } + } +} +#endif diff --git a/TechTalk.SpecFlow.Generator/TechTalk.SpecFlow.Generator.csproj b/TechTalk.SpecFlow.Generator/TechTalk.SpecFlow.Generator.csproj index 464e098fa..4b5e87f87 100644 --- a/TechTalk.SpecFlow.Generator/TechTalk.SpecFlow.Generator.csproj +++ b/TechTalk.SpecFlow.Generator/TechTalk.SpecFlow.Generator.csproj @@ -47,6 +47,7 @@ + diff --git a/changelog.txt b/changelog.txt index a0171348a..a1cce9dbd 100644 --- a/changelog.txt +++ b/changelog.txt @@ -25,6 +25,7 @@ Changes: Fixes: + Empty value for nullable enum should not throw an exception + RegEx performance fix in TEHelpers (Table column name validation) ++ Use AssemblyLoadContext for loading the generator plugin in case of netcoreapp Fixes: