2013-07-11 8 views
5

Quindi, sono arrivato da molti articoli che fanno riferimento all'uso di AppDomain.CurrentDomain.AssemblyResolve per caricare DLL da risorse incorporate in un plug-in in fase di esecuzione (senza l'utilizzo di IlMerge). Tuttavia, quando inserisco questo codice, il gestore eventi non riceve mai il thread prima che il plugin lanci un messaggio TypeLoadException per la mia libreria principale.AppDomain.CurrentDomain.AssemblyResolve in dynamics crm

Ho provato a inserire il codice in un costruttore statico, all'interno del metodo Execute e nel costruttore principale; e sebbene il gestore eventi sia registrato, i punti di interruzione nel gestore non vengono colpiti.

L'ambiente è Dynamics CRM 2011 con l'ultimo roll-up e l'utilizzo degli strumenti di sviluppo SDK Progetto plug-in e generazione di classi di plug-in.

Qualcuno sa cosa devo fare per farlo funzionare?

risposta

4

È importante che la registrazione degli eventi AssemblyResolve si verifichi prima di fare riferimento a qualsiasi tipo dagli assembly che si pianifica per il caricamento tramite tale callback. Anche se non si fa riferimento ai tipi nel costruttore statico, è inoltre necessario assicurarsi di non avere variabili statiche nella classe o le sue classi di base tali tipi di riferimento negli assembly esterni.

Ecco come lo faccio: ho una classe separata per gestire il caricamento di montaggio, giustamente chiamato AssemblyLoader:

using System; 
using System.IO; 
using System.Linq; 
using System.Reflection; 

internal static class AssemblyLoader 
{ 
    internal static void RegisterAssemblyLoader() 
    { 
     AppDomain currentDomain = AppDomain.CurrentDomain; 
     currentDomain.AssemblyResolve -= OnResolveAssembly; 
     currentDomain.AssemblyResolve += OnResolveAssembly; 
    } 

    private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args) 
    { 
     return LoadAssemblyFromManifest(args.Name); 
    } 

    private static Assembly LoadAssemblyFromManifest(string targetAssemblyName) 
    { 
     Assembly executingAssembly = Assembly.GetExecutingAssembly(); 
     AssemblyName assemblyName = new AssemblyName(targetAssemblyName); 

     string resourceName = DetermineEmbeddedResourceName(assemblyName, executingAssembly); 

     using (Stream stream = executingAssembly.GetManifestResourceStream(resourceName)) 
     { 
      if (stream == null) 
       return null; 

      byte[] assemblyRawBytes = new byte[stream.Length]; 
      stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length); 


      return Assembly.Load(assemblyRawBytes); 
     } 

    } 

    private static string DetermineEmbeddedResourceName(AssemblyName assemblyName, Assembly executingAssembly) 
    { 
     //This assumes you have the assemblies in a folder named "EmbeddedAssemblies" 
     string resourceName = string.Format("{0}.EmbeddedAssemblies.{1}.dll", 
              executingAssembly.GetName().Name, assemblyName.Name); 

     //This logic finds the assembly manifest name even if it's not an case match for the requested assembly       
     var matchingResource = executingAssembly.GetManifestResourceNames() 
               .FirstOrDefault(res => res.ToLower() == resourceName.ToLower()); 

     if (matchingResource != null) 
     { 
      resourceName = matchingResource; 
     } 
     return resourceName; 
    } 
} 

Poi, nella mia classe plug-in, io uso un costruttore statico di rimettere in mia AssemblyLoader . Spostando la logica nella classe separata, limito il numero di tipi che sto facendo riferimento al contesto statico della mia classe di plugin, riducendo il rischio che accidentalmente faccio riferimento a qualcosa che si trova negli assembly esterni.

using System; 
using Microsoft.Xrm.Sdk; 

public class MyPlugin : IPlugin 
{ 
    static MyPlugin() 
    { 
     AssemblyLoader.RegisterAssemblyLoader(); 
    } 

    public void Execute(IServiceProvider serviceProvider) 
    { 
     //... 
    } 
} 

ho anche spostato praticamente tutti gli usi delle assemblee esterne in altre classi in modo che la mia classe plug-in non utilizza il affatto. Per lo più, questo è fuori dall'abbondanza di cautela.

+0

ok ... la vostra soluzione non è sostanzialmente diversa da quella che ho postato ... tuttavia, si ottiene il segno di spunta dal momento che mi ha chiesto se il problema sarebbe persistito se la complessità del problema fosse ridotta e aumentata gradualmente. –

+0

La stessa tecnica funziona con il flusso di lavoro personalizzato? –

Problemi correlati