14

I want to load the assembly via the following

var loadedAssembly = Assembly.Load(File.ContentsAsBytes);

the File.ContentAsBytes returns the dll as a byte[], via the following

System.IO.File.ReadAllBytes("dll location");

The issue is the loaded assembly (loadedAssembly) loses its phyisical location

  • loadedAssembly.CodeBase - is set to the assembly which is loading it (which is not correct)
  • loadedAssembly.Location - is empty

Is there a way to load from a byte[] and getting a similar result to Assembly.LoadFile as I need the the result to work with the AppDomain.CurrentDomain.AssemblyResolve

dbones
  • 4,415
  • 3
  • 36
  • 52
  • That's the whole point. This has deep security implication. An assembly identity is not just represented by its bytes. Where it was loaded from (disk, internet, etc.) is crucial. You can't pretend a given set of byte is, say, mscorlib.dll. The only way would be to save it to a temp file and load it from there, which could work with AssemblyResolve, but that raises the question to why would you want to do this in the first place? – Simon Mourier May 19 '13 at 06:51
  • I don't know what your context is, but isn't it an option to keep track of a dictionary yourself? – Grimace of Despair May 22 '13 at 07:23
  • @SimonMourier the work around is already thought of, and can be used in my scenario, but the application would be far more flexible if I could accomplish the above. – dbones May 22 '13 at 19:59
  • @GrimaceofDespair already done, although you cannot override how .NET uses AssemblyResolve when loading assemblies and the dependent assemblies. the issue is the AssemblyResolve does not fire if it thinks it has the assembly loaded – dbones May 22 '13 at 20:03
  • Result of Assembly.Load(byte[]) should work with AppDomain.CurrentDomain.AssemblyResolve. Why do you say "as I need the the result to work with the AppDomain.CurrentDomain.AssemblyResolve"? – Stipo May 25 '13 at 20:57

3 Answers3

5

A byte array byte[] is simply a stream of bytes in memory. It has no correlation to any file at all. That byte array could have been read from file, downloaded from a web server, or created spontaneously by a random number generator. There is no extra data that "goes with it".

If you want to maintain the file location where the byte array was originally read from, then you must maintain that data separately in another variable. There is no way to "attach" the extra data to the byte[] variable.

When you use Assembly.Load to load the byte array as an assembly, it has no way to know where that byte array came from, because that extra data is not provided to the Load function.

As a workaround, is there a way you can save your byte array to a temporary file, use Assembly.LoadFile to give you the data you need and link the Location back to your original byte array?

Matt Houser
  • 33,983
  • 6
  • 70
  • 88
  • thanks, already aware of this solution, also it has been suggested by @carlosfigueira and in the comments. Consider that the LoadFile needs to do the same under the covers. I just need to find a way that will work with AssemblyResolve, unless there is an alternative to AssemblyResolve. – dbones May 23 '13 at 17:48
3

Sure, you'd think that Location would have a set method somewhere that you could access or some other way to tweak it. It doesn't. What happens (I dropped mscorlib.dll into IL DASM) is that when you load from file, there is a native handle that it associated with the assembly in the class RuntimeAssembly. When you call the Location getter, it grabs this handle and gives you the location from the native handle, but only if there was one. No handle, no location.

Here's the IL:

.method public hidebysig specialname virtual 
    instance string  get_Location() cil managed
{
  .custom instance void System.Security.SecuritySafeCriticalAttribute::.ctor() = ( 01 00 00 00 ) 
  // Code size       37 (0x25)
  .maxstack  3
  .locals init (string V_0)
  IL_0000:  ldnull
  IL_0001:  stloc.0
  IL_0002:  ldarg.0
  IL_0003:  call       instance class System.Reflection.RuntimeAssembly System.Reflection.RuntimeAssembly::GetNativeHandle()
  IL_0008:  ldloca.s   V_0
  IL_000a:  call       valuetype System.Runtime.CompilerServices.StringHandleOnStack System.Runtime.CompilerServices.JitHelpers::GetStringHandleOnStack(string&)
  IL_000f:  call       void System.Reflection.RuntimeAssembly::GetLocation(class System.Reflection.RuntimeAssembly,
                                                                       valuetype System.Runtime.CompilerServices.StringHandleOnStack)
  IL_0014:  ldloc.0
  IL_0015:  brfalse.s  IL_0023
  IL_0017:  ldc.i4.8
  IL_0018:  ldloc.0
  IL_0019:  newobj     instance void System.Security.Permissions.FileIOPermission::.ctor(valuetype System.Security.Permissions.FileIOPermissionAccess,
                                                                                     string)
  IL_001e:  call       instance void System.Security.CodeAccessPermission::Demand()
  IL_0023:  ldloc.0
  IL_0024:  ret
} // end of method RuntimeAssembly::get_Location
plinth
  • 48,267
  • 11
  • 78
  • 120
2

Once you pass the byte[] to the Assembly.Load method, that byte array has absolutely no information to even hint the Load method where it came from - it's only a bunch of bytes. The same would apply if you copied the file to a separate location:

File.Copy(dllLocation, anotherLocation);
var asm = Assembly.LoadFile(anotherLocation);

The assembly location will be pointing to anotherLocation, even though the assembly originally was on dllLocation. Similarly, when you load the assembly bytes (essentially copying the assembly from the disk to memory), the "location" of those bytes is now the memory.

carlosfigueira
  • 85,035
  • 14
  • 131
  • 171
  • thanks, that's how I understood the issue, however when you load it in from the byte[], is their a way to provide any Meta-data. As the loadFile must load the assembly in memory and at some point supply meta-data. – dbones May 16 '13 at 21:08