Revit API - 可能存在 NewtonSoft.Json 冲突
Revit API - Possible NewtonSoft.Json conflict
我正在尝试创建一个扩展到云端并检索数据,简单的请求。使用 Add-In 管理器时它工作完美,但是当我分发给其他用户时,似乎与我使用的 NewtonSoft.Json 版本(7.0.1)和我的版本有冲突在 Revit 程序文件 (5.0.8) 中找到。
完整的错误信息是:
[Window Title] Command Failure for External Command
[Main Instruction] Revit could not complete the external command.
Contact the provider for assistance. Information they provided to
Revit about their identity: icubY.
[Expanded Information] Revit encountered a
System.IO.FileNotFoundException: Could not load file or assembly
'Newtonsoft.Json, Version=6.0.0.0, Culture=neutral,
PublicKeyToken=30ad4fe6b2a6aeed' or one of its dependencies.
这是一个共享的 DLL,它封装了从 API 到应用程序(带有安全令牌、headers、cookie)的所有这些,因此分离版本将是一个真正的痛苦.
我真的需要使用旧版本才能工作吗?还有其他想法吗?
首先,我将从 Fuslogvw.exe 工具开始,看看加载程序集时会发生什么。
AddInManager 使用 Assembly.LoadFile 加载插件,然后挂接到 AppDomain.CurrentDomain.AssemblyResolve
事件以解决依赖关系。也许您可以使用相同的技术来加载 Newtonsoft.Json 程序集。
我在 IExternalApplication.OnStartup 方法中手动加载所有依赖项。您遇到的问题是因为 Revit 在包含 Revit.exe 的文件夹中查找任何依赖项,而不是在您的插件目录中查找。
如果您无法使 AssemblyResolve 事件起作用,请尝试如下操作:
使用
string location = Assembly.GetAssembly(typeof(YourIExternalApplicationClass)).Location;
,
然后使用 string dir = Path.GetDirectoryName(location);
然后可以通过string dllPath = Path.Combine(dir, "DLLName.dll");
获取每个依赖的路径
最后,使用Assembly.LoadFrom(dllPath);
加载每个DLL
我做了更多的研究,因为我没有完全理解上面的解决方案。我认为一个非常简单的解决方案是 explained here
您只需在 visual studio 项目中将引用 (newtonsoft.json) 设置为特定版本 = true,然后将该引用复制到带有 revit 加载项的加载项文件夹中。 dll
当您分发给用户时,他们需要 newtonsoft.json 库以及您的加载项 .dll,这不是理想的但可行的(刚刚测试并且对我有用)
所以我在我正在处理的项目中同样遇到了这个问题。在对这个问题进行了大量的挖掘之后,我觉得我对正在发生的事情有了很强的把握。
如前所述,Revit 使用 Assembly.LoadFile
命令加载程序集。这意味着所有加载项程序集都加载到同一个 AppDomain
中。如果您想将事件处理程序添加到 AppDomain.CurrentDomain.AsseblyResolve
以防止您的加载项发生冲突,那么这并不理想。这是因为 AssemblyResolve
是一个不寻常的事件,它需要一个 Assembly 作为 return 项目。这意味着如果您有多个事件处理程序附加到 AssemblyResolve
,那么第一个 return 非空程序集的事件处理程序将是使用的事件处理程序,因此如果多个加载项正在尝试导致冲突解析相同的程序集(例如在像 Newtonsoft.Json 这样的通用程序集的情况下)。
例如,如果您安装了 Dynamo,Dynamo 还会向 AssemblyResolve
添加一个事件处理程序,尝试解析 Newtonsoft.Json 并从调用时的 Dynamo 程序文件目录。在我的例子中,我需要 Newtonsoft.Json 7.0.0.0 版,但在我的计算机上安装了 Dynamo 0.9,它是 returning Newtonsoft.Json 4.5.0.0 版。这非常令人困惑,因为我在理论上已经完美地处理了该决议,但我的程序集解决事件没有在我需要时触发。
综上所述,在此特定情况下您无能为力。解决这个问题的一些迂回方法是:
-找到一种方法在 Dynamo(或正在解决您希望解决的事件的任何程序集)之前加载您的加载项,并更好地处理解决方案(即确保当前正在处理的是您的应用程序 运行 在解决装配问题之前)。注意:查看 Revit 启动时的 procmon.exe 输出后,Revit 似乎首先从 "C:\ProgramData\Autodesk\Revit\Addins\" 文件夹按字母顺序加载插件,然后从 "C:\ProgramData\Autodesk\ApplicationPlugins" 文件夹按字母顺序加载插件.
-联系冲突的加载项制造商并请他们修复解决方案。
-针对我的问题,只需将dynamo升级到1.2版本即可解决冲突。
我读过有关创建您自己的 AppDomain
并将您需要的所有程序集加载到其中然后执行您想要的操作而不会发生冲突的信息,但我无法让它为我自己工作。
注意:不要浪费时间处理特定库的 application.config 文件。 Revit 将只检查 Revit.exe.config 的程序集探测路径和相关程序集信息。我也不建议修改它。
我正在尝试创建一个扩展到云端并检索数据,简单的请求。使用 Add-In 管理器时它工作完美,但是当我分发给其他用户时,似乎与我使用的 NewtonSoft.Json 版本(7.0.1)和我的版本有冲突在 Revit 程序文件 (5.0.8) 中找到。
完整的错误信息是:
[Window Title] Command Failure for External Command
[Main Instruction] Revit could not complete the external command. Contact the provider for assistance. Information they provided to Revit about their identity: icubY.
[Expanded Information] Revit encountered a System.IO.FileNotFoundException: Could not load file or assembly 'Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed' or one of its dependencies.
这是一个共享的 DLL,它封装了从 API 到应用程序(带有安全令牌、headers、cookie)的所有这些,因此分离版本将是一个真正的痛苦.
我真的需要使用旧版本才能工作吗?还有其他想法吗?
首先,我将从 Fuslogvw.exe 工具开始,看看加载程序集时会发生什么。
AddInManager 使用 Assembly.LoadFile 加载插件,然后挂接到 AppDomain.CurrentDomain.AssemblyResolve
事件以解决依赖关系。也许您可以使用相同的技术来加载 Newtonsoft.Json 程序集。
我在 IExternalApplication.OnStartup 方法中手动加载所有依赖项。您遇到的问题是因为 Revit 在包含 Revit.exe 的文件夹中查找任何依赖项,而不是在您的插件目录中查找。
如果您无法使 AssemblyResolve 事件起作用,请尝试如下操作:
使用
string location = Assembly.GetAssembly(typeof(YourIExternalApplicationClass)).Location;
,
然后使用 string dir = Path.GetDirectoryName(location);
然后可以通过string dllPath = Path.Combine(dir, "DLLName.dll");
最后,使用Assembly.LoadFrom(dllPath);
我做了更多的研究,因为我没有完全理解上面的解决方案。我认为一个非常简单的解决方案是 explained here
您只需在 visual studio 项目中将引用 (newtonsoft.json) 设置为特定版本 = true,然后将该引用复制到带有 revit 加载项的加载项文件夹中。 dll
当您分发给用户时,他们需要 newtonsoft.json 库以及您的加载项 .dll,这不是理想的但可行的(刚刚测试并且对我有用)
所以我在我正在处理的项目中同样遇到了这个问题。在对这个问题进行了大量的挖掘之后,我觉得我对正在发生的事情有了很强的把握。
如前所述,Revit 使用 Assembly.LoadFile
命令加载程序集。这意味着所有加载项程序集都加载到同一个 AppDomain
中。如果您想将事件处理程序添加到 AppDomain.CurrentDomain.AsseblyResolve
以防止您的加载项发生冲突,那么这并不理想。这是因为 AssemblyResolve
是一个不寻常的事件,它需要一个 Assembly 作为 return 项目。这意味着如果您有多个事件处理程序附加到 AssemblyResolve
,那么第一个 return 非空程序集的事件处理程序将是使用的事件处理程序,因此如果多个加载项正在尝试导致冲突解析相同的程序集(例如在像 Newtonsoft.Json 这样的通用程序集的情况下)。
例如,如果您安装了 Dynamo,Dynamo 还会向 AssemblyResolve
添加一个事件处理程序,尝试解析 Newtonsoft.Json 并从调用时的 Dynamo 程序文件目录。在我的例子中,我需要 Newtonsoft.Json 7.0.0.0 版,但在我的计算机上安装了 Dynamo 0.9,它是 returning Newtonsoft.Json 4.5.0.0 版。这非常令人困惑,因为我在理论上已经完美地处理了该决议,但我的程序集解决事件没有在我需要时触发。
综上所述,在此特定情况下您无能为力。解决这个问题的一些迂回方法是:
-找到一种方法在 Dynamo(或正在解决您希望解决的事件的任何程序集)之前加载您的加载项,并更好地处理解决方案(即确保当前正在处理的是您的应用程序 运行 在解决装配问题之前)。注意:查看 Revit 启动时的 procmon.exe 输出后,Revit 似乎首先从 "C:\ProgramData\Autodesk\Revit\Addins\" 文件夹按字母顺序加载插件,然后从 "C:\ProgramData\Autodesk\ApplicationPlugins" 文件夹按字母顺序加载插件.
-联系冲突的加载项制造商并请他们修复解决方案。
-针对我的问题,只需将dynamo升级到1.2版本即可解决冲突。
我读过有关创建您自己的 AppDomain
并将您需要的所有程序集加载到其中然后执行您想要的操作而不会发生冲突的信息,但我无法让它为我自己工作。
注意:不要浪费时间处理特定库的 application.config 文件。 Revit 将只检查 Revit.exe.config 的程序集探测路径和相关程序集信息。我也不建议修改它。