9

A lot of .NET assemblies ship with a reference only version which is stripped of actual code, and only has the metadata.

For example, I can find System.Core.dll at several locations on my machine, two of which are:

  • C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.0\System.Core.dll Size: 276 KB
  • C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Core\v4.0_4.0.0.0__b77a5c561934e089\System.Core.dll Size: 1291 KB

The first one only has metadata, and loading it in default load context throws a BadImageFormat exception.

System.BadImageFormatException: Could not load file or assembly 'System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' or one of its dependencies. Reference assemblies should not be loaded for execution. They can only be loaded in the Reflection-only loader context

Given the path to an assembly, is it possible to find out if it is a "reference assembly"?

I can check the path for keyword "Reference Assemblies", but that is hacky and won't work if the assembly is copied to a different location. I have the freedom to first load the assembly in reflection only context if that would help.

Ross Ridge
  • 38,414
  • 7
  • 81
  • 112
Turbo
  • 2,179
  • 18
  • 38
  • There seems to be no detailed explanation from Microsoft on what has been removed from a full assembly when producing a reference assembly. Why do you need to check against that? Except on a developer machine, it would be rare to see reference assemblies. – Lex Li Aug 06 '16 at 01:27
  • How are you currently loading the assembly so that it throws BadImageFormatException? – Michael Liu Aug 06 '16 at 03:27
  • 1
    Hard to guess how you got into this pickle, the IDE certainly never gets this wrong. And the assembly is in the GAC so you'll always get the correct one loaded. It isn't otherwise hard to tell that you got the wrong one, the exception is loud and clear. Crystal ball says that you are using Assembly.LoadFile(), the entirely too attractively named method whose usage is wrong 99.9% of the time. Use Load instead. – Hans Passant Aug 06 '16 at 05:21

1 Answers1

5

I found this code dotnet/coreclr/.../pefile.inl in CoreCLR, which identifies a reference assembly by what I think is System.Runtime.CompilerServices.ReferenceAssemblyAttribute:

if (mdImport->GetCustomAttributeByName(TokenFromRid(1, mdtAssembly),
                                       g_ReferenceAssemblyAttribute,
                                       NULL,
                                       NULL) == S_OK) {
    ThrowHR(COR_E_LOADING_REFERENCE_ASSEMBLY, BFA_REFERENCE_ASSEMBLY);
}

I would assume full CLR does the same.

I haven't tried it yet, but you could probably load your assembly into Reflection-only context, and then checked whether it has a ReferenceAssemblyAttribute.

Andrey Shchekin
  • 21,101
  • 19
  • 94
  • 162