2012-10-26 9 views
12

Sto lottando con l'evento AssenblyResolve per un po 'di tempo. Ho cercato StackOverflow e fatto altri googling e provato tutto ciò che penso fosse rilevante. Ecco i link che sono il più vicino al mio problema (a mio parere):AssemblyResolve non licenziato per le dipendenze

  1. AssemblyResolve is not invoked and FileNotFoundException is thrown during serialization

  2. Where to handle AssemblyResolve event in a class library?

Ho una classe di avvio automatico con il metodo statico (toglierò il codice thread safe che abbiamo, solo per motivi di chiarezza:

public static void Initialize() 
{ 
    AppDomain.CurrentDomain.AssemblyResolve += CustomResolve; 
} 

private static Assembly CustomResolve(object sender, ResolveEventArgs args) 
{ 
    // There is a lot code here but basicall what it does. 
    // Is determining which architecture the computer is running on and 
    // extract the correct embedded dll (x86 or x64). The code was based 
    // on milang on GitHub (https://github.com/milang/P4.net). And it's the same 
    // purpose we want to be able to load the x86 or x64 version of the perforce dll 
    // but this time with the officially Perforce supported p4api.net. 
    // Once the dll is extracted we assign it to the boostrapper 
    Bootstrapper._p4dnAssembly = Assembly.LoadFile(targetFileName); 

    // Make sure we can satisfy the requested reference with the embedded assembly (now extracted). 
    AssemblyName reference = new AssemblyName(args.Name); 
    if (AssemblyName.ReferenceMatchesDefinition(reference, Bootstrapper._p4dnAssembly.GetName())) 
    { 
     return Bootstrapper._p4dnAssembly; 
    } 
} 

Sono riuscito a far funzionare il codice se ho una classe semplice con un metodo main e un costruttore statico. Il costruttore statico chiama semplicemente il metodo Boostrapper.Initialize(). Dopo di che, ho potuto usare la mia biblioteca e stava funzionando come previsto:

public static class Test 
{ 
    static Test() 
    { 
     Bootstrapper.Initialize(); 
    } 

    public static void Main() 
    { 
     // Using the library here is working fine. The AssemblyResolve event was 
     // fired (confirmed by a breakpoint in Visual Studio) 
    } 
} 

Il problema che ho è se c'è almeno uno strato di dipendenza. In pratica il codice rimane lo stesso, ma questa volta il mio codice della biblioteca si trova all'interno di un'altra libreria:

public static class Test 
{ 
    static Test() 
    { 
     Bootstrapper.Initialize(); 
    } 

    public static void Main() 
    { 
     Class1 myClass = new Class1(); 

     // The following line is using the code of the extracted library, but 
     // The AssemblyResolve event is not fired (or fired before I register the 
     // callback) and therefore the library is not found : result 
     // BadImageFormatException() error could not load libary because one 
     myClass.Connect(); 
    } 
} 

Suona come # 2 dei link che ho affermato in precedenza spiegare quello che sto vedendo, ma non funziona . Il punto di interruzione di Visual Studio sul callback AssemblyResove non viene mai colpito.

Qualche idea di cosa sta succedendo?

Francesco

risposta

7

qualcuno ha fatto risposta, ma la risposta è stato cancellato. Quindi non posso contrassegnarlo come risposta. Fondamentalmente sta funzionando il fatto che il codice non debba essere al di fuori del metodo "principale". Partendo fresco di un nuovo progetto, di risolvere il problema quindi credo che ho avuto alcuni problemi con la dll (probabilmente dll x86 nella cartella x64 o viceversa)

static void main(string[] args) 
{ 
    Boostrapper.Initialize(); 
    RealMain(); 
} 

static void RealMain() 
{ 
    Class1 myClass = new Class1(); 
    myClass.Connect(); 
} 
15

io so che è stato un po 'che la questione è stata ha chiesto e risposto, ma ho voluto aggiungere la mia opinione sul problema comunque (dato che ho sprecato poche ore per questo, forse grazie a questo qualcun altro non dovrebbe)

Il problema è fondamentalmente il fatto, che l'applicazione sta tentando di risolvere tutti gli assembly necessari per eseguire il metodo all'inizio di tale metodo:

static void main(string[] args) 
{ 
    // <-- here the app tries to resolve MyAssembly 
    // and as MyAssembly.Class1 is not found, the app crashes 

    // this next line is never called: 
    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(ResolveAssembly); 

    // class contained in an assemnly that we need to resolve 
    MyAssembly.Class1 myClass = new MyAssembly.Class1(); 
} 

Ecco perché il precedente si bloccherà: il gestore di eventi ResolveAssembly non verrà mai chiamato perché non è mai stato collegato.

Ed è anche per questo che la soluzione qui di seguito funziona (come pubblicato dalla OP):

static void main(string[] args) 
{ 
    Initialize(); 
    RealMain(); 
} 

static void Initialize() 
{ 
    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(ResolveAssembly); 
} 

static void RealMain() 
{ 
    // <-- here the app tries to resolve MyAssembly 
    // class contained in an assemnly that we need to resolve  
    MyAssembly.Class1 myClass = new MyAssembly.Class1(); 
    // and everything is OK 
} 
Problemi correlati