理解 CLR/System.IO.FileNotFoundException“无法加载文件或程序集...或其依赖项之一”

问题描述 投票:0回答:2

我在 C# 类库(SolidWorks 插件)中使用

System.Text.Json
时遇到问题。它可能是 DLL hell 的一个实例,如here所述。

由于这种方法不起作用,如果我对这个问题有更多的了解,我也许能够弄清楚一些事情。也许有人可以帮忙?

首先 - 我的代码。

我的“csproj”文件:

<Project Sdk="Microsoft.NET.Sdk">

  <!-- general stuff -->
  <PropertyGroup>
    <TargetFrameworks>net48</TargetFrameworks>
    <ImplicitUsings>disable</ImplicitUsings>
  </PropertyGroup>

  <!-- references: the top two are SolidWorks API (needed for making a SolidWorks addin -->
  <ItemGroup>
    <PackageReference Include="com.solidworks.core" Version="29.5.1" />
    <PackageReference Include="com.solidworks.tools" Version="21.5.0" />
    <PackageReference Include="System.Text.Json" Version="6.0.2" />
  </ItemGroup>

  <!-- In order to have the addin available within SolidWorks,
       it's dll needs to be registered in the codebase. For convenience
       we automatically register on build and unregister on clean. -->
  <Target Name="Register" AfterTargets="AfterBuild">
    <Exec Command="%windir%\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe &quot;$(TargetPath)&quot; /codebase" />
  </Target>
  <Target Name="Unregister" BeforeTargets="BeforeClean">
    <Exec Command="%windir%\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe &quot;$(TargetPath)&quot; /u" />
  </Target>

</Project>

我的

cs
文件的相关部分:

using System;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using SolidWorks...; // all the SolidWorks usings required

namespace SwxAddin
{
    [Guid("acb6f17b-9738-4f11-a324-30e05625ff89")]
    [ComVisible(true)]
    public class SwxAddinImpl : ISwAddin
    {
        // will be called on addin load in SolidWorks
        public bool ConnectToSW(object swx, int addinId)
        {
            var jsonText = "{ \"foo\": { \"bar\": 2 } }";
            var doc = System.Text.Json.JsonDocument.Parse(jsonText); // exception occurs

            return swx != null;
        }

        // will be called on addin unload in SolidWorks
        public bool DisconnectFromSW() { return true; }

        // This is run when registering the dll. It writes some stuff into the
        // SolidWorks registry to make the addin available.
        [ComRegisterFunction]
        protected static void RegisterFunction(Type type) { ... }

        // This is run when unregistering the dll. It removes the stuff from the
        // SolidWorks registry that was written into it by RegisterFunction.
        [ComUnregisterFunction]
        protected static void UnregisterFunction(Type type) { ... }
    }
}

当我在构建(并因此在代码库中注册我的 dll)后运行 SolidWorks 并调试它时,我收到运行时错误

var doc = System.Text.Json.JsonDocument.Parse(jsonText);

发生异常:CLR/System.IO.FileNotFoundException An 类型“System.IO.FileNotFoundException”的异常发生在 System.Text.Json.dll 但未在用户代码中处理:“无法加载” 文件或程序集'System.Runtime.CompilerServices.Unsafe, 版本=4.0.4.1,文化=中性,PublicKeyToken=b03f5f7f11d50a3a' 或 它的依赖项之一。系统找不到指定的文件。'

。如上所述,我确实尝试添加

<PropertyGroup>
  <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
  <GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
</PropertyGroup>

到我的 csproj 文件,在我的 bin/Debug 文件夹中生成以下

.dll.config
文件:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

但是仍然出现运行时错误。

所以我想真正了解这个问题,而不是仅仅遵循烹饪食谱。以下是我尝试过的一些事情和想法:

  1. 错误表明问题出在
    System.Text.Json.dll
    内部。据我了解,位于位置
    System.Text.Json.dll
    的文件
    A
    需要位置
    System.Runtime.CompilerServices.Unsafe.dll
    中版本
    4.0.4.1
    的文件
    B
    ,但在位置
    B
    中存在不同版本的文件
     System.Runtime.CompilerServices.Unsafe.dll
    (或者根本没有该名称的文件)。

=> 谁能告诉我我们所说的

A
B
是哪个位置?
是某个文件夹吗?是GAC 吗?如果是 GAC,我们实际上是在谈论文件还是其他东西?

  1. 我检查了(对我来说)最可能的位置,文件夹
    $myProjectPath\bin\Debug\net48
    。在那里我可以找到(除其他外)两个 dll
    System.Text.Json.dll
    System.Runtime.CompilerServices.Unsafe.dll
    。我在一些反编译工具中打开它们来检查它们的版本及其引用的版本。这是我发现的:
  • System.Text.Json.dll
    有版本
    6.0.0.2
    和版本
    System.Runtime.CompilerServices.Unsafe.dll
    的参考文献
    6.0.0.0

  • System.Runtime.CompilerServices.Unsafe.dll
    有版本
    6.0.0.0

=> 因此所需版本和当前版本

System.Runtime.CompilerServices.Unsafe.dll
是对齐的。 为什么我会收到错误消息?这不是意味着位置
A
B
不是
$myProjectPath\bin\Debug\net48
吗? 或者在某些情况下引用的版本是否被忽略?什么样的情况?

  1. 我构建了一个独立的控制台应用程序,仅使用

    System.Text.Json
    并包含两行

    var jsonText = "{ \"foo\": { \"bar\": 2 } }";

    var doc = System.Text.Json.JsonDocument.Parse(jsonText);

里面有

Main
方法。那里不会发生运行时错误。 所以 SolidWorks 一定是罪魁祸首,即使运行时错误消息中没有提及。

  1. 本文介绍了 dll hell 并提供了故障排除建议。我在 Visual Studio 中检查了模块(调试 -> Windows -> 模块)。原来就在错误发生之前
  • System.Text.Json
    版本
    6.0.0.0
    已加载(从我的
    $myProjectPath\bin\Debug\net48
    文件夹)。

  • System.Runtime.CompilerServices.Unsafe
    未加载。

=> 但是如果

System.Runtime.CompilerServices.Unsafe
之前没有被加载过,为什么
System.Text.Json
想要加载版本
4.0.4.1
而不是在它自己的引用(
6.0.0.0
)中指定的版本?
4.0.4.1
从哪里来?

c# .net dll
2个回答
0
投票

感谢 M Kloster 的评论,我可以通过手动加载程序集来解决该问题 - 尽管不幸的是这无助于理解该问题。

首先我插入了线

AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(MyResolveEventHandler);

进入

ConnectToSW
方法(作为第一行)。

然后我像这样实现了

MyResolveEventHandler

private static Assembly MyResolveEventHandler(object sender, ResolveEventArgs args)
{
    var nameCompilerServicesUnsafe = "System.Runtime.CompilerServices.Unsafe";
    if (args.Name == nameCompilerServicesUnsafe + ", Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
    {
        var assemblyPath = Assembly.GetCallingAssembly().Location;
        if (Path.GetFileName(assemblyPath) == "System.Text.Json.dll")
        {
            var assemblyFolder = Path.GetDirectoryName(assemblyPath);
            var pathCompilerServicesUnsafe = Path.Combine(assemblyFolder, nameCompilerServicesUnsafe + ".dll");
            if (File.Exists(pathCompilerServicesUnsafe))
                return Assembly.LoadFile(pathCompilerServicesUnsafe);
        }
    }

    return null;
}

现在,每当自动机制无法加载程序集时,就会调用

MyResolveEventHandler

这里我只是检查是否是

System.Text.Json.dll
尝试加载
System.Runtime.CompilerServices.Unsafe
版本
4.0.4.1
,如果是,我从
System.Runtime.CompilerServices.Unsafe.dll
的位置文件夹返回程序集
System.Text.Json.dll

奇怪的是,这让我确认尝试加载

System.Text.Json.dll
版本
System.Runtime.CompilerServices.Unsafe
4.0.4.1
确实是位于我的
$myProjectPath\bin\Debug\net48
文件夹中的版本。这对我来说毫无意义,因为反编译工具告诉我文件
$myProjectPath\bin\Debug\net48\System.Text.Json.dll
引用了
System.Runtime.CompilerServices.Unsafe
版本
6.0.0.0
,而不是
4.0.4.1

正如我在问题中所说,该问题不会发生在 SolidWorks 之外(例如在独立的控制台应用程序中)。因此,SolidWorks 必须以某种方式干扰(自动)装配体解析机制,也许是重定向绑定?很神秘...有办法关掉它吗?


0
投票

我的场景:一个主控制台应用程序项目和一个库项目。

最后,他们必须包含新的参考“System.Text.Json.dll”(在每个项目的参考部分中)及其依赖项(用于利用 .Net frm 4.8),编译所有内容并执行。

© www.soinside.com 2019 - 2024. All rights reserved.