Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exception on receiving Assembly reference from another AppDomain

I am loading all DLLs from a specific "extensions" directory in a new AppDomain to get some Reflection related information out of those.

This is what I'm trying:

I created a new library AssemblyProxy in my solution which just has this class:

public class AssemblyProxy : MarshalByRefObject
{
    public Assembly LoadFile( string assemblyPath )
    {
      try
      {
        return Assembly.LoadFile( assemblyPath );
      }
      catch
      {
        return null;
      }
    }
}

I make sure this DLL is present inside my "extensions" directory. Then I use the following code to load all assemblies from "extensions" directory into the new AppDomain.

foreach( string extensionFile in Directory.GetFiles( ExtensionsDirectory, "*.dll" ) )
{
        Type type = typeof( AssemblyProxy.AssemblyProxy );
        var value = (AssemblyProxy.AssemblyProxy) Domain.CreateInstanceAndUnwrap(
            type.Assembly.FullName,
            type.FullName );

        var extensionAssembly = value.LoadFile( extensionFile );

        types.AddRange( extensionAssembly.GetTypes() );
}

Some DLLs do get loaded successfully but on some DLLs an exception is thrown like this:

Could not load file or assembly 'Drivers, Version=2.3.0.77, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.

EDIT: The exception is not thrown in the new AppDomain. The DLL gets successfully loaded in the new AppDomain. The exception gets thrown as soon as the assembly reference is returned to the main/calling AppDomain. Does the main/calling AppDomain try to load the assembly on its own on just receiving the reference?

Thanks.

like image 741
user1004959 Avatar asked Jan 02 '13 14:01

user1004959


1 Answers

You should not return an Assembly object from the new AppDomain because this will only work if you main AppDomain has access to those assemblies which it does not since the assemblies are located in a directory that:

  • is not the AppDomain's base directory (AppDomain.BaseDirectory),
  • is not in the directories specified in the AppDomain's relative search path (AppDomain.PrivateBinPath)

One way to avoid this to follow the leppie's comment and:

  1. Create a serialized type that includes the minimum information you need from the Assembly object.
  2. Add this type to new assembly that both AppDomain's have access to. The simplest way to do this by adding it to the GAC.

Another approach would be to use Mono.Cecil instead of System.Reflection. Mono.Cecil will allow you to inspect assemblies without loading them. For a very simple example look at the second half from this answer.

like image 167
Panos Rontogiannis Avatar answered Nov 02 '22 23:11

Panos Rontogiannis