Home > Back-end >  Are there specific issues with .NET Core apps and System.Reflection.Assembly.LoadFrom(...)?
Are there specific issues with .NET Core apps and System.Reflection.Assembly.LoadFrom(...)?

Time:05-14

I'm using a tool I wrote that makes a call to the following line in order to inspect a few things, including the assembly version:

var assm = System.Reflection.Assembly.LoadFrom(path);

The tool works as designed, except when I attempt to run it against a .NET Core application.

When I provide a path to an app compiled for .NET Core 3.1, 5.0 or 6.0 I get a System.BadImageFormatException when attempting to load the assembly.

My tool was written in C# using the .NET 4.7.2 Framework and I updated it to use 4.8, but still get the exception. Thinking it might be a mix-up between regular .NET and .NET Core, I wrote the following quick project and compiled it using the same framework as the target app (.NET Core) but I get the very same error.

Turns out, it throws the exception for any and all .NET Core applications. It works OK on typical Windows apps using .NET 4.7.2 Framework etc., but dies on any .NET Core app.

In researching this, I have yet to find anything that suggests .NET Core application manifests are so different that they'll cause this call to choke. All of my apps and testing are compiled as 64bit apps; there's no mix of 64 bit and 32 bit going on.

Steps to reproduce using simple tester app (below):

  1. Open your flavor of Visual Studio
  2. Create a new console application project
  3. In the template fields, enter: C#, Windows and Console respectively
  4. Select 'Console App' (not: Console App (.NET framework))
  5. Click Next
  6. Give your app a short name and click next
  7. Choose .NET core 5 (or 3.1 or 6 - but you'll need to remove the main{} for 6.0)
  8. Paste the code below and compile.
  9. Provide the path to THIS app (or any other .Net core app)
  10. Scratch head

SIMPLE TESTER:

internal class Program
{
    static void Main(string[] args)
    {
        Console.Write("\r\nEnter complete path to assembly:");
        var path = Console.ReadLine();
        if (!string.IsNullOrEmpty(path))
        {
            var assm = System.Reflection.Assembly.LoadFrom(path);

            if (assm != null)
            {
                var c = assm.GetCustomAttributes(false);
                if (null != c && c.Length > 0)
                {
                    Console.WriteLine($"Len:{c.Length} Value type:{c}");
                    Console.WriteLine($"c0:[{c[0]}]");
                    var x = 1; // convenient breakpoint to examine vars
                }
            }
        }

        Console.WriteLine("Complete...");
        Console.ReadLine();
    }
}

UPDATE:

For anyone reading this now or later, Microsoft has provided a new package for reading cross-architecture .NET assembly attributes: System.Reflection.MetadataLoadContext - available on Nuget.org

CodePudding user response:

Beginning with .NET Core (i don't recall whether which .NET Core version exactly), the executable .exe file produced when building an application/executable project with default settings is not a .NET assembly anymore like it was in the old days of .NET Framework.

Rather, the .NET program is compiled into a separate assembly DLL (called "cross-platform binary"; the associated exe file is called "platform-specific executable"). Thus, unlike for .NET Framework applications, you need to locate and load the assembly DLL containing the application code. The reason for this difference basically boils down to the old .NET Framework having been a Windows-only platform (other compatible platforms like Mono not withstanding), whereas .NET Core (as well as .NET 5/6/7/...) is having a strong emphasis on being cross-platform.

(By the way, it is also possible to build a project as single file deployment, in which case you would not find separate .exe and .dll files.)

  • Related