2012-10-26 22 views
12

Od pewnego czasu walczę z wydarzeniem AssenblyResolve. Szukałem stackoverflow i zrobiłem inne google i wypróbowałem wszystko, co moim zdaniem było trafne. Oto linki będące bliżej mojego problemu (moim zdaniem):AssemblyResolve nie zwolniony dla zależności

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

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

Mam klasy Bootstrapper z metodą statyczną (usunę kod zabezpieczający wątek, który mamy, tylko ze względu na jasność:

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; 
    } 
} 

Udało mi się sprawić, że kod zadziała, jeśli mam prostą klasę z główną metodą i konstruktorem statycznym. Konstruktor statyczny wywołuje po prostu metodę Boostrapper.Initialize(). Po tym, mogłem użyć moją bibliotekę i działa zgodnie z oczekiwaniami:

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) 
    } 
} 

Mam problem jest, jeśli istnieje co najmniej jedna warstwa uzależnienia. Zasadniczo kod pozostaje taka sama, ale tym razem mój kod biblioteki znajduje się wewnątrz innej biblioteki:

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(); 
    } 
} 

Brzmi jak # 2 z linków podanych wcześniej mam wyjaśnić to, co widzę, ale to nie działa . Punkt przerwania Visual Studio wywołania zwrotnego AssemblyResove nigdy nie jest trafiony.

Masz pojęcie o tym, co się dzieje?

Francis

Odpowiedz

7

Ktoś zrobił odpowiedź, ale odpowiedź została usunięta. Nie mogę więc oznaczyć tego jako odpowiedzi. Zasadniczo działa kod, który nie musi znajdować się poza "główną" metodą. Zaczynając świeże z nowego projektu, rozwiązać problem, więc myślę, miałem pewne problemy z dll (prawdopodobnie x86 dll w folderze x64 lub odwrotnie)

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

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

wiem, że to było dawno to pytanie zapytałem i odpowiedziałem, ale mimo to chciałem dodać moją opinię na ten temat (ponieważ po prostu zmarnowałem kilka godzin nad tym, być może dzięki temu ktoś inny nie musiałby)

Problem polega w zasadzie na tym, że aplikacja próbuje rozwiązać wszystkie złożenia potrzebne do wykonania metody na początku tej metody:

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(); 
} 

Dlatego powyższe spowoduje awarię: program obsługi zdarzeń ResolveAssembly nigdy nie zostanie wywołany, ponieważ nigdy nie został podłączony.

I to również dlatego poniżej rozwiązanie działa (jak wysłane przez PO):

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 
} 
Powiązane problemy