Executing Code in Another AppDomain


The easiest way to run code in another appdomain is to execute an assembly entrypoint using AppDomain.ExecuteAssembly() or (starting in v2.0) AppDomain.ExecuteAssemblyByName().


If you want to execute a method other than an assembly entrypoint, call AppDomain.CreateInstance() on a type which extends MarshalByRefObject. Then, call a method on that type which does the Assembly.Load() or whatever work you needed to do there.


An easy way to get that to work is to have your MarshalByRefObject type be in your process exe. Then, call AppDomain.CreateInstanceFrom(Assembly.GetExecutingAssembly().Location, MBROtypeName).


Be sure to not pass any Type/Assembly/etc. instances (besides your MarshalByRefObject type) back to the original appdomain. If you do, it will cause those assemblies to be loaded into the original appdomain. If the appdomain settings are different between the two appdomains, those assemblies may not be loadable there. Plus, even if they are successfully loaded, the assemblies will remain loaded and locked after the target appdomain is unloaded, even if the original appdomain never uses them.


If the reason why you need to pass it back is so that it can interact with some assembly B in that other appdomain, instead, you could pass B to the new appdomain and do all of B’s work there instead of in the original one. For example, for some applications, it’s best if the only work done in the default appdomain is creating the new one and calling CreateInstanceFrom() on it. So, the new appdomain will do all the real work for that application.

Comments (46)

  1. Martin Spedding says:

    Hi, I am curious you mention version 1.2 of the framework. Are you talking about the whidbey release as I thought that was version 2 of the framework.Just curious. By the way good blog lots of useful information.

  2. Suzanne says:

    Thanks! Yes, today, it’s 1.2. We’ll see what it ships as.

  3. Joel Crisp says:

    Thanks! This note has solved a nasty problem we were having loading old serialized data once the assembly version has changed. Now we can create a new AppDomain, run the DLLs in that and use assembly version re-mapping in that AppDomain to override the serialized assembly version! Previously this wasn’t possible as the executing application downloads the dlls on startup so we can’t re-map them in the application config file. (Yes, I know this is dangerous as the fields may have changed, but we need to do it)

  4. Suzanne says:

    Glad to help, but your comment is making me nervous. 🙂 Sounds like you’ve already thought about the risks of using another assembly version. But, I hope that you’re only doing a redirect to a version that is officially ‘compatible’ with the original… If not, please read http://blogs.msdn.com/suzcook/archive/2003/05/30/57159.aspx since version redirects are similar to partial binds.

  5. Suzanne says:

    Martin: Looks like it will be 2.0 instead of 1.2, now, so I updated my entry. 🙂

  6. Kris says:

    Hi, is it possible to implement a simple plugin mechanism in which the parent EXE can host unknown, late bound assemblies in a secondary appdomain, provide callbacks to them (via a standard ‘IPlugin’ interface, and not load them in the host EXE app domain itself?

    If passing types back from a loaded AppDomain means they are implicitly loaded in the host AppDomain this doesn’t sound feasable. I have tried something similar before and the loading issues resulted in abandoning the isolated appdomain model in favor of just loading via reflection.

    Thanks,

    Kris

  7. Kris says:

    Eric Gunnerson’s article here answered my question nicely. Thanks again.

    Kris

    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp05162002.asp

  8. Reg says:

    Hi Suzanne,

    When I do

    AppDomain.CreateInstanceFrom(Assembly.GetExecutingAssembly().Location, MBROtypeName)

    would it result in my current assembly loaded into the AppDomain? It might be an overkill if we only need one type. Do you think it might be better to create a "glue" assembly containing only the MBROtype for this purpose?

    Regards,

    reg

  9. Suzanne says:

    Yes, it would be loaded there. But, assemblies already loaded in the process like that won’t be remapped when they’re loaded into another AppDomain. If you put the type in its own assembly, you’d have to pay additional performance costs of mapping the new file. (Other costs like the time to create a new Assembly instance would be required whether you use a new assembly or the current one.) So, it sounds like you should leave it as-is, unless you have other reasons to have another assembly for it.

  10. Jigar says:

    Suzanne,

    I am trying to load assemblies in the different AppDomain from remote machine. Executable is running on the machine and assemblies are stored on a network machine(with full permissions) . If I try loading these remote assemblies in the same AppDomain (of the executable), everything works fine. But, if I tried to load them in different AppDomain, I get System.IO.FileNotFoundException.

    I tried to use example given in Eric Gunnerson’s article. example works if my assemblies are on local machine. (I think its because example uses MarshalByRefObject (RemoteLoader) in the local executable. Example first creates new appdoamin and create instance of the RemoteLoader in the new domain and then RemoteLoder tried to load assemblies in it.

    I tried to set following

    AppDomainSetup setup = new AppDomainSetup();
    setup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
    setup.ShadowCopyFiles = "true";
    setup.ShadowCopyDirectories = functionDirectory; //remote system

    If I set application base to the remote system(function directory) then my
    CreateInstanceAndUnwrap fails as remoteloder is part of my local executable.

    remoteLoader = (RemoteLoader) appDomain.CreateInstanceAndUnwrap( "SuperGraph", "SuperGraphInterface.RemoteLoader");

    Please Help. What exactly I need to do/ what am I doing wrong?

    Thanks

  11. Suzanne says:

    Always start debugging file loading issues by getting the Fusion log (see http://blogs.msdn.com/suzcook/archive/2003/05/29/57120.aspx ). In this case, I imagine the problem is because the assemblies are loaded by path in the successful appdomain, but loaded by display name in the failing one. That’s a problem when that path does not match the ApplicationBase for that appdomain (because that means that that assembly is not available in the Load context, and your CreateInstance*() call only looks in the Load context).

    If it’s required to load it from that path, consider changing the ApplicationBase (to use the Load context), or using CreateInstanceFrom*() instead (to use the LoadFrom context). See http://blogs.msdn.com/suzcook/archive/2003/05/29/57143.aspx for more info.

  12. Marc Clifton says:

    Hi! The only way that I’ve found to resolve the problems discussed in this thread is to hook the AssemblyResolve event and "manually" load the assembly using the correct path. Creating a separate AppDomain isn’t necessary. In fact, it’s pretty much a no-brainer. Hope that helps.

  13. Suzanne says:

    Using the AssemblyResolve event as a catch-all for binding failures is a hack. It’s cleaner to deploy the app correctly, and use an AppDomain with the appropriate settings. Also, assemblies resolved through the event don’t get the benefits of the Load context – see http://blogs.msdn.com/suzcook/archive/2003/05/29/57143.aspx.

    Plus, keep in mind that the event is only raised after probing has failed, so its perf is not as good as the non-event case when an ApplicationBase is set.

  14. Levi Khatskevitch says:

    Suzanne, I’m trying to use the AppDomain.CreateInstanceFrom method but it returns MarshalByRefObject instead of my type. This happens only when my assembly is located outside of private path of the current domain. The executing assembly itself is loaded using Assembly.LoadFrom method. What could be the problem? Thanks.

  15. Suzanne says:

    Sounds like the assembly failed to load in the current appdomain. It will need to be loadable by display name, in the Load context of the appdomain where the type is Unwrap()’d. (The LoadFrom() is executed in the target appdomain, not the calling one.) My suggestions for making that work are in the blog entry above.

  16. Levi Khatskevitch says:

    Thanks Suzanne, it helped a lot. I’m writting a NAnt task (plugin) that must be loadable from anywhere by the file path. So I can’t just put it into the private path of NAnt.exe (it can’t be in GAC since it refers to other unsigned assemblies of NAnt framework. So I hooked up a CurrentDonain.AssemblyLoad event handler for the duration of the task execution, if requested name matches Assembly.GetExecutingAssembly().FullName, I return Assembly.GetExecutingAssembly(). Perfomance shouldn’t be a problem in my case, However I’m still wondering why doesn’t CLR check if an assembly is aready loaded into the current domain before probing for it on the disk.

  17. Suzanne says:

    You must mean the AssemblyResolve event. It’s not automatically found because resolving to a LoadFrom context assembly would make the Load context order-dependent. The appdomain transition causes the caller of Load() to be deserialization in mscorlib.dll, which is in the Load context. See http://blogs.msdn.com/suzcook/archive/2003/05/29/57143.aspx for more info about the different binding contexts.

  18. I did really mean AssemblyResolve event, sorry my typo. Thanks a lot.

  19. Ryan Gilchrist says:

    Hi Suzanne. Very useful blog for people new to AppDomains (like myself). Is there any way to have COM-callable .NET assemblies load in a separate self-designated application domain? This would be useful for controlling assembly versioning when you don’t have control of the host, like MMC for example. Two MMC snapins might rely on the same assembly, but require different versions. The versions can be kept separate on the file system, but need the snapins to be loaded in separate AppDomains because MMC is one big process.

  20. Karinta says:

    Hi Suzanne,

    As you mentioned i am trying to load a Windows Form Assembly at run time to a seprate AppDomain.

    I don’t want that this Assembly to be loaded in the Caller Domain, so i used the method

    CreateInstanceFromAndUnwrap instead of AppDomain.Load(..)

    // I am passing the Control’s parent through the constructor argument

    Object[] args1 = new Object[] {this};

    MyControl.MyControl Ctrl = (MyControl.MyControl) MyDomain.CreateInstanceFromAndUnwrap("D:TestMyControl.dll",MyControl.MyControl,

    false,BindingFlags.Public,null,args1,null,null,null);

    But when i do this i get an exception thrown "Constructor on type MyControl.MyControl not found.

    If i try to use the CreateInstanceFromAndUnwrap using the two parameters just the assembly and type, the function

    returns me the control object. But when i try to set the Parent of the control using the following

    code

    Ctrl.Parent = this;

    then system throws an exception the message is

    The type System.Windows.Forms.Form+ControlCollection in Assembly System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 is not marked as serializable.

    What am i doing any thing wrong in this both scenarios.

    Or is it advisable to have a design where i can load my Windows Forms Assemblies in to a seprate

    Domain and use, and later unload it.

  21. Pete says:

    Hi Suzanne,

    Thanks for the great information. I’m currently trying to use an AppDomain to isolate "3rd party" plugins from the host application. At present, I create a new AppDomain and load the 3rd party assembly into it, then starting using the appropriate items. What I want to do is detect if anything "blows up" in the foreign assembly, and if so then reload the AppDomain. However, when I get an exception thrown within a test assembly it’s just propogated to the /default/ AppDomain’s UnhandledExceptionEventHandler. Even worse is that the sender object is actually the default AppDomain, not that where the exception occurred. Can you shed any light on this one?

  22. vinay says:

    Hello Suzanne / all,

    I am trying to load an assembly in a new AppDomain (so that I can unload the appdomain later on when it is not needed). I just wanted to know whether there is any performance hit in using AppDomain.CreateInstanceFrom method vs the AppDomain.CreateInstance method? My hunch is that CreateInstanceFrom would be faster when loading a "new" assembly in an appdomain since it does not have to search for the "new" assembly file..any comments?

    vinay

  23. Mattia says:

    I tried to use another AppDomain to avoid the Memory Leak problem with XSLTs containing script code. Temporary assemblies are loaded in the main domain, noway to unload them!

    string assemblyName = "MemoryLeak.Transform, Version=1.0.3.0, Culture=neutral, PublicKeyToken=a738acded1cb795c";

    string type = "MemoryLeak2.Transform.Class1";

    System.Runtime.Remoting.ObjectHandle o = d.CreateInstance(assemblyName, type);

    MemoryLeak2.Transform.Class1 c = (MemoryLeak2.Transform.Class1)o.Unwrap();

    // do the transform

    c.transform(stylesheet, filename);

    AppDomain.Unload(d);

    but assemblies like:

    janzrica, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null

    qpeiskba, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null

    ncgptwtq, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null

    grow in the main appdomain!

    Why?

  24. Mattia says:

    I noticed that in the constructor of the Created class the AppDomain is the 2nd, while I can’t manage to invoke a function with 2 parameters without falling back to the main AppDomain. I also tried this:

    object res1 =

    (o.GetType()).InvokeMember(

    "transform",

    System.Reflection.BindingFlags.Public |

    System.Reflection.BindingFlags.Instance |

    System.Reflection.BindingFlags.InvokeMethod ,

    null,

    o,

    new object [] {stylesheet, filename});

    But the "transform" function gets executed in the main one.

    How to do the trick???

  25. Magnus says:

    This whole system seems very awkward and cumbersome to me. Is anyone actually succeeding in creating plugin systems with runtime reloading?

    I’m trying to load plugin assemblies into an AppDomain. Problem is that objects instantiated from these plugin assemblies generate events which the main program listens to.

    So basically I really need to have real objects on the main-application side.

    Is there not a simple solution to this VERY common need?

  26. wielun says:

    Hi Suzanne. Very useful blog for people new to AppDomains (like myself). Is there any way to have COM-callable .NET assemblies load in a separated d d self-designated application domain? This would be useful for controlling assembly versioning when you don’t have control of the host, like MMC for example. Two MMC snapins might rely on the same assembly, but require different versions. The versions can be kept separate on the file system, but need the snapins to be loaded in separate AppDomains because MMC is one big process.

  27. Amol says:

    HI

    can You give a simple code snippet suppoting your idea of communication between two appdomains?

    This will be of great help

    Thanks

    Amol Wankhede

  28. Stephane G says:

    As Mattia, I tried to use ExecuteAssembly to avoid the memory leak in compilation of XSLTs with scripts, as suggested in article 316775.

    I have a service process repeatedly creating an AppDomain and calling ExecuteAssembly every 30 s, and I noticed another memory consumption.

    I modified the code of the executed assembly to immediatly return, but I loose each time 16, 28 or 40 octets.

    If I just comment out the ExecuteAssembly call, the memory leak disappear.

    Seems that this AppDomain technology not so robust …

  29. learnerplates says:

    Hi Suzanne,

    Like alot of people I’ve being having problems with this, AppDomain.CreateInstanceFromAndWrap.

    I’ve posted on msdn forums http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=660892&SiteID=1

    he post title is "Why does AppDomain.CreateInstanceAndUnwrap(..) work and AppDomain.CreateInstanceFrom(…).UnWrap doesn’t? "

    In there you’ll see my problem.

    Now I’ve forced the AppDomain appBasePath like so, to the location of my assembly and it’s depenencies which I’ve grouped into this one dir:

    AppDomain ad = AppDomain.CreateDomain("Compiling Gravity", null, "file:///C://myproj//Metadata", "file://C://myproj//Metadata", false);

    Now when I try to invoke the function on the remote object using

    Configuration.CompileProxy.Compiler compiler = (Configuration.CompileProxy.Compiler)(ad.CreateInstanceFromAndUnwrap("file:///C:\myproj\Metadata" + "\Configuration.CompileProxy.dll", "Configuration.CompileProxy.Compiler"));

                   

    I get the error

    "Error: Unable to cast transparent proxy to type ‘Configuration.CompileProxy.Compiler"

    Any idea what’s happening?

    As I mentioned in the msdn forum post it all works fine if I put the same assembly into the GAC and create the AppDomain using CreateInstanceAndUnwrap("Configuration.CompileProxy, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1f77dad97b7dc0c2", "Configuration.CompileProxy.Compiler");

  30. La réflection est un des gros points forts de .Net. D’autant plus qu’il est très facile de s’en servir….

  31. There’s no way to unload an individual assembly without unloading all of the appdomains containing it.

  32. I hesitate to talk about this because I don’t want people who don’t know about it to think, "Hey, what’s

  33. So, after checking out the binding context options , you’ve decided to switch your app to use the Load

  34. JWolf says:

    Hey, your blog is a remoting lifesaver. But I ran into an issue that I don’t think there is an easy fix. What I’m doing is writing test case code to exercise a feature component of product where a client in one appdomain calls a remoted interface in another appdomain. The test case code executes in the context of the process and the default appdomain that also hosts the remoted well-known server object. Therefore, for the test case code, I would like to have the test case code create second appdomain, load the assembly which contains the code that a remoted client would utilize to call the APIs of the remoted server object, that I happened to have placed in the same assembly as the test case code, and, finally, from the test case code in the default assembly, using the techniques you talk about here, cause the client test code to execute in the second appdomain (and call back to the server object hosted by the default appdomain). In this test case code, I call: anotherAppDomain.CreateInstanceFromAndUnwrap(…). It returns an object that seems to be fully intact. The problem is that when I try to cast the object to the marshaled type so I can call a method of the marshaled type, I get a “Specified cast is not valid.” exception. I think this is related to what you mentioned in the blog, namely, “…get that to work is to have your MarshalByRefObject type be in your process exe.” My marshaled type is defined in a .dll assembly that is loaded, on-demand, by a entry point .exe assembly. Is there a way around this exception or do I need to re-think the design of  my test case code?

  35. JWolf says:

    BTW, can you call a static class method through a marshaled/proxied (remoted) type? If so, how?

    Thanks!

  36. exe says:

    it works fine in ConsoleApplication, but doesn’t work in asp.net.

               AppDomain dom=AppDomain.CreateDomain(“sandbox”);

               return dom.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().Location,typeof(ScriptRunner).FullName) as ScriptRunner;

    error:

    Could not load file or assembly ‘C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\evaltestsite\bf04395e\92dc3b2f\assembly\dl3\886f40f9\2090c92c_a883c701\EvalTest.DLL’ or one of its dependencies. The given assembly name or codebase was invalid. (Exception from HRESULT: 0x80131047)

  37. Chris Nevill says:

    I have an interesting problem.

    I’m making a .NET plugin which fits into a COM based Media Application (www.jrmediacenter.com)

    The .NET plugin uses Oleg Shilo’s C# Script Engine to provide scripting access to the media application.

    (http://www.codeproject.com/csharp/cs-script_for_CP.asp)

    Initialy I done this by creating new assembly within my application domain, which worked well, however it had problems in that if any threads were used etc then the scripts could not be shut down as assemblys cannot be unloaded.  Looking into this I found I should create a new Application Domain.  It turned out

    Oleg had actually made the work for this easy

    by providing a tool which loaded the scripts in a new domain, using CreateInstanceFromAndUnwrap

    However…. it wouldn’t work from within Media Center.

    It works fine as a standalone application, but if Media Center runs the plugin it comes up with the oh so famous

    “Error: Unable to cast transparent proxy to type….”

    If I use the current domain it’s fine.

    If i run it standalone it’s fine…

    but not in the new domain from Media Center.

    I’ve tried matching up just about every path I can find…

    It’s driving me nuts!

    I’ve been on this now for about 2 weeks getting no where.

    Any thoughts would be appreciated!

  38. dru says:

    it works fine in ConsoleApplication, but doesn’t work in asp.net.

              AppDomain dom=AppDomain.CreateDomain(“sandbox”);

              return dom.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().Location,typeof(ScriptRunner).FullName) as ScriptRunner;

    error:

    Could not load file or assembly ‘C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\evaltestsite\bf04395e\92dc3b2f\assembly\dl3\886f40f9\2090c92c_a883c701\EvalTest.DLL’ or one of its dependencies. The given assembly name or codebase was invalid. (Exception from HRESULT: 0x80131047)

    this is my exact problem too. any suggestions?

  39. Ricardo Adolfo Gonzalez Pineda says:

    Hi – to answer (Executing Code in Another AppDomain )

    i found this option:

    Use something like this:

    string rutaFisicaEnsamblado = typeof (MyClass).Assembly.Location;

    int length= rutaFisicaEnsamblado.IndexOf(“MyAssembly.dll”);

    rutaFisicaEnsamblado = rutaFisicaEnsamblado.Substring(0, length);

    and give that path to your AppDomain’s ApplicationBase and PrivateBinPath

    Vuola!!

    And now i got some other issue i’m trying to solve: it marks the famous “Unable to cast transparent proxy to type” even the class myClass is implementing an IClass and it extends MarshallByRefObject… so, if not your issue I think you got it.

    Regards

  40. Luther says:

    Thanks for this posting. I had left out the MarshalByRef and was debugging why my cross-appdomain objects were executing the calling domain and not the new domain I had created them on… and this fixed it!

  41. jdk99 says:

    I’m getting the FileNotFoundException or the SerializationExceptions when I attempt to register the ResolveEventHandler of my MarshalByRefObject derived class.

    myNewAppDomain.AssemblyResolve += myAssemblyResolver.Resolve;

    // throws FileNotFoundException and complains that the assembly’s fullname cannot be found.

    I kinda get it – since I haven’t added the handler to resolve assemblies, and I’m sending it the  myAssemblyResolver which must be deserialized before use in the other app domain, how is the other app domain going to know how to deserialize it if I haven’t been able to register the handler??

    But of course, that’s ALWAYS the case.  The new app domain is /empty/ until you tell it to run some code, and in order to tell it that, you have to send it something it doesn’t already know!!

    I’ve tried putting the MyAssemblyResolver type in the executing assembly, and I’ve tried putting it in a referenced assembly.  Same basic error either way.

    And I had something similar working just last week without any problems….  It’s got to be something stupid but I’ve been staring at it for hours and hours now.

  42. paul davidson says:

    I have been searching all over for a solution to my app domain problems! And although your blog seems to have a few entries in it that are along the lines of what I’m doing, they don’t exactly match.

    I’m hoping you could send me in the right direction!

    Basically..I have an updater program (say, UpdateService) that will be called, a sort of tool. When I have finished a new version of code for some software I am building, UpdateService will be run, and the user will choose the directory that the new software version is located at. UpdateService will then need to manually go through the whole folder, getting all dll’s, loading them into a temp app domain, to get to the culture of each one, and then unload them when finished.

    Basically so that once the UpdateService has run, it will have an object fully populated with all locations of the files, along with certain details like culture if appropriate.

    I can’t seem to get any of the dll’s loaded into this temp app domain. Always advising me file load exception, or could not find file or one of its dependencies. All the dll’s will be at a location anywhere on a computer, so they will not be in the app base for the UpdateService program.

    The folder that holds the software release, will not be in the same directory or appbase as the UpdateService program.

    Any ideas?