You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Assembly.LoadFrom加载自定义DLL时无法加载ASP.NET Core依赖程序集的问题咨询

Assembly.LoadFrom加载自定义DLL时无法加载ASP.NET Core依赖程序集的问题咨询

看起来你遇到了ASP.NET Core共享框架程序集的加载坑,我来给你拆解下原因和可行的解决办法:

首先说为啥会出现这个问题:

  • Assembly.LoadFrom是从你指定的路径加载自定义DLL,但ASP.NET Core那些放在C:\Program Files\dotnet\shared里的程序集属于框架依赖程序集,不是普通的私有程序集。你的侧应用(也就是用来做调查的这个小工具)如果不是标准的ASP.NET Core应用,CLR默认不会自动去共享框架目录里找这些依赖——因为它压根不知道要去那儿找啊!
  • 你的自定义DLL是针对ASP.NET Core共享框架编译的,它的依赖项会指向共享框架里的程序集,但你的侧应用没有配置对应的程序集解析逻辑,CLR找不到依赖自然就报错了。

接下来是具体的解决办法,你可以根据自己的需求选:

1. 把侧应用改成ASP.NET Core应用(最简单的方案)

如果只是用来做调查,其实最快的方式就是把你的侧应用改成ASP.NET Core控制台应用或者Worker Service。这样当应用启动时,ASP.NET Core的宿主会自动帮你配置好共享框架的程序集解析规则,自动去dotnet/shared目录里找依赖。
你只需要在项目的.csproj文件里加上这段框架引用:

<ItemGroup>
  <FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>

改完之后重新编译启动,再用Assembly.LoadFrom加载你的自定义DLL,CLR就能自动找到那些共享框架里的依赖了,省心又省力。

2. 手动订阅程序集解析事件(不想改应用类型的话用这个)

要是你的侧应用必须是普通控制台应用,不想改成ASP.NET Core应用,那可以手动给AppDomain.CurrentDomain.AssemblyResolve事件加个处理方法,在CLR找不到程序集的时候,手动去共享框架目录里找。

  • 你可以先用你已经发现的路径C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App\8.0.18,不过最好别硬编码版本号,比如可以通过读取环境变量DOTNET_ROOT或者动态获取已安装的ASP.NET Core版本来拼接路径,这样兼容性更好。
  • 然后在事件处理方法里,根据缺失的程序集名称生成DLL文件名,去共享框架路径下尝试加载。示例代码大概是这样的:
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
    var assemblyName = new AssemblyName(args.Name);
    // 这里可以改成动态获取版本,避免硬编码8.0.18
    var sharedFrameworkPath = Path.Combine(
        Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
        "dotnet", "shared", "Microsoft.AspNetCore.App", "8.0.18",
        $"{assemblyName.Name}.dll");
    
    if (File.Exists(sharedFrameworkPath))
    {
        return Assembly.LoadFrom(sharedFrameworkPath);
    }
    return null;
};

记得提前引用System.IOSystem.Reflection命名空间哦。

3. 用AssemblyLoadContext加载(更符合.NET Core设计的方案)

在.NET Core及以上版本,官方更推荐用AssemblyLoadContext来管理程序集加载,它能帮你隔离不同的加载上下文,避免程序集冲突,也能更灵活地配置依赖查找路径。
你可以创建一个自定义的加载上下文,然后在里面配置共享框架的路径,示例代码如下:

var loadContext = new AssemblyLoadContext("CustomDllLoadContext", isCollectible: true);
// 配置共享框架的路径
var sharedFrameworkPath = Path.Combine(
    Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
    "dotnet", "shared", "Microsoft.AspNetCore.App", "8.0.18");
// 当找不到依赖时,去共享框架路径里找
loadContext.Resolving += (context, assemblyName) =>
{
    var assemblyPath = Path.Combine(sharedFrameworkPath, $"{assemblyName.Name}.dll");
    if (File.Exists(assemblyPath))
    {
        return context.LoadFromAssemblyPath(assemblyPath);
    }
    return null;
};
// 加载你的自定义DLL
var customAssembly = loadContext.LoadFromAssemblyPath(@"C:/Dev/MyApp/My.Dll");

这种方式比直接用Assembly.LoadFrom更可控,也更符合.NET Core的程序集加载设计思想。

另外,你可以检查下自定义DLL的依赖项,确认它依赖的确实是8.0.0.0版本的那些程序集,避免因为版本不匹配导致的加载失败。

内容来源于stack exchange

火山引擎 最新活动