'Can't read types from assembly using Entity Framework Core 5.0

I am trying to read the types out of an assembly that contains Entity Framework Core, but I am getting this error:

Could not load file or assembly '..file path..\TestRoslyn\Database\bin\Debug\net5.0\Database.dll'. The system cannot find the file specified.

The code I am using to read the types is pretty simple:

using System;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.Build.Locator;
using Microsoft.CodeAnalysis.MSBuild;

namespace TestRoslyn
{
    class Program
    {
        static async Task Main(string[] args)
        {
            if (!MSBuildLocator.IsRegistered) 
                 MSBuildLocator.RegisterDefaults();

            using var w = MSBuildWorkspace.Create();

            // Substitute your file location
            var basePath = @"C:\Users\username\source\repos\";
            var slnFile = @$"{basePath}TestRoslyn\TestRoslyn.sln";
            var sln = await w.OpenSolutionAsync(slnFile);

            foreach (var p in sln.Projects)
            {
                var asm = Assembly.LoadFrom(p.OutputFilePath);
                foreach(var t in asm.GetTypes())
                    Console.WriteLine($"{p.OutputFilePath}\t{t.FullName}");
            }
        }
    }
}

This works as is. However, when I add a simple project to the solution that references nuget package Microsoft.EntityFrameworkCore (5.0) with one file:

using Microsoft.EntityFrameworkCore;

namespace Database
{
    public class AppContext: DbContext
    {
    }
}

(To keep it simple, I didn't include anything in the AppContext class except the base class.)

When I add a project with the EntityFrameworkCore nuget package to the solution above with just this class I get the error indicated above.

Not sure what the cause is? Do I need to somehow load the nuget package into the workspace? If so, how?



Solution 1:[1]

Use AssemblyDependencyResolver and custom AssemblyLoadContext (from System.Runtime.Loader) to help load assemblies with dependencies.

Here is the custom AssemblyLoadContext, allowing to resolve dependencies:

using System;
using System.Reflection;
using System.Runtime.Loader;

namespace TestRoslyn
{
    public class LoadContext : AssemblyLoadContext
    {
        private AssemblyDependencyResolver _resolver;

        public LoadContext(string assemblyPath)
        {
            _resolver = new AssemblyDependencyResolver(assemblyPath);
        }

        protected override Assembly Load(AssemblyName assemblyName)
        {
            string assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
            if (assemblyPath != null)
            {
                return LoadFromAssemblyPath(assemblyPath);
            }

            return null;
        }

        protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
        {
            string libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName);
            if (libraryPath != null)
            {
                return LoadUnmanagedDllFromPath(libraryPath);
            }

            return IntPtr.Zero;
        }
    }
}

It can be used like this:

foreach (var p in sln.Projects)
{
    string outputPath = p.OutputFilePath;
    AssemblyName assemblyName = AssemblyName.GetAssemblyName(outputPath);
    LoadContext loadContext = new LoadContext(outputPath);
    Assembly asm = loadContext.LoadFromAssemblyName(assemblyName);
    
    foreach (var t in asm.GetTypes()) 
        Console.WriteLine($"{p.OutputFilePath}\t{t.FullName}");
}

See details here and here.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Ruslan Gilmutdinov