Thirdparty addin library clash

FlorisvdG
Advocate
Advocate

Thirdparty addin library clash

FlorisvdG
Advocate
Advocate

Hi all, hope you are doing well.

 

This is not so much asking for a solution, more of an inquiry how others may have handled such a situation.

 

We have built a few addins for Revit. Some of them use a third party UI-library (a pretty well known one, but I'll leave the name out).

We have never had any issues with this, until recently when we installed a different addin from a third-party vendor.

Suddenly our addins started throwing weird exceptions upon loading the UI. When we disable the third party addin, everything is fine.

 

Turns out that they use the same UI library as we do, and there is a version mismatch. Let's say they use version 18.x, and we use 21.x. Support from said UI library mentions that within one AppDomain, only 1 version can be referenced.

Since all Revit addins run in Revit's Appdomain, this poses a problem.

 

We have tried building a release with the exact same version as the third party addin, but without succes unfortunately.

 

I am wondering if anybody here ever encountered this, if, and how, you managed to work around or fix this issue?

 

Thanks.

 

0 Likes
Reply
Accepted solutions (1)
981 Views
12 Replies
Replies (12)

caroline.gitonga
Autodesk
Autodesk

Hi @FlorisvdG,

A similar concern have been raised a number of times on handling third party libraries with different versions. Revit only loads one instance of a third party library.  Its unfortunate that we cannot control external addins unless they are your own in which you are able to control which libraries they load as well as have the correct DLL referenced. This said, you may check this forum thread on the same and get some important points highlighted: https://forums.autodesk.com/t5/revit-api-forum/loading-different-versions-of-same-third-party-librar...

Carol Gitonga, Developer Advocacy and Support, ADN Open

FlorisvdG
Advocate
Advocate

Thanks for the Reply.

 

So if Revit only loads one instance of a particular library, if we built our Addin against the exact same version of that library, we should be able to get the already loaded library from the current AppDomain. I'll give that a shot.

ricaun
Advisor
Advisor

Hello @FlorisvdG 


I believe the best approach to prevent this kind of problem is Repack the dll to a new assembly, this gonna trick Revit and ensure your UI dll gonna be loaded with your version.

 

I helped a user with a similar problem with two plugins and each one with one version of the UI library.

 

https://forums.autodesk.com/t5/revit-api-forum/the-phenomenon-that-other-ui-components-are-not-visib...

 

I have been using ILRepack.Lib.MSBuild.Task to embed the library inside another dll.

 

I have issues with HelixToolkit.Wpf that is used in Dynamo, then I created my own version ricaun.HelixToolkit.Wpf. and now my plugin does not break others and others do not break mine.

 

If you need help to setup the project just give a shoutout.

 

Luiz Henrique Cassettari

ricaun.com - Revit API Developer

AppLoader EasyConduit WireInConduit ConduitMaterial CircuitName ElectricalUtils

FlorisvdG
Advocate
Advocate

Hello @ricaun,

Thank you for your reply. We are actually dynamically loading (most of) our dependencies using reflection. We can make sure the right version will be loaded. We have also tried your approach (though using Custora Fody) to ensure all packages are within the assembly. This normally works, but not in this particular case.

 

The issue here is that the third party vendor does not allow cross-version use of their libraries within the same appdomain. So even when we succesfully load our version, it will create conflicts when any other addin loads a different version of the library.

 

ricaun
Advisor
Advisor

I have been using Costura Fody as well, I am pretty sure Costura creates a copy of the dll and loads on the fly, but in the end gonna have the same AssemblyName as the original.

 

And if you have two AssemblyName with the same Name loaded in the AppDomain with different versions, the AppDomain gonna use only one, and most of the time something breaks.

 

In a normal Application, the AppDomain never gonna load two versions of the same AssemblyName, it`s a no-no.

 

If you change the AssemblyName using ILRepack probably gonna fix the issue.

Luiz Henrique Cassettari

ricaun.com - Revit API Developer

AppLoader EasyConduit WireInConduit ConduitMaterial CircuitName ElectricalUtils

FlorisvdG
Advocate
Advocate

I see. You are correct about Fody. I now understand the difference with your suggested solution.

I will take a look into ILRepack. It sounds like it could work, but it kind of depends how the third party library will handle that. The library itself may use multiple packages from their origin as well. I cannot of re-pack those.

So if xxx.Data is referencing xxx.layout, I can repack xxx.Data, but that one would still refer to xxx.layout.

If xxx.layout is then also used by the other addin, we're still nowhere. Or is that not how it works?

 

It's a great suggestion though, thank you!

If I need help, I'll search you out. It it works, I'll come back and thank you. 😃

 

ricaun
Advisor
Advisor

The idea is to trick your application to use your version of the xxx.Data and xxx.layout, and you should repack these two library in one new library with a new AssemblyName.

 

All the namespace gonna stay the same in your main application but your application gonna use a different dll.

 

Here is an example that I used in the HelixToolkit

  <ItemGroup>
    <PackageReference Include="HelixToolkit.Wpf" Version="2.20.2" IncludeAssets="build; compile" PrivateAssets="All" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="ILRepack.MSBuild.Task" Version="*" IncludeAssets="build; compile" PrivateAssets="All" />
  </ItemGroup>

  <Target Name="ILRepacker" AfterTargets="Build">
    <PropertyGroup>
      <WorkingDirectory>$(MSBuildThisFileDirectory)$(OutDir)</WorkingDirectory>
    </PropertyGroup>
    <ItemGroup>
      <InputAssemblies Include="$(TargetPath)" />
      <InputAssemblies Include="@(ReferencePathWithRefAssemblies)" Condition="'%(filename)' == 'HelixToolkit.Wpf'" />
      <InputAssemblies Include="@(ReferencePathWithRefAssemblies)" Condition="'%(filename)' == 'HelixToolkit'" />
      <!-- 
      -->
    </ItemGroup>

    <ItemGroup>
      <!-- Must be a fully qualified name -->
      <DoNotInternalizeAssemblies Include="ExampleAssemblyToMerge3" />
    </ItemGroup>

    <!-- https://github.com/peters/ILRepack.MSBuild.Task/blob/master/src/ILRepack.MSBuild.Task/ILRepack.cs -->
    <ILRepack XmlDocumentation="true" AllowDuplicateResources="true" Union="false" DebugInfo="true" CopyAttributes="true" Parallel="true" Internalize="false" OutputType="$(OutputType)" MainAssembly="$(AssemblyName).dll" OutputAssembly="$(AssemblyName).dll" InputAssemblies="@(InputAssemblies)" WilcardInputAssemblies="true" InternalizeExcludeAssemblies="@(InternalizeExcludeAssemblies)" WorkingDirectory="$(WorkingDirectory)" />
  </Target>

 

 

Luiz Henrique Cassettari

ricaun.com - Revit API Developer

AppLoader EasyConduit WireInConduit ConduitMaterial CircuitName ElectricalUtils

FlorisvdG
Advocate
Advocate

Hey @ricaun , we have solved our issue by disabling the third party addin. However, I am now looking into a more sustainable solution with ILRepack. I'd love your help on this.

Apon release build I get this error:

[...]nuget\packages\ilrepack.lib.msbuild.task\2.0.18.2\build\ILRepack.Lib.MSBuild.Task.targets(19,5): error : Failed to resolve assembly: 'RevitAPI, Version=21.0.0.0, Culture=neutral, PublicKeyToken=null'
Feel free to DM me if you are happy to help.

0 Likes

ricaun
Advisor
Advisor

@FlorisvdG what are you trying to repack?


Looks like is your main plugin, I usually do not use ILRepack for the main plugin, only in libraries I can't compile or do not have the source code to recompile in a new assembly, third-party library that was not designed to work with Revit.
You could use the ILRepack in your main plugin but you need to add all the references in the debug/release folder, so ILRepack can use that references to Repack in on assembly. In your case, the RevitAPI is missing...

 

Is too messy to implement ILRepack in the main code, and the debug/release folder looks horrendous.

Costura Fody in another hand works great, the debug/release folder is clear, one file only. But the file.dll is a copy inside the main.dll, and in the end, is almost the same as not using Costura.

Luiz Henrique Cassettari

ricaun.com - Revit API Developer

AppLoader EasyConduit WireInConduit ConduitMaterial CircuitName ElectricalUtils

FlorisvdG
Advocate
Advocate

Here's my code snippet from my Addin.dll, I copied your example.

<Target Name="ILRepacker" AfterTargets="Build">
		<PropertyGroup>
			<WorkingDirectory>$(MSBuildThisFileDirectory)$(OutDir)</WorkingDirectory>
		</PropertyGroup>
		<ItemGroup>
			<InputAssemblies Include="$(TargetPath)" />
			<InputAssemblies Include="@(ReferencePathWithRefAssemblies)" Condition="'%(filename)' == 'DevExpress.Wpf'" />			
			<!-- 
      -->
		</ItemGroup>

		<ItemGroup>
			<!-- Must be a fully qualified name -->
			<!--<DoNotInternalizeAssemblies Include="ExampleAssemblyToMerge3" />-->
		</ItemGroup>

		<!-- https://github.com/peters/ILRepack.MSBuild.Task/blob/master/src/ILRepack.MSBuild.Task/ILRepack.cs -->
		<ILRepack XmlDocumentation="true" AllowDuplicateResources="true" Union="false" DebugInfo="true" CopyAttributes="true" Parallel="true" Internalize="false" OutputType="$(OutputType)" MainAssembly="$(AssemblyName).dll" OutputAssembly="$(AssemblyName).dll" InputAssemblies="@(InputAssemblies)" WilcardInputAssemblies="true" InternalizeExcludeAssemblies="@(InternalizeExcludeAssemblies)" WorkingDirectory="$(WorkingDirectory)" />
	</Target>

 

0 Likes

ricaun
Advisor
Advisor
Accepted solution

If this is for your RevitAddin.dll, you probably need to enable the copy in the reference RevitAPI.dll to make ILRepacker work.

 

The best solution I found is creating a new cs project like ricaun.HelixToolkit.Wpf without referencing any Revit library, only the HelixToolkit.Wpf like this: https://github.com/ricaun-io/ricaun.HelixToolkit.Wpf

 

If you wanna help to set up your project you could find me in the unofficial Revit API Discord:

https://forums.autodesk.com/t5/revit-api-forum/revit-api-discord/m-p/11311265#M64780

 

See yaa

 

Luiz Henrique Cassettari

ricaun.com - Revit API Developer

AppLoader EasyConduit WireInConduit ConduitMaterial CircuitName ElectricalUtils

0 Likes

FlorisvdG
Advocate
Advocate

Thanks Ricaun, Seeing your example made me understand how to approach this thing.

 

I have removed my DevExpress libraries from RevitAddin.Dll, I have created a new empty project with the DevExpress References & the ILRepack thing.

 

Ricaun, Thanks for your continued support in this thread! Kudos!