2014-11-02 10 views
5

W moich testach integracji używam tego samego SimpleInjector.Container, który buduję w projekcie Web API, który testuję.container.RegisterWebApiControllers (GlobalConfiguration.Configuration) powoduje InvalidOperationException

Ale ta linia w skład klasy root:

container.RegisterWebApiControllers(GlobalConfiguration.Configuration); 

powoduje wyjątek:

System.TypeInitializationException : The type initializer for 'MyProject.Api.Test.Integration.HttpClientFactory' threw an exception. 
---- System.InvalidOperationException : This method cannot be called during the application's pre-start initialization phase. 
Result StackTrace: 
at MyProject.Api.Test.Integration.HttpClientFactory.Create() 
    at MyProject.Api.Test.Integration.Controllers.ProductControllerIntegrationTest.<GetProductBarcode_Should_Return_Status_BadRequest_When_Barcode_Is_Empty>d__0.MoveNext() in d:\Projects\My\MyProject.Api.Test.Integration\Controllers\ProductControllerIntegrationTest.cs:line 26 
----- Inner Stack Trace ----- 
    at System.Web.Compilation.BuildManager.EnsureTopLevelFilesCompiled() 
    at System.Web.Compilation.BuildManager.GetReferencedAssemblies() 
    at System.Web.Http.WebHost.WebHostAssembliesResolver.System.Web.Http.Dispatcher.IAssembliesResolver.GetAssemblies() 
    at System.Web.Http.Dispatcher.DefaultHttpControllerTypeResolver.GetControllerTypes(IAssembliesResolver assembliesResolver) 
    at System.Web.Http.WebHost.WebHostHttpControllerTypeResolver.GetControllerTypes(IAssembliesResolver assembliesResolver) 
    at SimpleInjector.SimpleInjectorWebApiExtensions.GetControllerTypesFromConfiguration(HttpConfiguration configuration) 
    at SimpleInjector.SimpleInjectorWebApiExtensions.RegisterWebApiControllers(Container container, HttpConfiguration configuration) 
    at MyProject.Api.ContainerConfig.RegisterTypes(Container container) in d:\Projects\My\MyProject.Api\App_Start\ContainerConfig.cs:line 128 
    at MyProject.Api.ContainerConfig.CreateWebApiContainer() in d:\Projects\My\MyProject.Api\App_Start\ContainerConfig.cs:line 63 
    at MyProject.Api.Test.Integration.HttpClientFactory..cctor() in d:\Projects\My\MyProject.Api.Test.Integration\HttpClientFactory.cs:line 17 

Po komentując to wszystko działa poprawnie, zarówno samą aplikację internetową i testy.

Więc pytanie brzmi:

  • Co jest powodem wyjątkiem?
  • (i jest to metoda naprawdę konieczne?)

Oto kod dla HttpClientFactory (klasa pomocnika stworzyć HttpClient z odpowiednich nagłówków, takich jak klucz API lub zezwolenia):

internal static class HttpClientFactory 
{ 
    private static readonly Container _container = ContainerConfig.CreateWebApiContainer(); 

    public static HttpClient Create() 
    { 
     var client = new HttpClient { BaseAddress = GetUrl() }; 
     //... 
     return client; 
    } 
} 
+1

Czy możesz opublikować szczegóły InnerException i StackTrace? Czy masz jakieś wiążące przekierowania w pliku konfiguracyjnym? –

+1

Zgadzam się z @DarinDimitrov, proszę podać nam pełny ślad stosu. Trudno o tym myśleć bez tych szczegółów. – Steven

+0

@ Darin: Zaktualizowano, dziękuję! Binding przekierowania są bardzo podobne do tego, co mam w Web.config. – abatishchev

Odpowiedz

5

Jeśli dokładnie przyglądamy się śladowi stosu, możemy dokładnie zobaczyć, co się tutaj dzieje. Metoda rozszerzeń RegisterWebApiControllers wywołuje metodę GetControllerTypes na instancję IHttpControllerTypeResolver, którą pobiera zi przechodzi przez IAssembliesResolver, która jest również pobierana z konfiguracji. Metoda o nazwie GetControllerTypes (z WebHostHttpControllerTypeResolver) wywołuje w GetControllerTypes z DefaultHttpControllerTypeResolver, która ostatecznie spowoduje wywołanie GetReferencedAssemblies z klasy System.Web.Compilation.BuildManager.

Jednakże, System.Web.Compilation.BuildManager nie można wczytać wcześnie w potoku ASP.NET ani w ogóle poza kontekstem ASP.NET. Ponieważ jesteś w teście, BuildManage rzuci wyjątek, którego doświadczasz.

Zatem rozwiązaniem (lub "sztuczką", aby to zrobić) jest zastąpienie domyślnego IAssembliesResolver podczas testowania urządzenia. Wyobrażam sobie, że rezolwer wyglądać tak:

public class TestAssembliesResolver : IAssembliesResolver 
{ 
    public ICollection<Assembly> GetAssemblies() 
    { 
     return AppDomain.CurrentDomain.GetAssemblies(); 
    } 
} 

[TestMethod] 
public void TestMethod1() 
{ 
    // Replace the original IAssembliesResolver. 
    GlobalConfiguration.Configuration.Services.Replace(typeof(IAssembliesResolver), 
     new TestAssembliesResolver()); 

    var container = SimpleInjectorWebApiInitializer.BuildContainer(); 

    container.Verify(); 
} 

To trochę niefortunne, że masz do czynienia tego, zwłaszcza, że ​​Prosty wtryskiwacza został zaprojektowany, aby być sprawdzalne. Wygląda na to, że przeoczyliśmy to, tak bardzo integrując metodę rozszerzenia z Web API. Musimy zrobić krok wstecz i zastanowić się, jak ułatwić weryfikację konfiguracji Web API w teście jednostki.

+0

Witam Steven, widziałem, że niedawno wydałeś nową wersję pakietu integracji Web Api, ale ten problem nie został jeszcze naprawiony. – abatishchev

+0

@abatishchev: To prawda. v2.6.2 pakietu integracji Web API naprawia wyłącznie stany problemów [tutaj] (https://simpleinjector.codeplex.com/workitem/20987). Na razie musisz skorzystać z rozwiązania opisanego w mojej odpowiedzi lub napisać własną niestandardową rejestrację kontrolera, zamiast wywoływać 'RegisterWebApiControllers'. – Steven

+0

Witaj Steven, czy masz jakieś informacje/plany dotyczące rozwiązania tego problemu? – abatishchev

3

Rozwiązanie dla SI v3.x jest po prostu ...

container.RegisterWebApiControllers(
    GlobalConfiguration.Configuration, 
    Assembly.GetExecutingAssembly() 
); 

.. więc teraz zna zespół, aby szukać sterowników.

Powiązane problemy