C# - Returning Value From a Method in Another AppDomain
Asked Answered
I

3

5

I have a scenario in which I am adding DLLs to the GAC from actions in my C# code. I then need to do an Assembly.Load on the newly added DLL. However, since the DLL wasn't in the GAC when the process started, it returns null.

So, I see that code can be run in a different AppDomain, which would result in the DLL being available from the GAC in the separate AppDomain.

How can I return the value from the other AppDomain to my main thread?

I simply want to run:

var type = Assembly.Load(assembly).GetType(className);

And have it return from the other AppDomain to my main thread.

Irade answered 26/9, 2012 at 22:17 Comment(1)
have you tried this using reflection..? for example Type t = typeof(YourNamespace.YourClass); string assemblyQualifiedName = t.AssemblyQualifiedName; Type type = Type.GetType(assemblyQualifiedName, false, true); // type will not be nullKariekaril
G
10

You'll have to play a little with .NET Remoting. Your objects loaded on the other AppDomain will need to derive from the MarshalByRefObject class (http://msdn.microsoft.com/en-us/library/system.marshalbyrefobject.aspx).

Just to save time, here's the code from that link:

using System;
using System.Reflection;

public class Worker : MarshalByRefObject
{
    public void PrintDomain() 
    { 
        Console.WriteLine("Object is executing in AppDomain \"{0}\"",
            AppDomain.CurrentDomain.FriendlyName); 
    }
}

class Example
{
    public static void Main()
    {
        // Create an ordinary instance in the current AppDomain
        Worker localWorker = new Worker();
        localWorker.PrintDomain();

        // Create a new application domain, create an instance 
        // of Worker in the application domain, and execute code 
        // there.
        AppDomain ad = AppDomain.CreateDomain("New domain");
        Worker remoteWorker = (Worker) ad.CreateInstanceAndUnwrap(
            Assembly.GetExecutingAssembly().FullName,
            "Worker");
        remoteWorker.PrintDomain();
    }
}

/* This code produces output similar to the following:

Object is executing in AppDomain "source.exe"
Object is executing in AppDomain "New domain"
 */
Germaun answered 26/9, 2012 at 22:56 Comment(1)
Worked perfectly. Thanks so much.Irade
P
5

Generally speaking objects that are shared between app domains must derive from MarshalByRefObject. You will have an issue with returning the actual type, if the type is defined in the dynamically loaded DLL. Since the type is not available in your AppDomain of your main thread. You may be able to cast it to a base class that is available in a DLL already loaded in the main application thread.

What i have done in the past was to create an interface for the class I wanted to share between app domains. Obviously the interface would be in some base dll shared by both the main application and the dynamically loaded dll.

in your base dll you can declare your interface:

public interface IMyBaseInterface
{
     void DoStuff();
}

Then in the dynamically loaded dll, the class implements the interface and derives from MarshalByRefObject:

public class MyDynamicClass : MarshalByRefObject, IMyBaseInterface
{
    public void DoStuff()
    {
        Console.WriteLine("Hello other app domain!");
    }
}

The code to load an instance of the object would look like this:

AppDomainSetup ads = new AppDomainSetup();
AppDomain appDomain = AppDomain.CreateDomain(_appDomainName, null, ads);
IMyBaseInterface myObj = (IMyBaseInterface) appDomain.CreateInstanceAndUnwrap(assemblyName, typeName);
myObj.DoStuff(); 
Potential answered 26/9, 2012 at 23:3 Comment(1)
I was trying to set public properties for my dynamically created instance which already implemented an custom interface. But your answer helped me because now I'm just calling a method inside the Interface and let the dll itself set the public properties :) thanks again!Aurist
C
2

When you "leak" objects through AppDomain boundary (implicitly, or explicitly as in your case) the implementing assembly must be loaded into both domains.

As you've already noticed assembly the was not in the GAC on first request to a class from the assembly in the AppDomain will not be loaded to the AppDomain (fact that it is not GAC is cached till end of AppDomain lifetime since it is not expected for assembly to magically show up in the GAC).

I think you have to keep classes from newly GAC'ed assembly in that new AppDomain.

Chara answered 26/9, 2012 at 23:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.