2012-02-07 8 views
6

Próbuję użyć zdarzenia AppDomain.AssemblyResolve do obsługi wyjątków podczas rozwiązywania Złożenia niektórych bibliotek dll załadowanych w środowisku wykonawczym (SerializationException for dynamically loaded Type).Praca z zdarzeniem AppDomain.AssemblyResolve

Kiedy zdarzenie jest zwolniony, załadować wszystkie pliki DLL w moim katalogu i utworzyć Assembly tablicę, a następnie użyć tej metody, aby uzyskać Assembly zawierający typ określić:

public static Assembly GetAssemblyContainingType(String completeTypeName, Assembly[] assemblies) 
    { 
     Assembly assembly = null; 

     foreach (Assembly currentassembly in assemblies) 
     { 
      Type t = currentassembly.GetType(completeTypeName, false, true); 
      if (t != null) 
      { 
       assembly = currentassembly; 
       break; 
      } 
     } 

     return assembly; 
    } 

Problemem jest to, że Kod działa tylko z AssemblyQualifiedName, a ResolveEventArgs.Name dostarczone przez zdarzenie nie jest tak przydatne.

Czy możesz zaproponować mi obejście problemu?

Czy istnieje sposób przekazania innym argumentów do zdarzenia po jego uruchomieniu?

Odpowiedz

12

Można zdefiniować słownika zespołów z katalogu, jak poniżej:

private readonly IDictionary<string,Assembly> additional = 
    new Dictionary<string,Assembly>(); 

załadować ten słownik z zespołami ze swojej znanej książce telefonicznej, jak to:

foreach (var assemblyName ... corresponding to DLL names in your directory...) { 
    var assembly = Assembly.Load(assemblyName); 
    additional.Add(assembly.FullName, assembly); 
} 

Zapewnienie wdrożenia na haku ...

private Assembly ResolveAssembly(Object sender, ResolveEventArgs e) { 
    Assembly res; 
    additional.TryGetValue(e.Name, out res); 
    return res; 
} 

... i podłączyć go do zdarzenia:

AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += ResolveAssembly; 
AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly; 

To powinno załatwić sprawę.

+5

Czy wstępne ładowanie złożeń nie eliminuje potrzeby obsługi zdarzeń AssemblyResolve? –

+2

@mikez Z tego co wiem, proste ładowanie złożenia za pomocą 'Assembly.Load (assemblyName)' nie powoduje automatycznego udostępnienia go do kodu rozdzielczości zespołu domeny aplikacji (chyba że ten kod może uzyskać dostęp do złożenia przy użyciu domyślnej rozdzielczości proces). Ten kod został usunięty z działającego systemu (usunąłem kod obsługi błędów, np. Wokół wywołania 'additional.TryGetValue (e.Name, out res)' w celu uproszczenia niektórych rzeczy). Po usunięciu haka 'ResolveAssembly' mój system operacyjny przestaje działać :) – dasblinkenlight

+2

Podczas budowania słownika użyj AssemblyName.GetAssemblyName () zamiast Assmebly.Load, aby uzyskać nazwę zespołu na mapowanie nazw plików i unikaj bezwarunkowo ładowanie wszystkich zespołów. –

0

Jeśli znasz listę złożeń, które mogą zawierać typ, który planujesz deserializować, lepiej byłoby wstępnie załadować wszystkie złożenia przed wykonaniem serializacji.

Po uruchomieniu zdarzenia AssemblyResolve nie masz informacji o typie przyczyny obciążenia, ale tylko o nazwie zespołu. Nie jest jasne, dlaczego w tym przypadku wyszukiwałoby się zestawienie według jakiegoś określonego typu.

Należy zauważyć, że jeśli 2 złożenia mają tę samą tożsamość (np. Nazwa pliku w przypadku nie podpisanego silnie), a jedno jest już załadowane, zdarzenie nie zostanie uruchomione, gdy można się spodziewać, nawet jeśli typ nie zostanie znaleziony w już załadowanym zespole.

Link do artykułu dla celów historycznych: Resolving Assembly Loads.

+0

Jak możesz również przeczytać w moim starym pytaniu http://stackoverflow.com/q/9158353/1061499 Pracuję nad aplikacją, która używa podejścia plug-in do ładowania różnych aplikacji interfejsu w czasie wykonywania.Kiedy aplikacja jest zamknięta, muszę serializować te obiekty, a następnie, gdy aplikacja zostanie ponownie uruchomiona, te obiekty muszą zostać zdekseralizowane. Problem polega na tym, że typy obiektów są ładowane w czasie wykonywania, więc ich typ nie został rozwiązany ... – davioooh