2016-03-25 14 views
7

Mamy projekt WWW dnx46, który używa skanowania zespołu autofac podczas uruchamiania, aby zarejestrować typy. Nasze zależności project.json obejmują:Autofac nie rozpoznaje typów ze skanowania zespołu w asp.net 5

"Autofac.Configuration": "4.0.0-rc1-268", 
"Autofac.Extensions.DependencyInjection": "4.0.0-rc1-177", 
"Autofac.Extras.CommonServiceLocator": "3.2.0", 
"Microsoft.AspNet.Hosting": "1.0.0-rc1-final", 
"Microsoft.AspNet.IISPlatformHandler": "1.0.0-rc1-final", 
"Microsoft.AspNet.Mvc": "6.0.0-rc1-final", 
"Microsoft.AspNet.Mvc.TagHelpers": "6.0.0-rc1-final", 
"Microsoft.AspNet.Mvc.ViewFeatures": "6.0.0-rc1-final", 
"Microsoft.AspNet.Server.Kestrel": "1.0.0-rc1-final", 
"Microsoft.AspNet.Session": "1.0.0-rc1-final", 
"Microsoft.AspNet.StaticFiles": "1.0.0-rc1-final", 
"Microsoft.AspNet.Tooling.Razor": "1.0.0-rc1-final", 
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0-rc1-final", 
"Microsoft.Extensions.Configuration.Json": "1.0.0-rc1-final", 
"Microsoft.Extensions.Logging": "1.0.0-rc1-final", 
"Microsoft.Extensions.Logging.Console": "1.0.0-rc1-final", 
"Microsoft.Extensions.Logging.Debug": "1.0.0-rc1-final", 
"Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0-rc1-final", 
"Newtonsoft.Json": "8.0.3" 

Nasza metoda startup.cs ConfigureServices wygląda następująco:

public IServiceProvider ConfigureServices(IServiceCollection services) 
{ 
    services.AddSingleton(serviceType => Configuration); 
    services.AddInstance<Microsoft.Extensions.Configuration.IConfiguration>(Configuration); 

    services.AddCaching(); 
    services.AddSession(); 
    services.AddMvc(); 

    var builder = new ContainerBuilder(); 

    var assemblies = Directory.GetFiles(<ourBinDirectoryPath>, "*.dll", SearchOption.TopDirectoryOnly).Select(Assembly.LoadFrom); 

    foreach (var assembly in assemblies) 
    { 
     builder.RegisterAssemblyTypes(assembly).Where(t => t.Name.EndsWith("Service") || t.Name.EndsWith("Repository") || t.Name.EndsWith("DataContext")).AsSelf().AsImplementedInterfaces(); 
     builder.RegisterAssemblyTypes(assembly).Where(t => !t.Name.EndsWith("Service") && !t.Name.EndsWith("Repository") && !t.Name.EndsWith("DataContext")).AsSelf().AsImplementedInterfaces().InstancePerDependency(); 
    } 

    builder.Populate(services); 
    var container = builder.Build(); 

    return container.Resolve<IServiceProvider>(); 
} 

Nasz proces jest to, że mamy kilka projektów, które budujemy, że spadek biblioteki DLL, że ten projekt będzie musiał do niestandardowego folderu bin. Podczas uruchamiania skanujemy te zespoły, aby zarejestrować typy za pomocą Autofac. Zrobiliśmy to w projekcie proof of concept i działało bez problemów. W naszym nowym projekcie choć mamy następujące kwestie:

  1. Jeśli próbujesz rozwiązać usługę w konstruktorze kontrolera, to zgłasza błąd wskazujący zastrzyk Microsoft Dependency nie może rozwiązać usługę. Nie wiesz, dlaczego nie korzysta z dostawcy Autofac tutaj.
  2. Jeśli ręcznie usuniemy pojedynczy typ przy starcie razem z naszym skanowaniem złożenia, otrzymamy błąd w konstrukcji sterownika, wskazując, że Autofac nie może rozwiązać usługi (korzysta z tego dostawcy Autofac, ale nadal nie znajduje naszych typów).
  3. Jeśli sprawdzę konstruktora i kontener przed jego powrotem w ConfigureServices, wydaje się, że wszystkie nasze typy są zarejestrowane. Jednakże, jeśli zmienię kontroler, aby wstrzyknąć IServiceProvider, a następnie spróbuję rozwiązać z niego usługę, to on dokładnie wykorzystuje dostawcę Autofac, ale zawsze uzyskuję zerowy wynik (nie znaleziono usługi).

Po wypróbowaniu wielu rzeczy, wziąłem nasz dowód projektu koncepcyjnego i skopiowaniu go do naszego nowego rozwiązania (w przypadku brakowało nam trochę mały ustawienie lub coś podczas konfigurowania nasz nowy projekt), a złe zachowanie kontynuowane. Zaczynam myśleć, że nasze zespoły wprowadzają jakiś błąd (ponieważ są to jedyne rzeczy, które zmieniły się po kopiowaniu), ale Autofac nie rzuca błędu podczas skanowania, a zamiast tego po prostu nie używa typów, z których poprawnie skanował .

Edycja 1

Stworzyłem i napisali very simplified example które reprodukuje problem Używam do. Powinieneś być w stanie to zrobić i uruchomić, aby odtworzyć błąd. Powinieneś otrzymać błąd w konstruktorze kontrolera macierzystego, wskazując niepowodzenie usługi.

Uwaga: podczas działania tego przykładu wykonywany jest plik .bat, który umieszcza wyjściową bibliotekę dll z projektu domeny w folderze .nuget w profilu użytkownika. Interfejs

Edycja 2

Podział w folderze abstrakcji na podstawie rekomendacji od @Travis Illig. Kiedy już to zrobiłem, rozwiązanie zaczęło działać. Podzieliliśmy to na nasz "prawdziwy" projekt, ale to nie działa. Nadal eksperymentuję, aby dowiedzieć się, dlaczego.

Edycja 3

Więc w końcu nasz projekt działa ponownie.Problem okazał się być kilka rzeczy:

  1. Mieliśmy zależność projektu abstrakcji wymienionych w naszym projekcie sieci web, a my również ładowanie i skanowanie dll z tego zestawu (podwójne ładowanie). (Myślę, że to była poważna sprawa).
  2. Nasze wersje NuGet były złe, więc nie sądzę, żeby ładowały się poprawnie. Korzystaliśmy z wersji 1.0.0-1, która jest nieprawidłowym formatem wstępnym. Zaktualizowano go do wersji 1.0.0-b1 i wszystko zaczęło działać lepiej.

Zajęło mi to więcej czasu, aby dowiedzieć się, a moim największym problemem w tym momencie jest to, że Autofac po cichu zawiedzie. Naprawdę chciałbym, żeby to wybuchło i dał mi jakieś wyniki debugowania lub coś wskazującego na problem. Zamiast tego wszystko wyglądało na to, że skanuje i ładuje się dobrze, ale kiedy poszedłeś użyć kontenera, nic by się nie zmieniło.

Odpowiedz

2

Istnieje prawdopodobieństwo, że zespoły są ładowane w takiej kolejności, w której niektóre typy nie mogą zostać załadowane ze względu na brak załadowania wstępnie wymaganych złożeń.

Załóżmy na przykład, że masz zespół A zawierający interfejs IComponent. Załóżmy również, że masz zespół B, który zawiera klasę Component, która implementuje IComponent. Jeśli najpierw zostanie załadowany zespół B, typ Component nie będzie można załadować, ponieważ interfejs, który implementuje, nie jest zdefiniowany.

Podczas skanowania typu, Autofac stara się być tak bezpieczny, jak to możliwe i nie eksploduje, jeśli na zewnątrz wybiegnie w typy, których nie można załadować. Możesz zobaczyć w scanning registration source, gdzie do załadowania używa specjalnej bezpiecznej metody.

W twoim kodeksie zakładam, że do załadowania było o wiele mniej zestawów, więc skończyło się ładowanie rzeczy we właściwej kolejności. Szczęśliwy wypadek. Kiedy dostajesz się do większych projektów, znacznie łatwiej jest kontrolować kolejność ładunków i powodować takie problemy.

+0

Tak więc zakończyliśmy określanie kolejności ładowania złożenia (tak więc najpierw pobrano abstrakcje, następnie klasy bazowe itd.). To samo zachowanie było kontynuowane. Myślę, że to, co mówisz, wciąż ma sens, ale może być bardziej ziarniste, niż miałem nadzieję. Jestem w punkcie, w którym powtarzam klasy indywidualnie, dopóki nie będę mógł powtórzyć tego zachowania, a następnie zdecydować, w jaki sposób możemy się zająć. Dzięki za wskaźnik. –

+0

I rzeczywiście, twój wskaźnik do kodu pomógł mi. Nie zdawałem sobie sprawy, że może to zająć zbiór złożeń, a następnie utworzyć jedną kolekcję wszystkich typów ładowalnych. Może to pomóc w przypadku zamówienia. Zobaczę, czy mogę to wykorzystać. –

+0

Aktualizacja: Tak więc zmiana kolejności lub załadowanie wszystkich złożeń na raz nie działało. W efekcie powstał całkiem nowy projekt, który ma jeden zespół z tylko jednym interfejsem i jedną klasą. Doświadczanie dokładnie takiego samego zachowania jak powyżej. Kiedy wrócę później wieczorem, mogę popchnąć ten nowy projekt do githubu i sprawdzić, czy ktoś ma myśli o tym, co się dzieje. –