无法使用 Entity Framework Core 5.0 从程序集中读取类型

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

我正在尝试从包含 Entity Framework 核心的程序集中读取类型,但出现此错误:

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

我用来读取类型的代码非常简单:

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}");
            }
        }
    }
}

这按原样工作。但是,当我将一个简单的项目添加到使用一个文件引用 nuget 包 Microsoft.EntityFrameworkCore (5.0) 的解决方案时:

using Microsoft.EntityFrameworkCore;

namespace Database
{
    public class AppContext: DbContext
    {
    }
}

(为了简单起见,除了基础 class 之外,我没有在 AppContext class 中包含任何内容。)

当我将带有 EntityFrameworkCore nuget 包的项目添加到上面的解决方案时 class 我得到上面指出的错误。

不确定是什么原因?我是否需要以某种方式将 nuget 包加载到工作区中?如果是,怎么做?

使用 AssemblyDependencyResolver 和自定义 AssemblyLoadContext(来自 System.Runtime.Loader)来帮助加载具有依赖项的程序集。

这里是自定义 AssemblyLoadContext,允许解析依赖项:

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;
        }
    }
}

可以这样使用:

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}");
}

查看详情here and here