I am trying to dynamically load a .NET Core DLL containing an ASP.NET Core's Startup
class. I then want to instantiate the Startup
class and hand it over to the TestHost
API, so I can start the site in memory. I've written the following code:
var directoryPath = @"C:\Dlls";
var assemblyFilePath = Path.Combine(directoryPath, "Foo.dll");
var assemblyName = AssemblyLoadContext.GetAssemblyName(assemblyFilePath);
var assembly = new AssemblyLoader(directoryPath).LoadFromAssemblyName(assemblyName);
var startupType = assembly.ExportedTypes
.FirstOrDefault(x => string.Equals(x.Name, "Startup"));
var webHostBuilder = new WebHostBuilder()
.UseStartup(startupType)
.UseUrls(new string[] { "http://localhost" });
using (var testServer = new TestServer(webHostBuilder))
{
var response = testServer.CreateClient().GetAsync("/");
}
public class AssemblyLoader : AssemblyLoadContext
{
private readonly string directoryPath;
public AssemblyLoader(string directoryPath) =>
this.directoryPath = directoryPath;
protected override Assembly Load(AssemblyName assemblyName)
{
var dependencyContext = DependencyContext.Default;
var compilationLibraries = dependencyContext
.CompileLibraries
.Where(x => x.Name.Contains(assemblyName.Name))
.ToList();
if (compilationLibraries.Count > 0)
{
return Assembly.Load(new AssemblyName(compilationLibraries.First().Name));
}
else
{
var file = new FileInfo($"{this.directoryPath}{Path.DirectorySeparatorChar}{assemblyName.Name}.dll");
if (File.Exists(file.FullName))
{
var asemblyLoader = new AssemblyLoader(file.DirectoryName);
return asemblyLoader.LoadFromAssemblyPath(file.FullName);
}
}
return Assembly.Load(assemblyName);
}
}
However, this throws a TypeLoadException
when assembly.ExportedTypes
is called. The full stack trace:
System.TypeLoadException occurred HResult=0x80131522
Message=Method 'ConfigureServices' in type 'Foo.Startup' from assembly 'Foo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' does not have an implementation. Source= StackTrace: at System.Reflection.RuntimeAssembly.GetExportedTypes(RuntimeAssembly assembly, ObjectHandleOnStack retTypes) at System.Reflection.RuntimeAssembly.GetExportedTypes()
I think it's having trouble loading the ASP.NET Core and other third party DLL's like Newtonsoft.Json.
<CopyLocalLockFileAssemblies>true</..>
so all referenced assemblies are put into the same output folder as the dll? – Platusdotnet publish
and then thedirectoryPath
variable points at the published output folder, so all DLL's should be available. – JephthahConfigureServices
: one that returns null and one that returnsIServiceProvider
. (IStartup
would require the one returningIServiceProvider
) – PlatusIStartup
this morning and happened to just make the switch to it today for the extra type safety, so I am using it. That said, the error is occuring inassembly.ExportedTypes
very early on. – Jephthah