Conflicted Reference DLL in Dynamo

I’m developing a dynamo package that reference a nugetpackage which reference another dll (the conflicted dll). Another Revit plugin also use the same dll and it create a conflict.

Most existing solutions use AssemblyResolve to load the correct updated dll. So far I have tried these and they do not work for me

  1. I have seen solutions out there for Revit plugin but I’m developing dynamo package so I do not know where to specify the AssemblyResolve for dynamo development.
  1. I tried to do sth similar to this. So I call AssemblyResolve right before I used the third party dll. Basically right before I use the code inside the conflicted dll. That did not work either
    The Building Coder: RvtVa3c Assembly Resolver

  2. I tried using a seperate AppDomain but I thinnk Revit only allow one appDomain that Revit uses. So I cannot use a seperate AppDomain either.

Any suggestion would be helpful. Thank you

1 Like

Which DLLs are your referencing?

Hi. the third party package is a self developed package. the conflicted dll it reference is System.Diagnostics.DignosticSource.dll. The one i used is version 6, it is conflicted with version 4.

I dont think which dll matter. The conflicted reference error is generic for any dll

Why not use version 4 so that you’re aligned with the other tool(s)?

The nuget package that I developed rely on a suite of tools and their versions need to match. Also I’m looking for a comprehensive solution. It is just an example that there’s one package happens to have System.Diagnostic version 4. What if the user happens to have two Revit plugins, one use System.Diagnostic version 4 and another one use version 5? Simply downgrading/upgrading our own version would not solve the overall problem

Maybe the problem could be solved if there’s a way I can specify which Dll to load when Dynamo start? Similar to how OnStartUp() works for Revit plugin.

One of the add-ins fails to load, and the user has to contact the developers to get them to standardize on a single version.

There are ways to load a conflicting library as an alias or something to prevent this, but I don’t know how as I’m not a ZT node developer.

Best solution let use merge assembly, app domain just load an assembly with unique merged.

1 Like

there is no general solution to this problem.

  1. Assembly merging only works if the types that you merge are modified to be unique, usually the merging tools like costura or il merge do not do this. We have a simple tool that we have written for this, it generates a new assembly with new type names for each type (adds a new namespace) and renames the assembly.
    Dynamo/src/Tools/AssemblyRenamerCLI at master · DynamoDS/Dynamo · GitHub -

  2. appDomain would work, but then you need to serialize and deserialize between domains.

  3. loading your assembly first - this works when things are loaded in a certain order, and only sometimes, it depends on how the other addin is loading their assemblies.

  4. loading your assembly with assembly resolve - again, it can work, but anyone else can also inject an assembly resolve event, and they are called in the order they are added, so a previous assembly resolve handler from another addin might win.

  5. loading the binary from the GAC can actually work… but you would have to install this binary into the GAC… if it’s not already in there.

There are more things we’ve tried or others have, this is not an exhaustive list, it’s just what I can recall - but first questions first:

What issues do you actually see because of the conflict? Anything?
Have you checked what modules actually get loaded by debugging Revit at runtime?

Quick note: Because the conflict is a Dynamo package with a Revit add-in, the Revit add-in will always load first.

1 Like

Thank you Michael for a very comprehensive answer. Option 2 and 5 sound good (what is GAC though?). Do you have an example for them? I tried option 2 without serializing and that didnt work, and not sure how this solution should work

This is a good question. The sequence of loaded module is perplexing to me. The sequence is as such.

  1. When I start Revit along with the debugger , no System.Diagnostic module is loaded

2.When I start Dynamo. The correct dll (the dll I use) is loaded

  1. No other System.Diagnostic module is loaded when i drop the node.

  2. It’s only when line 47 is called, the line that actually use the third party package is used then System.Diagnostics ver 4 module is reported loaded and cause the error.

The GAC Global Assembly Cache - .NET Framework | Microsoft Docs is the global assembly cache - in general the recommendation from MS is NOT to install things here, and I would agree that installing a Microsoft assembly there if it’s not already located there was probably not avoided for a reason.

I would give the renamer a shot if you really need it, though I still don’t understand what error you actually encounter.

Another option I have seen addin developers use is to take the source and manually change the type names by wrapping in one big namespace.

the dotnet source is now MIT licensed:

What do you mean by renamer? renaming and wrapping System.Diagnostics namespace? That’s one option but there are probably more dlls that are going to have conflicts. But maybe I can give it a try

Do you have any example for using appDomain (solution number 2 in your suggestion) ? I thought Revit only allow one appDomain to work with Revit?

Anyway, when i step through line 47. The error is this. Thanks Michael

image

Also just to clarify. System.Diagnostics.Diagnostics.dll is not a reference that I used. It is a required dependency of a nuget package that I used so I do not have control over it.

If we use renaming, that means if we have 4 or 5 dependencies that clash we will have to rename all the namespaces in that 4 or 5 dll. The problem is we will not even know which are the dlls that we are going to clash. This depends very much on the Revit plugins each user have in their machine. I’m just using this System.Diagnostics.Diagnostics dll as an example.

Any time you develop for a system you need to confirm that your code runs in that system. This is the case for Revit add-ins conflicting with each other, just as much as it is Dynamo nodes conflicting with each other and Revit add-ins.

The only way to ensure you never conflict is to only use your own stuff, or ensure that you always “rename” as noted above. If the namespace goes from ‘somepackage’ to ‘myHappyDynamoPackage’ the issue is resolved. This is difficult and time consuming to set up, but it is the only way you can ensure that your 3rd or 4th (nth?) party dependencies don’t conflict.

I believe that someday when we get to .net 6 this gets a good bit simpler, but that’s a ways out yet.

I managed to solve this using appDomain. I didnt use the proxy properly before. Here is the example of my code for anyone who is interested.

const string thirdPartyPath = @"ThirdpartyAssemblyPath ";
var newDomain = AppDomain.CreateDomain("newDomain");
string yourPluginPath = @"yourPluginPath";
var asmLoaderProxy = (Proxy)newDomain.CreateInstanceFromAndUnwrap(yourPluginPath, typeof(Proxy).FullName);
asmLoaderProxy.DoSomething(thirdPartyPath);

 public class Proxy : MarshalByRefObject
    {
        public void DoSomething(string assemblyPath)
        {
            var assembly = Assembly.LoadFile(assemblyPath);

            var instance = Activator.CreateInstance(assembly.GetTypes("TypeYouWantToUse"));
            instance.Work();
        }
    }
2 Likes

Really appreciate you sharing your solution in the end!

2 Likes