5

Nei test di integrazione sto utilizzando lo stesso SimpleInjector.Container che costruisco nel progetto Web API che sto testando.container.RegisterWebApiControllers (GlobalConfiguration.Configuration) causa InvalidOperationException

Ma questa linea in classe radice composizione:

container.RegisterWebApiControllers(GlobalConfiguration.Configuration); 

causa un'eccezione:

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 

Dopo aver commentato che tutto funziona bene, sia la web app in sé ed i test.

Quindi la domanda è:

  • Qual è la ragione per l'eccezione?
  • (ed è questo metodo necessario davvero?)

Ecco il codice per HttpClientFactory (una classe di supporto per creare HttpClient con le intestazioni appropriate, come la chiave API o autorizzazione):

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

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

Potrebbe pubblicare i dettagli InnerException e StackTrace? Avete alcuni reindirizzamenti vincolanti nel vostro file di configurazione? –

+1

Sono d'accordo con @DarinDimitrov, per favore ci dia la traccia dello stack completo. È difficile ragionare su questo senza questi dettagli. – Steven

+0

@Darin: aggiornato, grazie! I reindirizzamenti vincolanti sono molto simili a quelli che ho in Web.config. – abatishchev

risposta

5

Se guardiamo da vicino la traccia dello stack possiamo vedere esattamente cosa sta succedendo qui. Il metodo di estensione RegisterWebApiControllers chiama il metodo GetControllerTypes nell'istanza IHttpControllerTypeResolver che preleva dallo HttpConfiguration e passa lo IAssembliesResolver che viene anche recuperato dalla configurazione. Il metodo GetControllerTypes chiamato (WebHostHttpControllerTypeResolver) chiama nello GetControllerTypes dello DefaultHttpControllerTypeResolver che causerà infine una chiamata a GetReferencedAssemblies della classe System.Web.Compilation.BuildManager.

Il System.Web.Compilation.BuildManager tuttavia, non può essere chiamato in anticipo nella pipeline ASP.NET o al di fuori del contesto di ASP.NET. Dato che sei in prova, lo BuildManage genererà l'eccezione che stai riscontrando.

Quindi la soluzione (o "trucco" così sarà) qui è sostituire il valore predefinito IAssembliesResolver durante il test dell'unità. Immagino che resolver a guardare come questo:

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

E 'un po' un peccato che si ha a che fare questo, soprattutto perché iniettore Semplice stato progettato per essere verificabile. Sembra che abbiamo trascurato questo problema integrando il metodo di estensione RegisterWebApiControllers così profondamente con l'API Web. Dobbiamo fare un passo indietro e pensare a come rendere più semplice la verifica della configurazione dell'API Web all'interno di un test di unità.

+0

Ciao Steven, ho visto che hai recentemente rilasciato la nuova versione del pacchetto di integrazione Web Api, ma questo problema non era ancora stato risolto. – abatishchev

+0

@abatishchev: è corretto. v2.6.2 del pacchetto di integrazione dell'API Web risolve esclusivamente gli stati problematici [qui] (https://simpleinjector.codeplex.com/workitem/20987). Per ora, dovrai fare i conti con la soluzione descritta nella mia risposta, o scrivere la tua registrazione personalizzata del controller invece di chiamare "RegisterWebApiControllers". – Steven

+0

Ciao Steven, hai qualche notizia/programma su come risolvere questo problema, per favore? – abatishchev

3

Una soluzione per SI v3.x è solo ...

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

.. quindi ora si conosce l'assemblea per la ricerca per i controllori.

Problemi correlati