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? - Martin Ullrichdotnet publishand then thedirectoryPathvariable points at the published output folder, so all DLL's should be available. - Muhammad Rehan SaeedConfigureServices: one that returns null and one that returnsIServiceProvider. (IStartupwould require the one returningIServiceProvider) - Martin UllrichIStartupthis 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.ExportedTypesvery early on. - Muhammad Rehan Saeed