locked
Issue with ReflectionOnlyLoadFrom against assemblies compiled against differing .NET versions. RRS feed

  • Question

  • We came across a strange issue using ReflectionOnlyLoadFrom that appears to be related to the version of the .NET Framework. We found this quite by accident with some tooling we use against our Enterprise application but I'm able to replicate the behavior fairly simply.

    I have a solution with three projects; two class libraries BaseClassLibrary and FormsLibrary and a console application to perform the actual reflection. FormsLibrary references BaseClassLibrary and the issue I'll describe occurs if BaseClassLibrary targets .NET framework versions 2, 3 or 3.5 while FormsLibrary targets .NET framework version 4 or 4.5.

    BaseClassLibrary contains a single class, BaseForm, which inherits from System.Windows.Forms.Form. FormsLibrary contains one class, Form1, which inherits from BaseForm and one interface, IMinimumSize, which defines a single property, MinimumSize, of type System.Drawing.Size.

    The console application first wires up AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve event to a method which simply calls Assembly.ReflectionOnlyLoad on the assembly to be resolved. Next it calls Assembly.ReflectionOnlyLoad specifying a path to the FormsLibrary assembly file. Once loaded it then calls the GetTypes method on the assembly.

    If the target frameworks are set up as previously described, i.e. BaseClassLibrary=2, 3 or 3.5 and FormsLibrary=4 or 4.5, the call to GetTypes throws a ReflectionTypeLoadException with a LoaderException that states "Method 'get_MinimumSize' in type 'FormsLibrary.Form1' from assembly 'FormsLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' does not have an implementation.". Since Form1 inherits from BaseForm which in turn inherits from Form MinimumSize is definitely implemented but ReflectionOnlyLoad is telling a different story.

    If both libraries are set to target any combination of .NET 2/3/3.5 or 4/4.5, e.g. BaseClassLibrary=2 and FormsLibrary=3.5, this exception goes away and GetTypes returns the correct data. The issue also doesn't occur with just any Form properties. We've replicated it with MinimumSize and MaximumSize but found a number of Form properties that have no such issues.


    • Edited by Dane Vinson Tuesday, January 29, 2013 7:35 PM
    Tuesday, January 29, 2013 7:32 PM

Answers

  • What you're observing here is that the assembly itself is part of a type's identity. Specifically in this case, System.Drawing.Size (4.0) is not the same type as System.Drawing.Size (2.0). Your IMinimumSize interface is using the former but the inherited MinimumSize property on BaseForm is using the latter. Form1 cannot therefore implement the interface by inheriting from BaseForm. This isn't normally a problem at runtime because the machine policy will be applied to assembly names before they're resolved, which means your BaseClassLibrary will actually reference System.Drawing (4.0) post-policy at runtime. The reflection-only context does not apply policy so you will need to do this yourself in your ReflectionOnlyAssemblyResolve event handler. See ApplyPolicy for more information.

    HTH

    • Marked as answer by Dane Vinson Wednesday, January 30, 2013 12:14 AM
    Wednesday, January 30, 2013 12:01 AM

All replies

  • What you're observing here is that the assembly itself is part of a type's identity. Specifically in this case, System.Drawing.Size (4.0) is not the same type as System.Drawing.Size (2.0). Your IMinimumSize interface is using the former but the inherited MinimumSize property on BaseForm is using the latter. Form1 cannot therefore implement the interface by inheriting from BaseForm. This isn't normally a problem at runtime because the machine policy will be applied to assembly names before they're resolved, which means your BaseClassLibrary will actually reference System.Drawing (4.0) post-policy at runtime. The reflection-only context does not apply policy so you will need to do this yourself in your ReflectionOnlyAssemblyResolve event handler. See ApplyPolicy for more information.

    HTH

    • Marked as answer by Dane Vinson Wednesday, January 30, 2013 12:14 AM
    Wednesday, January 30, 2013 12:01 AM
  • Excellent. We were theorizing something along those lines but could not see how Size had changed. It seems like a pretty bad idea to change a type but keep it's name and namespace the same. Obviously this is something specific to Size (and probably other types) but not all types. If assembly was part of every type's identity then absolutely every type in the system would fail like this which is definitely not the case. We've been using ReflectionOnlyLoadFrom for years without issue and it wasn't until someone added the MinimumSize property to an older interface that we discovered this issue.

    Thanks for the info.

    Wednesday, January 30, 2013 12:14 AM
  • AFAIK this applies to all types from all assemblies with one exception: mscorlib. You cannot load a version of mscorlib into the reflection-only context that's different to the version in the execution context. In your example, if you renamed the MinimumSize property to Name (of type String) then it would work without applying policy. It's also worth remembering that the 3.0 and 3.5 versions of the framework add new libraries (WPF, WCF, LINQ, etc.) but still rely on the 2.0 runtime and framework, i.e. there are no 3.0 or 3.5 versions of System.Drawing.Size.

    HTH

    Wednesday, January 30, 2013 1:26 AM