Addin-Manager + Multiple/ Support Dll's

Addin-Manager + Multiple/ Support Dll's

mertens3d
Enthusiast Enthusiast
6,031 Views
37 Replies
Message 1 of 38

Addin-Manager + Multiple/ Support Dll's

mertens3d
Enthusiast
Enthusiast

I am able to get my primary dll to update after rebuilding with the AIM, but support dll's do not.

 

Is this the same behavior others see?

 

Has anyone found a solution to using the AIM with multiple Dll's?

 

 

 

0 Likes
6,032 Views
37 Replies
Replies (37)
Message 21 of 38

matthew_taylor
Advisor
Advisor

Hi Jeremy,

Thank you again for taking the time.

 

This is a frustrating issue that takes us back to the days of restart Revit to debug after changes to code. Most frustrating. I'm sure there is a reason for the inadvertent behaviour, be it a Visual Studio setting or something, but until we know what that is, we're at sea.

 

  • The number of users affected. Potentially all Revit API developers.
  • The potential revenue impact to you. Each change in code has an added overhead of 5 minutes. Potentially several hours per week per person.
  • The potential revenue impact to Autodesk. 4 hours to fix the issue.
  • Realistic timescale over which a fix would help you. Before the official Revit 2019 roll-out, preferably sooner.
  • In the case of a request for a new feature or a feature enhancement, please also provide detailed Use cases for the workflows that this change would address. n/a

Autodesk has spent a huge amount of time and money developing the Revit API community. This is an important tool for the community, probably second only to Revit Lookup; please treat it accordingly.

 

Thank you.


Cheers,

-Matt
_______________________________________________________________________________
Marking a post as a 'solution' helps the community. Giving a post 'Kudos' is as good as saying thanks. Why not do both?
Message 22 of 38

jeremytammik
Autodesk
Autodesk

Dear Matt,

 

Thank you for your business case.

 

I added it to the development issue.

 

Cheers,

 

Jeremy



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 23 of 38

mertens3d
Enthusiast
Enthusiast

In addition to what @matthew.taylor stated so well, I'll also state the obvious.

 

This not only affects the devs time but also their code quality. If it is not easy to debug the code live, they we come up with a workaround. Like most workarounds, it's probably not the best realistic way. Frustration sets in and quality suffers.

 

Out of curiosity, is there a reason not to open source it?

I doubt it has any trade secrets. Allowing us to view the code may help to come up with a solution and/or get it off of your list so that you can deal with larger issues.

 

Thanks for looking into it.

 

 

Message 24 of 38

jeremytammik
Autodesk
Autodesk
Dear Matt and Gregory, Thank you for your patience, comments and suggestions. The development team created a new ticket for this issue, REVIT-129984 [Addin Manager: auto unload DLLs before reloading them -- 13857937]. I added your input to that. Another new thread was just submitted for this issue here in the forum as well: https://forums.autodesk.com/t5/revit-api-forum/debugging-with-addinmanager-in-2019/m-p/7951087 Cheers, Jeremy


Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Message 25 of 38

Anonymous
Not applicable

Hi people,

 

The workaround I've got in place is pretty complicated (requires a lot of extra scripting) but it works (i.e. I don't have to Restart Revit):

 

Include a version number in the assembly names of *all* projects that you are making modifications to / debugging.

 

Have a build script that increments these version numbers before building. (I've had to write an ironpython script that updates the project files and then builds the projects using msbuild.) The script then copies the output files to a staging folder that is uniquely-named with a build timestamp.

 

I then have a dedicated Revit python shell command script that scans the staging folders for the most recently built one, dynamically loads the addin dll from there (using clr.AddReferenceToFileAndPath(...)), and using reflection locates and instantiates the class responsible for the command. It then executes that command.

 

It's still a bit annoying because Visual Studio detects the changes to the project files after the build and prompts for reloading them. In some cases you also have to detach then re-attach to the process because the source files have changed. But I don't have to restart Revit.

 

In any case, this workflow works for even the case where you're debugging DLLs referenced by your addin. The unique assembly names seem to be the only way to force the .NET loader to load these referenced DLLs without clashing with the old versions of them (from a prior loaded build or from existing addins that have loaded what would otherwise be the same referenced dlls).

 

P.S. I found that changing the assembly version property alone did not work. For me the .NET loader would load just one version of the dll and use that for all loaded addins that referenced a different version of it, leading to type missing exceptions in the case that a type was modified or removed in the most recent build. Changing the assembly name (property) on every build circumvented this issue.

 

With a bit of work I could probably cleanup and generalize these scripts to work for other users (if Autodesk doesn't beat me to it)...

 

0 Likes
Message 26 of 38

mertens3d
Enthusiast
Enthusiast

That's kind of funny as I've been working on a similar solution/ workaround, except with gulpjs. (Not sure how successful it will be long term)

 

I have a my gulp task assigned to run prior to build.

That changes the value in a constants file.

That value is referenced by all of my individual projects for the build #.

The downside is that it is probably pretty much doing a rebuild every time I do a plain build, but this way I'm guaranteed to have a clean set of dll's when it does come time to attach and so I don't have to remember to do a rebuild. If it gets too slow I may refine the idea.

 

One refined solution may be to only modify the build number of each project, but that would mean watching all of the cs files in the project....or some such. That would mean only the files that reference that project's dll's would have to rebuild. 

 

Anyway...thought I'd post my current work around along with yours.

 

 

Snippet

Snippet
gulp.task('UpdateBuildNumber'function () {
    var targetFile = "Hatch22.FuzzyBunny/Constants.cs";
 
    var nowDate = new Date();
    var Year = nowDate.getFullYear();
    var Month = ("0" + (nowDate.getMonth() + 1)).slice(-2);
    var Day = ("0" + (nowDate.getDate() + 0)).slice(-2);
    var Hour = ("0" + (nowDate.getHours() + 0)).slice(-2);
    var Min = ("0" + (nowDate.getMinutes() + 0)).slice(-2);
    var Seconds = ("0" + (nowDate.getSeconds() + 0)).slice(-1);
 
    gulp.src(targetFile)
        .pipe(replace(/private const string ReleasePrefix.*/'private const string ReleasePrefix = "' + Year + '.' + Month + '.' + Day + '.' + Hour + Min + Seconds + '";'))
        .pipe(gulp.dest("Hatch22.FuzzyBunny/"));
 
});

Snippet

namespace mertens3d.hatch22.fuzzyBunny
{
    internal class Constants
    {
        private const string ReleasePrefix = "2018.05.07.00270";
        public const string CurrentRelease = ReleasePrefix;     }
}

Snippet

[assemblyAssemblyVersion(mertens3d.hatch22.fuzzyBunny.Constants.CurrentRelease)]

  

Message 27 of 38

Anonymous
Not applicable

@mertens3d

 

Yep sounds like we have more or less the same approach. Interesting that just changing the AssemblyVersion works for you. When I tried changing only the AssemblyVersion (keeping the AssemblyName the same) I found that Revit would only load one version (whichever is loaded first) and then potentially raise an exception because some other modules dependent on a different version of the assembly are now missing types, for example (if the more recent version lacked a class that was present before). This wouldn't be an issue I guess if you're not debugging a dll that is shared by other addins that are loaded at the same time you're debugging a new version. I found that when deploying addins that have a common dll but different version of it, the only way to ensure both versions would be loaded is to have the AssemblyName be different. In my case a version number as a part of the name.

 

Incidently, how well does gulpjs integrate with visual studio, esp. C# projects? Sounds like its quite useful for managing pre-build tasks...

 

I am modifying the AssemblyName property before build but I couldn't put that script in the pre-build section of the project (msbuild seems to use a cached version of that property at that point in the build unfortunately).

0 Likes
Message 28 of 38

jeremytammik
Autodesk
Autodesk

Dear all, @mertens3d and @Anonymous,

 

Very cool and reassuring indeed to hear that you have a working solution.

 

If you do clean it up and make it portable, I would love to publish it on the blog for easy reading, reuse and posterity.

 

I hope that is possible. Just let me know when you think a state of info suitable for publication has been reached.

 

Thank you!

 

Cheers,

 

Jeremy

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 29 of 38

mertens3d
Enthusiast
Enthusiast

@Anonymous Gulp is the best thing since sliced bread! I just started using it a few months ago, so I have a long way to go.

It integrates really well with VS. Just install node, install Gulpjs and you're off and running. There are several ways you can trigger it. You can bind it to different build steps, run it manually, but the coolest is the 'watch'. You have it automatically watch whichever files you specify. If one of them changes that will trigger your function of choice.

 

As far as dll version go...yes Revit (or windows) does not like to have multiple dll's of the same name (or possibly GUID) running. I have to uninstall any version of my app that are running before I can debug. I also need to make sure that the 'release' build has been cleaned. If there are binaries laying around there either vs won't be able to attach to revit or it will crash.

 

@jeremytammik thank you for helping on this. If I come up with a more refined method I will try to remember to post it here.

0 Likes
Message 30 of 38

mastjaso
Advocate
Advocate

@jeremytammikwrote:

Dear all, @mertens3d and @Anonymous,

 

Very cool and reassuring indeed to hear that you have a working solution.

 

If you do clean it up and make it portable, I would love to publish it on the blog for easy reading, reuse and posterity.

 

I hope that is possible. Just let me know when you think a state of info suitable for publication has been reached.

 

Thank you!

 

Cheers,

 

Jeremy

 


While this is undeniably awesome and helps alleviate some of the development pain, I'd like to reiterate that this is still a workaround, and a fix (or open sourcing) of the Add In Manager is what is really needed. Adding a bunch of extra build requirements should be completely unnecessary and just complicates efforts to work collaboratively or with continuous integration and build servers, not to mention fudging version numbering is not ideal for a variety of reasons.

 

Again, thank you very much to everyone for these workarounds, but I want to reiterate that these are just workarounds, and this is still a major issue that Autodesk should fix. Alternatively, if Autodesk lacks the engineering resources to fix this in a timely manner, it should be open sourced so that we can fix it. I'm willing to bet that the people in this thread could have fixed this problem thrice over in the time they've spent changing version numbers and coming up with complicated workarounds.



 

0 Likes
Message 31 of 38

Anonymous
Not applicable

@mastjaso

 

I'm with you on wanting an open sourced version of the addin manager made available.

 

However the fundamental problem comes back to how the windows / .NET dll loader works, and is somewhat related to the old 'DLL Hell' of the native windows loader. I believe any plugin architecture running on windows that relies on loading plugin dlls into the same 'appdomain' of the same process will enounter the problem of dll versioning and the inability to unload a dll once it is loaded (and hence this is why the version numbering hacks are necessary). I believe that in any case a pre-build step of at least updating the version numbers in the assemblies will be necessary if they are to be loaded into the process as distinct from previous builds. Since .NET won't let you unload these dlls I can't see another viable workaround to debugging fresh builds of dlls in a live process (without restarting it).

 

Actually you can unload Dlls if they reside in a different AppDomain but that has its own set of complications (marshalling function calls and data between appdomains in the same process).

0 Likes
Message 32 of 38

Anonymous
Not applicable
0 Likes
Message 33 of 38

mastjaso
Advocate
Advocate

Ah, I didn't realize it was a general Windows/.Net issue, though that does make sense given some of the other issues / weirdness that comes with running in the same app domain. In that case I should walk back some of my criticism of Autodesk, my irritation just got the better of me. Thanks for the link!

0 Likes
Message 34 of 38

jeremytammik
Autodesk
Autodesk

Please note a continuation of this discussion, a development issue raised with the Revit development team and the workaround description in the follow-up thread:

 

https://forums.autodesk.com/t5/revit-api-forum/revit-2019-addin-manager-cannot-load-external-dll/m-p...

 

Cheers,

 

Jeremy

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Message 35 of 38

jeremytammik
Autodesk
Autodesk

Dear all,

 

I am sorry to say that the development team are unable to fix this issue.

 

They say:

 

Given the situation that the Add-In Manager code has not been touched for many years, the only possible factor which may contribute to the different behaviours between Revit 2018 and Revit 2019 is the version of .NET framework and the configuration files.

 

However, we can't rollback to 4.5, and, based on the team schedule, we will not be able to spend more effort on resolving the config conflicts.

 

We are therefore forced to close the issue REVIT-129984 [Addin Manager: auto unload DLLs before reloading them -- 13857937, 14267353] as 'Won't Fix' and 'Workaround Provided'.

 

If anything more remains to be said about this, please let us continue this discussion in the follow-up thread:

 

https://forums.autodesk.com/t5/revit-api-forum/revit-2019-addin-manager-cannot-load-external-dll/m-p...

 

Thank you!

 

Cheers,

 

Jeremy

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 36 of 38

mastjaso
Advocate
Advocate

@mertens3d@matthew_taylor@Anonymous

 

I have just added open sourcing the Add In Manager as an idea to the Ideas portal! It can be voted on here:
https://forums.autodesk.com/t5/revit-ideas/open-source-add-in-manager/idi-p/8049456

Message 37 of 38

jeremytammik
Autodesk
Autodesk

Dear Jason and all concerned,

 

Thank you very much for the engagement and enthusiasm.

 

The development team reacted to your renewed input and answer:

 

The only variable among 2017, 2018, 2019 is the .NET version and its related configurations, so we still believe this is the root cause.

 

We talked with other developers before and thought that the behaviour in 2019 is correct:

 

.NET should not reload the new assembly automatically, since there is already one with the identical signature in memory.

 

The best practice of solving this issue would be to load an add-in into a separate AppDomain; when reloading, the old AppDomain gets unloaded first and a new one will then be created to hold the add-in.

 

I personally am very much in favour of open sourcing AIM to let the community deal with it, but in the end,  this should be decided by the product managers.

 

I really am sorry to hear that this is continuing to cause problems for you.

 

A surprising number of alternative approaches have been proposed and implemented, with surprisingly differing rates of successful reuse by other developers.

 

In case you are not aware of them, have a look at the approaches for implementing Edit and Continue, Debug without Restart, and Live Development suggested in The Building Coder topic group:

 

http://thebuildingcoder.typepad.com/blog/about-the-author.html#5.49

 

As said, the best way forward is probably to submit a wish list item for this, or two:

 

  • Development team modifies AIM to load add-in into a separate AppDomain and enable reload as suggested above.
  • Open source AIM to enable community to fix it.

 

Lots of votes will help drive it forward fast.

 

Thank you!

 

Best regards,

 

Jeremy

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 38 of 38

mastjaso
Advocate
Advocate

The only variable among 2017, 2018, 2019 is the .NET version and its related configurations, so we still believe this is the root cause.

 

We talked with other developers before and thought that the behaviour in 2019 is correct:

 

.NET should not reload the new assembly automatically, since there is already one with the identical signature in memory.

 

The best practice of solving this issue would be to load an add-in into a separate AppDomain; when reloading, the old AppDomain gets unloaded first and a new one will then be created to hold the add-in.

 

Well in regards to .NET version it's possible that it came with the update to .NET 4.5, but I'd stress again that this issue exists in at least Revit 2016, 2017, 2018, and 2019 (unfortunately I can't test going farther back), so I don't believe it's anything specific to .NET 4.7.

But in regards to the behaviour being correct and not loading a new version into memory, I understand why .NET behaves that way it does but isn't the whole purpose of the addin manager to avoid that in the first place? Its raison d'etre is to load our Addin DLLs into Revit's AppDomain (or a separate AppDomain with access to the API) and then unload them, so that we can keep testing our Addin without restarting Revit. However the AIM is doing this, it's successfully doing it with multiple versions (with the same version number) of our primary addin DLLs, the issue is just that it doesn't seem to unload and reload the dependent DLLs that these rely on.

But again, thank you for the support and feedback from the team, and I do hope that the AIM gets open sourced! If nothing else I think it would be an enlightening look into the world of AppDomain and .NET management!

0 Likes