我在 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 "$(TargetPath)" /codebase" />
</Target>
<Target Name="Unregister" BeforeTargets="BeforeClean">
<Exec Command="%windir%\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe "$(TargetPath)" /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>
但是仍然出现运行时错误。
所以我想真正了解这个问题,而不是仅仅遵循烹饪食谱。以下是我尝试过的一些事情和想法:
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,我们实际上是在谈论文件还是其他东西?
$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
吗? 或者在某些情况下引用的版本是否被忽略?什么样的情况?
我构建了一个独立的控制台应用程序,仅使用
System.Text.Json
并包含两行
var jsonText = "{ \"foo\": { \"bar\": 2 } }";
var doc = System.Text.Json.JsonDocument.Parse(jsonText);
里面有
Main
方法。那里不会发生运行时错误。 所以 SolidWorks 一定是罪魁祸首,即使运行时错误消息中没有提及。
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
从哪里来?
感谢 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 必须以某种方式干扰(自动)装配体解析机制,也许是重定向绑定?很神秘...有办法关掉它吗?
我的场景:一个主控制台应用程序项目和一个库项目。
最后,他们必须包含新的参考“System.Text.Json.dll”(在每个项目的参考部分中)及其依赖项(用于利用 .Net frm 4.8),编译所有内容并执行。