ExecuteAssembly: Slightly Misleading API

I'm posting this to save someone else an hour or two worth of work. Awhile back I was working on a problem where I needed to dynamically create new AppDomains in a given client application, where in each new AppDomain I needed to load an assembly. There are a few different ways to accomplish this task, and one of the ways I investigated was using ExecuteAssembly.

To call ExecuteAssembly, you first need to get a reference to an AppDomain object, by either getting the current AppDomain (AppDomain.CurrentDomain) or by creating a new AppDomain (AppDomain.CreateDomain). Once you have that, you simply invoke the ExecuteAssembly method on the AppDomain object, as such:

AppDomain newDomain = AppDomain.CreateDomain(“NewDomain“);
newDomain.ExecuteAssembly(“SomeAssembly.exe“);

Notice the extension of the assembly that is passed to the ExecuteAssembly method: it's an EXE, not a DLL. I kept running into problems because I wanted to dynamically load DLL assemblies and execute the stuff inside them. For those unaware, there is one primary difference between an EXE and a DLL: EXEs have entry points, DLLs do not (more on that later). Once I remembered that little fact, I realized ExecuteAssembly would not work in my situation.

My issue here is I feel the name of the ExecuteAssembly method is a little misleading. Afterall, an EXE written in .NET and a DLL written in .NET are both assemblies. So it's easy to see how the name ExecuteAssembly could be mistaken as something that can execute *any* .NET assembly type. And the exception that gets raised is a COMException, which is also a bit misleading. Why doesn't ExecuteAssembly throw an InvalidAssemblyTypeException or something like that? That makes more sense to me.

I also went back through some of the MSDN documentation and although it does say “... assembly begins executing at the entry point specified ...“, it does not explicitly state that ExecuteAssembly will not work with DLLs. I know it seems very much like a minor detail, but I think having that in the documentation would help clear up the confusion of the method name itself. Or it could be that I simply forgot about entry points for an hour or so and decided to blog about it.

As for entry points, how would a developer know that DLLs do *not* have entry points (yes, there are plenty of devs unaware of entry points)? Where would they find that information? I mean, it's not really documented or explicitly stated anywhere, at least no place that I can remember at this moment (if there is, please comment so I can refer people to it). The answer is in the IL.

To see this, create a new Windows application project in VS.NET, compile it, then open up the assembly with ILDASM. Navigate to the Main method and view its IL. The first thing you'll see is .entrypoint. Now, go to the project properties and change it's output type from Windows Application to Class Library. Recompile, open in ILDASM, and look at the IL for the Main method again. Notice the .entrypoint line is gone, yet all the other IL is exactly the same. Above all else, that's the difference between EXEs and DLLs.

Print | posted on Saturday, May 28, 2005 10:28 PM

Feedback

# re: ExecuteAssembly: Slightly Misleading API

left by Randy Bourgeois at 6/23/2005 7:11 AM
I am attempting to do the same thing. I need to load DLLs into an AppDomain because I need to specify the configuration file for each DLL (i.e. MyLibrary.dll.config). Have you found another approach to the load a Library assembly into an AppDomain, and execute methods in the Library assembly?

I looks to me like there are ways to load the assembly into the AppDomain, but the classes in the library must be derived from MarshalByRefObject because remoting is necessary to communicate between AppDomains.

Any thoughts?

# re: ExecuteAssembly: Slightly Misleading API

left by Dave at 6/23/2005 7:22 AM
Randy - a couple questions for you:

1) Are you trying to load class libraries into an already existing AppDomain, or are you trying to load each one into its own AppDomain that you'll create on the fly?

2) What are you passing between AppDomains? Certainly not the assemblies themselves. Do you mean you need to simply pass data between AppDomain? In which case the type you're passing back and forth needs to inherit from MarshalByRefObject.

# re: ExecuteAssembly: Slightly Misleading API

left by Randy Bourgeois at 7/25/2005 7:31 AM
Basically, I need to load a number of DLLs into an executing application, and execute methods on the classes in the DLLs using reflection. The DLLs and methods are configurable.

Here's the rub: These DLLs depend on the existence of an application config file. So, I would like to be able to load each of the DLLs with their own config file (i.e MyAssembly.dll.config). For example, many of the DLLs rely on the enterprise application blocks which are highly configurable through config files.

# re: ExecuteAssembly: Slightly Misleading API

left by Dave at 7/25/2005 7:35 AM
Randy - Check out my blog post on that from a while back:

http://loudcarrot.com/Blogs/dave/archive/2004/06/09/269.aspx

# re: ExecuteAssembly: Slightly Misleading API

left by thedax at 4/28/2006 3:10 AM
Good one, Dave.

I more or less need to do what you say, i.e. load assemblies (DLLs) in their own appdomain and create instances there. The matter is that I want to instance objects whose type is unknown at compiletime, so I need to reflect it at runtime.

typeName = GetTypeFromAssembly(assemblyName); // loads an assembly in a "foo" domain and uses reflection to read the exact type

AppDomain newDomain = AppDomain.CreateDomain("bar", null, appDomSetup); // another domain to create instances of the reflected type

object objectInstance = newDomain.CreateInstanceAndUnwrap(assemblyFileName, typeName); // create an instance of the reflected type, which is for sure both [Serializable] and derived from MarshalRefByObject

Here's what I get:

An unhandled exception of type 'System.TypeLoadException' occurred in mscorlib.dll

Additional information: Could not load type <reflected type> from assembly <name of dll without extension>, Version=1.0.2309.19164, Culture=neutral, PublicKeyToken=null.

Any clue?
Comments have been closed on this topic.