Posted on 19. March 2009

Where art thou API Command? – User settings Part 3

As I mentioned in part 1 , using the advanced classes in System.Configuration in Revit API commands won’t run out of the box. That’s a bit of a generalisation. With a standard installation of Revit, an API command that is using System.Configuration’s more advanced classes such as ConfigurationSection will only work from one location. The directory of the Revit executable (Revit.exe). On XP32 this is usually C:\Program Files\Revit Architecture 2009\Program .

You’ll even hear some say you can only utilise any System .NET assembly with Revit commands when the command is in the Revit executable directory. This is not true. In this post I’m going to explain what the problem is and why it’s happening.

In Part 4 of this series I’ll explain how to make Revit commands that suffer these symptoms run from any path. I should add the Autodesk recommended practice is to install your assemblies in the Revit executable directory. I disagree ;-)

What are the symptoms? Because it’s not just System.Configuration commands that suffer from this. There are 2 symptoms that give you a clear indication your command has this issue.

  • Does your command run when in the Revit executable directory, but not when outside the executable directory?
  • Does the command run as a standalone application (in an .exe) but not as a Revit Command?

I’ve suffered these symptoms using System.Configuration, Remoting API’s , Serialisation, and System.Security. And there is probably others as well. What initially makes this hard to diagnose is the error messages (or lack off) and unexplained behaviour of your classes when you run your command, in no way point to the root cause of the problem.  If you find yourself thinking “”I’m sure my code is correct””, trying running it from the Revit program directory if it’s not there already and see if this fixes the problem.

So come on, what is causing this??

In part 1 I talked about AppDomains and how (except VSTA) all commands are loaded into one default AppDomain. The default path of the ApplicationBase for the AppDomain is the Revit executable directory. When Revit parses the Revit.ini and begins loading these assemblies and any referenced assemblies into the default AppDomain, 2 things happen depending on the path of the command to be loaded.

  1. If the assembly is in the GAC or in the Revit executable directory then the Assembly is loaded using the Assembly.Load(<assembly name>) method.
  2. If it anywhere else it is loaded into the AppDomain using Assembly.LoadFrom(<assembly path>). You can read more detailed explanations here and here.

An AppDomain essentially sandboxes your code. As you’ll see from the documentation Load() and LoadFrom() load the assemblies into different AppDomain contexts. This is a really subtle distinction. What is an AppDomain context? Basically it’s another layer of sandboxing or isolation within the AppDomain. Here’s a diagram to try and show what happens:

AppDomain

It is these AppDomain contexts and the sandboxing of your command assemblies and referenced assemblies in either context that can cause commands to fail. If you find you need to run a command from the Revit executable directory then a referenced assembly is taking issue with the fact the assembly is in the LoadFrom() AppDomain context and not the Load() context. The Load() context always contains assemblies from the GAC and at the very least the RevitAPI assembly.

In the next post I’ll explain how to make a command assembly in any directory load into the correct context (Load() context) . I hope this all makes sense. I’ve tried to explain it simply so everyone can understand, if not feel free to post a question. Thanks to the anonymous Autodesk .NET guru “Albert” who initially put me onto Assembly loading when I was trying to figure out why configurations weren’t working.

Comments are closed