Revit API Forum
Welcome to Autodesk’s Revit API Forums. Share your knowledge, ask questions, and explore popular Revit API topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Additional .dll files as resource

12 REPLIES 12
Reply
Message 1 of 13
antonio_hipolito
1435 Views, 12 Replies

Additional .dll files as resource

I'm developing a REVIT addin that needs a external .dll library.
In order to reduce the number of deployed files, I want to integrate that .dll library as a resource. However, I'm struggling with associating the event handler for the AssemblyResolve. The event dosen't fire up when a not found library is raised.

Where should I place the bellow AddHandler command? At OnStart event handler (that runs when REVIT loads the addin) or at the addin Execute (that runs when REVIT executes the command)?

        AddHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf ResolveAssemblies

 

Any example on this?
Do you deploy additional dll libraries as a separate files, or do you integrate then in the main addin .dll as a resource?

 

12 REPLIES 12
Message 2 of 13

I believe most people ship them as separate DLLs. I have never heard of anyone doing what you propose, although it sounds useful.

 

Jeremy Tammik, Developer Advocacy and Support, The Building Coder, Autodesk Developer Network, ADN Open
Message 3 of 13

I tried this to get out of some .dll hell issues I was having. It worked, but statically linking .dlls as an embedded resources like this can cause issues with other add-ins, I found (pyRevit in my case). If that doesn't happen for you, then great! There may still be some pros and cons of doing it this way vs. shipping separate though.

 

Add the usual event listener to your startup:

 

AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;

 

You will need to add the .dlls you're referencing as an embedded resources (In VS, Add->Existing Items, then under Properties, change Build Action to Embedded Resource). I put all of my .dlls in an Assemblies folder for tidyness. Then you can use the following code for your AssemblyResolve function:

 

        private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
        {
            string assemblyName = args.RequestingAssembly.GetName().Name;
            if(assemblyName == "YourAssemblyName")
            {
                string resourceName = "YourAssemblyName.Assemblies." + new AssemblyName(args.Name).Name + ".dll";
                using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
                {
                    if (stream != null)
                    {
                        byte[] assemblyData = new byte[stream.Length];
                        stream.Read(assemblyData, 0, assemblyData.Length);
                        return Assembly.Load(assemblyData); 
                    }
                }
            }
            return null;
        }

 

Let me know if this works for you. I got stuck trying to fix the issues it was causing with pyRevit and reverted to shipping the .dlls separately. I'd be curious to see if there is a way to workaround it. That's what I was trying to do with the lines that were checking the calling assembly name. Perhaps someone with more experience in how the CLR loads in assemblies could give some insight.

Message 4 of 13

Try subscribe to AssemblyResolve event in the static constructor of your implementation of IExternalApplication

Message 5 of 13
ricaun
in reply to: antonio_hipolito

@josh.roth.MEIand @antonio_hipolito you could use Fody.Costura to embed the .dll references automatically, the Costura.Template has the ILTemplate.cs and Common.cs to handle all the load resources files, if the Assembly is already loaded the code does not force it to load again.

 

@jeremy_tammikI use this technic on the ConduitMaterial and others plugins.

 

Adding... ILTemplate.Attach(); on the IExternalApplication should do the trick.

 

See yaa

Luiz Henrique Cassettari

ricaun.com - Revit API Developer

AppLoader EasyConduit WireInConduit ConduitMaterial CircuitName ElectricalUtils

Message 6 of 13
antonio_hipolito
in reply to: ricaun

Thank all for you suggestions.

I'll try them out.

Regards!I

Message 7 of 13

I also wanted to chime in here with resources. Ehsan actually hopped on a call with me and showed me his process with submodules. Since then that's how I have been handling other libraries that I need to use in my project.

 

While I started with an AssemblyResolver, loading in a newer version of the assembly will not resolve correctly when a previous version has already been loaded. This came about because of the CTC addins still used the MahApps version 2 (I believe). Then I come barreling in to the situation with  the new 3.x versions of MahApps because I wanted to use the new, fancy features. Revit will resolve everything up to the point where you wanted to use one of the 3.x features that the 2.x didn't have. Then my app would throw an Exception telling me that it couldn't find that 3.x feature because CTC had loaded the 2.x version first.

 

So, Ehsan told me about submodules in git (which I had to learn about) and re-building MahApps open-source code under a new .dll name.

 

Opening the open-source project, changing the name, building the submodules, and then referencing the new submodules have been fantastic.

 

Attached is a snippet of my library with the re-built MahApps content. Also if you look in pyRevit's library, Ehsan does the same thing, or at least used to.

 

Kudos of course to Ehsan for showing me this and thanks to Jeremy for pointing me here from the blog.

 

Hopefully this helps someone in the future.

Message 8 of 13
Kennan.Chen
in reply to: kraftwerk15

Same issue with MahApps before and I also rebuilt the whole project.

 

Life can be easier to compile MahApps project with another Public/Private key pair(.snk file), which will sign a unique strong name to the dll. Referencing a strong-named dll is supposed to be a common practise to "dll hell" issue.

 

Strong-named assemblies | Microsoft Docs

Tags (1)
Message 9 of 13

Many thanks to everybody for all your helpful advice!

 

I summarised and edited it on the blog for posterity:

  

https://thebuildingcoder.typepad.com/blog/2021/10/dll-as-resource-and-multi-version-add-ins.html#5

  

Jeremy Tammik, Developer Advocacy and Support, The Building Coder, Autodesk Developer Network, ADN Open
Message 10 of 13

Thanks again for all your thoughts!

Message 11 of 13
minet.axel
in reply to: kraftwerk15

Hello, maybe you will provide an example, I'm trying to do the same thing but I don't know where to start.

Message 12 of 13
minet.axel
in reply to: Kennan.Chen

Hello,

I need some information.

If I modify the signature of the MahApps project and I recompile the project without modifying the name of the assembly. Does this work? Because in the project there are lots of references to the MahApps assembly name.

 

Thk

Message 13 of 13
Kennan.Chen
in reply to: minet.axel

Theoretically, you don't need to rename the dll name once your have sign a strong name to the dll and reference that dll directly.

 

Weird thing is I went through my code written years ago and found that I actually did the renaming. I could not recall why I did that and whether it was necessary.

 

EDIT:

One thing to mention is that an add-in is a part of Revit and there could be other add-ins referencing MahApps without strong name. If your add-in uses a strong-named MahApps.dll, add-ins that loaded after your add-in will use your MahApps.dll, which could cause those add-ins to fail to load because of the incompatible version. Renaming your strong-named MahApps dll can prevent your add-in from "polluting" the common .NET runtime in Revit.

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Rail Community