2013-05-16 15 views
14

voglio caricare l'assembly tramite il seguenteCaricamento un assembly Bytes perde la posizione

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

il File.ContentAsBytes restituisce il dll come byte[], tramite il seguente

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

Il problema è il gruppo caricato (loadedAssembly) perde la sua posizione fisica

  • loadedAssembly.CodeBase - è impostato il gruppo che sta caricando esso (che non è corretto)
  • loadedAssembly.Location - è vuoto

C'è un modo per caricare da un byte[] e ottenere un risultato simile a Assembly.LoadFile come ho bisogno del risultato di lavorare con il AppDomain.CurrentDomain.AssemblyResolve

+0

Questo è il punto. Questo ha implicazioni di sicurezza profonde. Un'identità dell'assieme non è solo rappresentata dai suoi byte. Da dove è stato caricato (disco, internet, ecc.) È fondamentale. Non si può pretendere che un determinato insieme di byte sia, per esempio, mscorlib.dll. L'unico modo sarebbe salvarlo in un file temporaneo e caricarlo da lì, che potrebbe funzionare con AssemblyResolve, ma ciò solleva la domanda sul perché dovresti farlo in primo luogo? –

+0

Non so quale sia il tuo contesto, ma non è un'opzione per tenere traccia di un dizionario tu stesso? –

+0

@SimonMourier il lavoro è già stato pensato e può essere utilizzato nel mio scenario, ma l'applicazione sarebbe molto più flessibile se potessi realizzare quanto sopra. – dbones

risposta

2

Una volta superato il byte[] al metodo Assembly.Load, che array di byte non ha assolutamente alcuna informazione a suggerire anche il metodo Load WHE è venuto da - è solo un mucchio di byte. Lo stesso vale se è stato copiato il file in una posizione separata:

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

La posizione di montaggio saranno indicando anotherLocation, anche se il gruppo in origine era su dllLocation. Allo stesso modo, quando si caricano i byte dell'assieme (essenzialmente copiando l'assieme dal disco alla memoria), la "posizione" di quei byte è ora la memoria.

+0

grazie, è così che ho capito il problema, tuttavia quando lo si carica dal byte [], è il loro modo di fornire qualsiasi Meta-dati. Poiché loadFile deve caricare l'assembly in memoria e ad un certo punto fornire metadati. – dbones

5

Un array di byte byte[] è semplicemente un flusso di byte in memoria. Non ha alcuna correlazione con nessun file. Quella matrice di byte poteva essere letta dal file, scaricata da un server web o creata spontaneamente da un generatore di numeri casuali. Non ci sono dati extra che "si accompagnino".

Se si desidera mantenere il percorso del file dal quale è stata originariamente letta la matrice di byte, è necessario mantenerli separatamente in un'altra variabile. Non c'è modo di "allegare" i dati extra alla variabile byte[].

Quando si utilizza Assembly.Load per caricare l'array di byte come un assieme, non è possibile sapere da dove proviene l'array di byte, poiché tali dati aggiuntivi non vengono forniti alla funzione Load.

Come soluzione alternativa, esiste un modo per salvare l'array di byte in un file temporaneo, utilizzare Assembly.LoadFile per fornire i dati necessari e collegare lo Location all'array di byte originale?

+0

grazie, già a conoscenza di questa soluzione, anche questa è stata suggerita da @carlosfigueira e nei commenti. Considera che il LoadFile deve fare lo stesso sotto le coperte. Ho solo bisogno di trovare un modo che funzioni con AssemblyResolve, a meno che non ci sia un'alternativa a AssemblyResolve. – dbones

3

Certo, dovresti pensare che che Posizione avrebbe un metodo impostato da qualche parte che è possibile accedere o un altro modo per modificarlo. Non è così. Quello che succede (ho mscorlib.dll rilasciato in IL DASM) è che quando si carica da file, c'è un handle nativo che è associato con l'assembly nella classe RuntimeAssembly. Quando chiami il getter Location, afferra questo handle e ti dà la posizione dall'handle nativo, ma solo se ce n'era uno. Nessuna maniglia, nessuna posizione.

Ecco il 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 
2

ho affrontato una situazione simile. È raro che io abbia effettivamente bisogno della posizione, ma per i casi che faccio, ho creato una classe helper (AssemblyUtilities) che utilizzo per caricare i byte per l'assembly e archiviare semplicemente la posizione in un dizionario statico. Un ulteriore metodo di supporto (GetLocation) fa capolino nella posizione effettiva dell'assembly e, se non ce n'è uno, consulta il dizionario. Funziona bene dato che sono responsabile del caricamento dei byte non elaborati e degli assembly di maniglie "peek-through" caricati in modo "tradizionale". Così ...

public static class AssemblyUtilities { 
    private static Dictionary<Assembly, string> locationByAssembly = 
     new Dictionary<Assembly, string>(); 

    private static Dictionary<string, Assembly> assemblyByLocation = 
     new Dictionary<string, Assembly>(StringComparer.OrdinalIgnoreCase); 

    public static Assembly LoadFile(string location) { 
     Assembly assembly; 
     lock (locationByAssembly) { 
      if (!assemblyByLocation.TryGetValue(location, out assembly)) { 
       byte[] bytes = ReadAllBytes(location); 
       if (bytes == null) return null; 
       byte[] pdb = ReadAllBytes(Path.ChangeExtension(location, ".pdb")); 
       assembly = ((pdb == null)? Assembly.Load(bytes): Assembly.Load(bytes, pdb)); 
       locationByAssembly[assembly] = location; 
       assemblyByLocation[location] = assembly; 
      } 
      return assembly; 
     } 
    } 

    public static string GetLocation(Assembly assembly) { 
     if (assembly == null) return null; 
     string location = assembly.Location; 
     if (location == null) locationByAssembly.TryGetValue(assembly, out location); 
     return location; 
    } 

    private static byte[] ReadAllBytes(string path) { 
     try { return File.ReadAllBytes(path); } 
     catch { return null; } 
    } 
} 

// And if you prefer extensions... 
public static class AssemblyExtensions { 
    public static string GetLocation(this Assembly self) { 
     return AssemblyUtilities.GetLocation(self); 
    } 
} 
+0

Potresti pubblicare un esempio di ciò di cui stai parlando? Questa risposta è alquanto confusa. – BradleyDotNET

+0

In breve, ecco cosa ho: 'public static class AssemblyUtilities { Dizionario statico privato locationByAssembly = ...; Assembly statico pubblico LoadFile (stringa loc) { byte [] byte = ReadAllBytes (loc); byte [] pdb = ReadAllBytes (Path.ChangeExtension (loc, ".pdb")); Assembly a = ((pdb == null)? Assembly.Load (byte): Assembly.Load (byte, pdb)); locationByAssembly [a] = loc; return a; } public static string GetLocation (Assembly a) { string loc = a.Location; if (loc == null) locationByAssembly.TryGetValue (a, out loc); ritorno loc; } } ' – the7thchakra

+0

Perdonare la formattazione scadente. Ho usato il segno di spunta posteriore, ma ha mangiato le newline. Meh. – the7thchakra