none
Problem of ReflectionOnlyLoadFrom and ReflectionOnlyLoad? RRS feed

  • Question

  • We have an application (We call it PostBuildStep), this application reflects some target asssemblies and gets some info from attributes of exported types in these assemblies. For some reason we can't use LoadFrom and Load methods, so in our implementation of PostBuildStep we use ReflectionOnlyLoadFrom and ReflectionOnlyLoad. Let's say our PostBuildStep uses ReflectionOnlyLoadFrom to load AssemblyA (In private folder not in GAC), then PostBuildStep tries to get all it's exported types, normally at this point AssembyA's dependencies are needed, but different from LoadFrom ReflectionOnlyLoadFrom won't automatically load AssemblyA's dependencies for us. So before we use ReflectionOnlyLoadFrom to load AssemblyA, we get the current domain, and we register a event handler on ReflectionOnlyAssemblyResolve even of current AppDomain, in this event handler we first try load AssemblyA's dependencies with ReflectionOnlyLoad method (it's dependencies may stay in GAC), if ReflectionOnlyLoad fails we will try to use ReflectionOnlyLoadFrom to load it's dependencies at same locate of AssembyA. Code snippet below is some sample code:

    var currentDomain = AppDomain.CurrentDomain;
    currentDomain.ReflectionOnlyAssemblyResolve += ReflectionOnlyAssemblyResolveHanlder;var binaryFiles = Directory.GetFiles(_environment.IntermediateDtmTargetDirectory);
    foreach (var binaryFile in binaryFiles)
    {
    var assembly = Assembly.ReflectionOnlyLoadFrom(binaryFile);
            var assemblyTypes = assembly.GetExportedTypes();

             ......

    }

    private Assembly ReflectionOnlyAssemblyResolveHanlder(Object sender, ResolveEventArgs args)
    {
          Assembly loadedAssembly = null;

          try
          {
                    // Here we first try to load the dependency assembly from GAC, 
                    // if it doesn't exist in GAC then we should try to load it from IntermediateDtmTargetDirectory.
            loadedAssembly = Assembly.ReflectionOnlyLoad(args.Name);
            }
            catch(FileNotFoundException)
            {
                    
             }

             if (loadedAssembly == null)
             {
                 var index = args.Name.IndexOf(',');
                 var assemblyName = args.Name.Substring(0, index);
                 assemblyName = assemblyName + ".dll";
                 assemblyName = Path.Combine(_environment.IntermediateDtmTargetDirectory, assemblyName);

                    loadedAssembly = Assembly.ReflectionOnlyLoadFrom(assemblyName);
              }

              return loadedAssembly;
     }

    The code works well while AssemblyA is based on FrameWork3.5 (CLR2), but it doesn't work if AssemblyA is based on Framework4(CLR4), when assembly.GetExportedTypes() being called the TypeLoadException be thrown with the error message "Method 'GetIcon' in type 'Vendor.ModbusDemoDevice.Dtm.Configuration.DtmConfiguration' from assembly 'Vendor.ModbusDemoDevice.Dtm.Configuration, Version=1.0.0.0, Culture=neutral, PublicKeyToken=2610f61b2927af74' does not have an implementation.", Of course we implemented GetIcon (it's a method of InterfaceA in another assembly). I've already checked the version of the assembly that contains InterfaceA, the version is correct (Plus this works fine if AssemblyA is based on Framework3.5 CLR2),  by the way our PostBuildStep application is based on Framework4(CLR4). What's the possible problem?

    Thanks in advance.

    Thursday, December 20, 2012 11:21 AM

Answers

  • Find the solution, the main difference between ReflectionOnlyLoad and Load is Load method will apply versioning policy, but ReflectionOnlyLoad won't. So the solution is call AppDomain.ApplyPolicy before call ReflectionOnyLoad. Hopefully this can help those people that meet similar problem.
    • Marked as answer by SZ-BlueNight Friday, December 21, 2012 7:47 AM
    Friday, December 21, 2012 7:47 AM

All replies

  • Find the cause, in our AssemblyA there is a classA, it implements the interfaceA that in AssemblyB. When our PostBuildStep loads AssemblyA with ReflectionOnlyLoadFrom, it's dependencies will also be loaded in ReflectionOnlyAssemblyResolve event handler. AssemblyA has two dependencies, one is System.Drawing, the other is AssemblyB. AssemblyB is based on CLR2, and AssemblyB  also has a dependency of System.Drawing(Version 2.0.0.0). When AssemblyA is based on CLR2, it depends on System.Drawing(Version2.0.0.0), so everything works well. But when AssemblyA based on CLR4, it depends on System.Drawing(Version4.0.0.0). So there will be two System.Drawing with different version be loaded into ReflectionOnlyLoadContext. And the interfaceA uses class Icon in System.Drawing(Version2.0.0.0), and ClassA uses class Icon from System.Drawing(Version4.0.0.0), this cause the exception messages

    My questions is why it works when we use LoadFrom to replace ReflectionOnlyLoadFrom? Based on my understanding, even we use LoadFrom, two different version of System.Drawing assembly will still be loaded into Default Load context. Why Default Load context can handle such problem? Why ReflectionOnlyLoadContext can't? Any workaround? Note for some reason we can't use LoadFrom and Load.

    Thanks.

    Friday, December 21, 2012 3:24 AM
  • Find the solution, the main difference between ReflectionOnlyLoad and Load is Load method will apply versioning policy, but ReflectionOnlyLoad won't. So the solution is call AppDomain.ApplyPolicy before call ReflectionOnyLoad. Hopefully this can help those people that meet similar problem.
    • Marked as answer by SZ-BlueNight Friday, December 21, 2012 7:47 AM
    Friday, December 21, 2012 7:47 AM
  • Hi sz,

    Thank you for posting your solution here. It will be very benefit to the other community members.

    Best regards,


    Mike Feng
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Friday, December 21, 2012 7:49 AM
    Moderator