Home > Enterprise >  Intermittent TypeLoadException when calling Assembly.GetType - Method in type from assembly does not
Intermittent TypeLoadException when calling Assembly.GetType - Method in type from assembly does not

Time:03-08

In my project, there is an abstract base class with an abstract method. We generate implementations based on a schema and later load these by reflection with Assembly.LoadFrom and then call Assembly.GetType to get a concrete implementation of an interface which is defined in yet another DLL.

The structure of the different projects (DLL files):

  1. Schema - Containing type definition
  2. Base - Has the base class shared by all generated implementations
  3. Generated - A generated type that implements the abstract base class from Base and the interface from Schema.
public interface IExample 
{
   //Some methods here, irrelevant to the problem
}
public abstract Base 
{
    protected abstract void SomeMethod(SomeType someArg); //This method is the method the exception specifies, but I suspect it's only because it's the first one in the file.

    //More methods like the above, and some non-abstract/virtual methods too
}
public class Generated : Base, IExample
{
    protected override void SomeMethod(SomeType someArg)
    {  
        //Some implementation here
    }
    
    //More content here, not all of it being from either the interface or the Base type

}
var asm = Assembly.LoadFrom(path);
asm.GetType("SomeNameSpace.Generated"); //This is where it fails

This worked fine until the Base project was updated in an unrelated area and its version advanced.

The generated implementation is being requested by the interface type it implements. (Generics are involved in the type definition, not sure if that's really relevant)

Now normally this would be a simple case of "Oh you just need to re-compile it and include it again" but the exciting part is that this only sometimes fails!

Roughly half the time, it just works. The other half, it throws the TypeLoadException arguing the method doesn't have an implementation. Normally I'd expect it to always fail, but that's not the case.

Of course, including the newly compiled Generated DLL avoids this entirely. But I'm looking to be able to update both the Schema and Base projects without requiring the whole thing. (It's for 'service pack' style software updates only containing the relevant files)

Just to be clear, none of the involved types were modified. No "Oh I just added an optional argument to a method so it's the same method" mistakes.

The only changes are in other parts of the files. Base is in a big DLL with lots of unrelated utility in it. Base, IExample, and the resulting Generated are still exactly the same. If it was some version resolution causing havoc, I'd expect problems.

This is sadly not a simple small project I could pack up into a reproducible example, but a rather complicated program with many layers and patterns. I'm not sure I could reproduce this if I tried, I'm relying on it failing when the program starts loading things and calling code. (The relevant reflection code that creates an instance of Generated)

The exception message looks like this: (names changed to match example code, and yes its assembly version is 0.0.0.0)

System.TypeLoadException: Method 'SomeMethod' in type 'SomeNameSpace.Generated' from assembly 'SomeNameSpace.Generated, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' does not have an implementation.
   at System.Reflection.RuntimeAssembly.GetType(RuntimeAssembly assembly, String name, Boolean throwOnError, Boolean ignoreCase, ObjectHandleOnStack type)
   at System.Reflection.RuntimeAssembly.GetType(String name, Boolean throwOnError, Boolean ignoreCase)
   at SomeMoreOfOurOwn.CallingTheReflection.AndFailing(Factory factory)

As mentioned, this is a case where trying the same thing and hoping for different results works, because this issue doesn't happen half the time. (And not due to the code not being called, the codebase is built on this pattern for everything)
The only predictable thing is that it always fails on the same thing, but I think that's just because it's deterministically doing that one thing first amongst all of the non-updated generated files.

This is a .NET Framework 4.7.1 project.

CodePudding user response:

We found one suspect. Apparently the fact we also load Base's DLL by reflection via AssemblyResolve it might cause this issue when there's a version mismatch because it's also directly referenced by another directly referenced assembly.

We've only got tentative proof of this being the matter, but it's the best hunch we've got.

So in conclusion, avoid doing whatever it is we're doing in our project.

  • Related