Revit API - Possible NewtonSoft.Json conflict

∥☆過路亽.° 提交于 2020-01-03 01:51:29

问题


I'm trying to create an extension that goes to the cloud and retrieve data, simple request. It works flawless when using the Add-In Manager, but when I distribute to other users, there seems to be a conflict with the version of the NewtonSoft.Json I'm using (7.0.1) and the version I found in Revit Program Files (5.0.8).

Full error message is:

[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.

This is a shared DLL that encapsulates all this comes and goes from the API to the APP (with security token, headers, cookies), so a separated version would be a real pain.

Do I really need to use the older version for this to work? Any other idea?


回答1:


First, I will start with the Fuslogvw.exe tool to see what happens when your assembly is loaded.

AddInManager use Assembly.LoadFile to load the addin, then hook into the AppDomain.CurrentDomain.AssemblyResolve event to resolve the dependencies. May be you can use the same technique to load your Newtonsoft.Json assembly.




回答2:


I manually load all of my dependencies in the IExternalApplication.OnStartup method. The problem you're experiencing is because Revit looks in the folder containing Revit.exe for any dependencies and not in your addin directory.

If you can't get the AssemblyResolve event to work, then try something like this:

Retrieve the directory of your addin by using string location = Assembly.GetAssembly(typeof(YourIExternalApplicationClass)).Location;, then use string dir = Path.GetDirectoryName(location);

You can then get the path of each dependency by using string dllPath = Path.Combine(dir, "DLLName.dll");

Finally, load each DLL by using Assembly.LoadFrom(dllPath);




回答3:


I did a bit more research because I did not fully understand the solution above. I thought a really simple solution was explained here

You just set the reference (newtonsoft.json) to specific version = true in your visual studio project, and then copy over that reference into the add-in folder with your revit add-in .dll

When you distribute to users they would need the newtonsoft.json library as well as your add-in .dll which isn't ideal but workable (just tested and this worked for me)




回答4:


So I similarly had this issue in a project that I'm working on. After a substantial amount of digging on the issue I feel like I have a strong grasp on what is happening.

As was stated, Revit loads assemblies using the Assembly.LoadFile command. This means that all the add-in assemblies are loaded into the same AppDomain. That's not ideal given if you want to add an event handler to AppDomain.CurrentDomain.AsseblyResolve in order to prevent conflict in your add-in. This is because AssemblyResolve is an unusual event which requires an Assembly as the return item. That means that if you have multiple event handlers attached to AssemblyResolve then the first event handler that returns a non null Assembly will be the event handler that is used and thus cause conflict if multiple add-ins are attempting to resolve the same Assembly (such in the case of a common Assembly like Newtonsoft.Json).

So for instance, and example that would likely be common among programmers, if you have Dynamo installed, Dynamo ALSO adds an event handler to AssemblyResolve that attempts to resolve Newtonsoft.Json and loads it from the Dynamo program files directory when called. In my case, I needed Newtonsoft.Json version 7.0.0.0 but with Dynamo 0.9 installed on my computer it was returning Newtonsoft.Json version 4.5.0.0. This was incredibly confusing given I had theoretically handled the resolution perfectly but my assembly resolve event was not firing when I needed it to.

With all that said, there isn't too much that you can do in this certain instance. A few round-about ways to defeat this problem are:

-Find a way to load your add-in prior to Dynamo (or whichever Assembly is resolving the event that you wish to resolve) and handle the resolution better (i.e. make sure it's your application that is currently being run prior to resolving the assembly issue). NOTE: Having looked at the procmon.exe output at the startup of Revit it appears that Revit loads addins from the "C:\ProgramData\Autodesk\Revit\Addins\" folder first, in alphabetical order, AND THEN from the "C:\ProgramData\Autodesk\ApplicationPlugins" folder in alphabetical order.

-Contact the conflicting add-in manufacturer and ask them kindly to fix the resolution.

-Specific to my issue, simply upgrading dynamo to version 1.2 solved the conflict.

I've read about creating your own AppDomain and loading all the assemblies that you need into it and then perform the operations you want without conflict, but I couldn't get it to work for myself.

Note: Don't waste time messing with the application.config file for your specific library. Revit will only check the Revit.exe.config for the Assembly probing path and dependent assembly information. I also wouldn't recommend modifying that.



来源:https://stackoverflow.com/questions/33109558/revit-api-possible-newtonsoft-json-conflict

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!