2010-10-26 12 views
19

Scenariusz: używam Zarządzanej Rozszerzającej Struktury do ładowania wtyczek (eksportów) w czasie wykonywania na podstawie umowy interfejsu zdefiniowanej w oddzielnej bibliotece dll . W moim rozwiązaniu Visual Studio mam 3 różne projekty: aplikację hosta, bibliotekę klasy (definiującą interfejs - "IPlugin") i inną bibliotekę klasy implementującą interfejs (eksport - "MyPlugin.dll").MEF: "Nie można załadować jednego lub więcej żądanych typów. Pobierz Wyjątki LoaderExcessions, aby uzyskać więcej informacji"

Host szuka eksportu w swoim własnym katalogu głównym, więc podczas testowania buduję całe rozwiązanie i kopiuję plik Plugin.dll z folderu bin/release biblioteki klas do katalogu debugowania hosta, aby katalog katalogowy hosta znalazł i móc dodać go do CompositionContainer. Plugin.dll nie jest automatycznie kopiowany po każdej odbudowie, więc robię to ręcznie za każdym razem, gdy wprowadzam zmiany do umowy/implementacji.

Jednak kilka razy mam uruchomić aplikację hosta bez kopiowane (zaktualizowany) Plugin.dll pierwszy, i to rzucony wyjątek podczas składzie:

Unable to load one or more of the requested types. Retrieve the LoaderExceptions for more information

Jest to oczywiście ze względu na fakt, że Plugin.dll próbuje importować z implementacji inną wersję z IPlugin, gdzie podpisy właściwości/metody nie są zgodne. Chociaż łatwo jest tego uniknąć w kontrolowanym i monitorowanym środowisku, po prostu unikając (nie) przestarzałych implementacji IPlugin w folderze wtyczek, nie mogę polegać na takich założeniach w środowisku produkcyjnym, w którym można napotkać starsze wtyczki.

Problem polega na tym, że ten wyjątek skutecznie dusi całą akcję Kompilacja i importowane są eksportowane nie. Wolałbym, aby niedopasowane implementacje IPlugin były po prostu ignorowane, aby inne eksporty w katalogu (ach), implementujące poprawną wersję IPlugin, były nadal importowane.

Czy istnieje sposób, aby to osiągnąć? Myślę, że jedną z kilku możliwych opcji:

  • Jest flaga ustawić na CompositionContainer („ignorować braku importu”) przed lub podczas wywoływania Compose
  • Istnieje podobna flaga określić na <ImportMany()> atrybut
  • Istnieje sposób na „haczyk” na proces iteracji leżącej Compose(), i być w stanie poradzić sobie ze sobą (nie), import indywidualnie
  • Korzystanie silną nazwę podpisania jakoś patrzeć tylko import wykonawczego prąd wersja IPlugin

Pomysły?

Odpowiedz

15

Mam również spotkać a similar problem.

Jeśli masz pewność, że chcesz zignorować takie "złe" złożenia, rozwiązaniem będzie wywołanie AssemblyCatalog.Parts.ToArray() zaraz po utworzeniu każdego katalogu zespołu. Spowoduje to wywołanie ReflectionTypeLoadException, o którym wspomniałeś. Wtedy masz szansę uchwycić wyjątek i zignorować zły montaż.

Po utworzeniu obiektów dla wszystkich "dobrych" zespołów można je agregować w postaci AggregateCatalog i przekazać do konstruktora CompositionContainer.

+0

Będę musiał rzucić okiem. I tak, jestem pewien, że chcę je zignorować - i tak nie mogę ich wykorzystać, a oni zepsują wszystko, co chcę, więc to nie myślenia, nie? :) – d7samurai

+0

@ d7samurai: Niektórzy ludzie skończą tutaj, wyszukując wiadomość wyjątku. Chciałem po prostu podkreślić, że to nie naprawia podstawowej przyczyny błędu. Ponadto, wprowadzanie cichej awarii (czyli "po błędzie wznowić następne" zachowanie) nie jest dokładnie nie myślenia; może znacznie utrudnić wykrywanie i diagnozowanie błędów. Zalecam przynajmniej dać wskazówkę użytkownikowi, że stało się coś złego. –

+0

Oczywiście. Przez "ignorowanie" rozumiem "poruszanie się bez pozwolenia na zatrzymanie całego procesu importu". Nie ma użytkownika, ponieważ jest to usługa systemu Windows, ale wszystko to, co robi (bootstrapper), jest rejestrowane, zarówno zwykłe operacje, jak i wyjątki (w tym odrzucanie wszystkich wyjątków w wyrażeniach "LoaderExceptions" - kiedy ma to zastosowanie). – d7samurai

7

Ten problem może być spowodowany przez wiele czynników (żadnych wyjątków na obciążonych zespołów), jak wyjątek mówi, spojrzeć na ExceptionLoader do (miejmy nadzieję) dostać jakiś pomysł

inny problem/rozwiązanie, które znalazłem, jest jeśli używasz DirectoryCatalog, jeśli nie określisz drugiego parametru "searchPattern", MEF załaduje WSZYSTKIE biblioteki DLL w tym folderze (w tym strony trzeciej) i zacznie szukać typów eksportu, które również mogą powodować ten problem, rozwiązaniem jest posiadanie nazwy konwencji na wszystkich złożeniach, które eksportują typy i określenie, że w konstruktorze DirectoryCatalog używam * _Plugin.dll, w ten sposób MEF załaduje tylko zestawy, które zawierają eksportowane rodzaje

W moim przypadku MEF ładował dll NHibernate i rzuca jakiś błąd wersji montażu na LoaderException (Ten błąd może zdarzyć się z żadnym z bibliotek DLL w katalogu), podejście to rozwiązało problem

7

Tutaj jest przykładem wyżej wymienionych metod:

var di = new DirectoryInfo(Server.MapPath("../../bin/")); 

     if (!di.Exists) throw new Exception("Folder not exists: " + di.FullName); 

     var dlls = di.GetFileSystemInfos("*.dll"); 
     AggregateCatalog agc = new AggregateCatalog(); 

     foreach (var fi in dlls) 
     { 
      try 
      { 
       var ac = new AssemblyCatalog(Assembly.LoadFile(fi.FullName)); 
       var parts = ac.Parts.ToArray(); // throws ReflectionTypeLoadException 
       agc.Catalogs.Add(ac); 
      } 
      catch (ReflectionTypeLoadException ex) 
      { 
       Elmah.ErrorSignal.FromCurrentContext().Raise(ex); 
      } 
     } 

     CompositionContainer cc = new CompositionContainer(agc); 

     _providers = cc.GetExports<IDataExchangeProvider>(); 
+0

To nie działa dla ASP.NET MVC, jeśli nie używasz oddzielnej domeny, ponieważ Assembly.LoadFile wczytuje plik do innej domeny. Aby go rozwiązać, wystarczy użyć Assembly.LoadFrom. – Eben

Powiązane problemy