1

I have a .Net4 assembly which exposes an abstract, base class. In that same assembly, I have some code which reflects over all the files in a folder to build up a list of classes inheriting that base class. Here's the salient routine

private JsonTextWriter GetAvailableServices(JsonTextWriter writer, string path)
{
    try
    {            
        writer.WriteStartArray();
        writer = new DirectoryInfo(path).GetFiles(FileFilter)
                                        .Where(f => IsAssembly(f.FullName))
                                        .Select(f => Assembly.LoadFile(Path.Combine(path, f.Name)))
                                        .SelectMany(a => GetLoadableTypes(a))
                                        .Where(p => typeof(ServiceProxy).IsAssignableFrom(p) && !p.IsAbstract)
                                        .Select(a0 => new { Instance = Activator.CreateInstance(a0), ClassName = a0.ToString() })
                                        .Aggregate(writer, (s, v) =>
                                        {
                                            s.WriteStartObject();
                                            s.WritePropertyName(ClassnameLabel);
                                            s.WriteValue(v.ClassName);
                                            s.WritePropertyName(DescriptionLabel);
                                            s.WriteValue(((ServiceProxy)v.Instance).Description);
                                            s.WriteEndObject();
                                            return s;
                                        });                
    }
    catch { Exception ex; }
    finally
    {
        writer.WriteEndArray();                
    }

    return writer;
}

private IEnumerable<Type> GetLoadableTypes(Assembly assembly)
{            
    try
    {
        return assembly.GetTypes();
    }
    catch (ReflectionTypeLoadException e)
    {
        return e.Types.Where(t => t != null);
    }
}

I have a unit test which runs this code, targeting a specific folder, and it all works fine returning a list of classes inheriting the base class as JSON.

The above code sits in an assembly which is to be invoked from a COM (VB6) component. If I now invoke this same code from COM, targetting the same folder which the unit test targets, I get the reflection error and the loader info reports that it can't load the assembly which contains the above code. This only occurs in the GetLoadableTypes routine on the GetTypes() call when I am reflecting over an assembly which contains classes which do inherit the base class.

It sounds almost like a re-entrancy issue which only arises when COM is involved. I guess I could put the abstract base class into another assembly but wondered if there was something else going on.

Any explanation or pointers obviously gratefully received

Error Message:

ReflectionTypeLoadException "Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information."

and in the LoaderExceptions:

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

EDIT1: I changed things around a bit to extract the base class into its own assembly and am still getting the same error. Perhaps relevant, is that I have atest assembly which contains 3 classes inheriting the base class. I get 3 LoaderExceptions (all the same as reported above. I assume 1 for each class.

Simon Woods
  • 905
  • 1
  • 6
  • 13

2 Answers2

1

It may also happen when the assembly is locked by a process. Both of Assembly.LoadFile and Assmebly.LoadFrom methods lock the assembly and if you call this method more than one in a process, it is possible to get this exception on second call.

To avoid lock, you need to change this line

    .Select(f => Assembly.LoadFile(Path.Combine(path, f.Name)))

with

    .Select(f => Assembly.Load(File.ReadAllBytes(Path.Combine(path, f.Name))))

it will work if all dependent assemblies are located in directories where you are traversing, otherwise you can check System.Reflection.Assembly.LoadFile Locks File and Loading Assembly to Leave Assembly File Unlocked

Mutlu Kaya
  • 129
  • 7
0

The problem was with this line

.Select(f => Assembly.LoadFile(Path.Combine(path, f.Name)))

It actually should have been

.Select(f => Assembly.LoadFrom(Path.Combine(path, f.Name)))

Since LoadFrom loads dependencies as well. I assume that when running unit tests, the dependencies must have already been loaded.

Simon Woods
  • 905
  • 1
  • 6
  • 13