2016-03-25 34 views
7

Abbiamo un progetto Web dnx46 che utilizza la scansione dell'assieme autofac durante l'avvio per registrare i tipi. Le nostre dipendenze project.json includono:Autofac non risolve i tipi dalla scansione dell'assembly in 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" 

Il nostro metodo startup.cs ConfigureServices assomiglia a questo:

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

Il nostro processo è che abbiamo diversi progetti che costruiamo quella goccia DLL che questo progetto avrà bisogno in una cartella bin personalizzata. All'avvio, scansioniamo quegli assembly per registrare i tipi con Autofac. Lo abbiamo fatto in un progetto proof of concept, e ha funzionato senza problemi. Nel nostro nuovo progetto, però, abbiamo le seguenti questioni:

  1. Se si tenta di risolvere un servizio in un costruttore controller, getta un errore che indica iniezione Microsoft dipendenza non può risolvere il servizio. Non sei sicuro del motivo per cui non sta utilizzando il provider di Autofac qui.
  2. Se risolviamo manualmente un singolo tipo all'avvio insieme alla scansione del nostro assembly, avremo un errore nella struttura del controller che indica che Autofac non è in grado di risolvere il servizio (utilizza il provider di Autofac qui, ma non trova ancora i nostri tipi).
  3. Se ispeziono il builder e il contenitore prima che ritorni in ConfigureServices, sembra che tutti i nostri tipi siano registrati. Tuttavia, se cambio il controller per iniettare IServiceProvider e poi provo a risolvere un servizio da esso, utilizza accuratamente il provider Autofac, ma ottengo sempre il valore null (nessun servizio trovato).

Dopo aver provato molte cose, ho preso la nostra prova di concetto di progetto e copiato verso la nostra nuova soluzione (nel caso in cui abbiamo perso qualche piccolo ambiente o qualcosa quando si imposta il nostro nuovo progetto), e il cattivo comportamento continuato. Sto iniziando a pensare che i nostri assembly stanno introducendo qualche bug (dal momento che sono le uniche cose che sono cambiate dopo la copia), ma Autofac non lancia un errore durante la scansione, e invece non usa i tipi che ha scansionato correttamente .

Modifica 1

ho creato e inviato un very simplified example che riproduce il problema che sto funzionando in. Dovresti essere in grado di tirarlo verso il basso ed eseguirlo per riprodurre l'errore. Si dovrebbe ottenere un errore nel costruttore del controller domestico che indica che la risoluzione del servizio non è riuscita.

Nota: quando si esegue questo esempio, esegue un file .bat che inserisce la DLL di uscita dal progetto di dominio nella cartella .nuget del profilo utente. Interfaccia

Edit 2

Split nella cartella astrazione basato sulla raccomandazione @Travis Illig. Una volta che l'ho fatto, la soluzione ha iniziato a funzionare. Lo abbiamo diviso nel nostro progetto "reale", ma non funziona. Ancora sperimentando per capire perché.

Edit 3

Così finalmente il nostro progetto di lavorare di nuovo.Problema finito per essere diverse cose:

  1. Abbiamo avuto una dipendenza progetto di un'astrazione elencato nel nostro progetto web, e siamo stati anche il caricamento e la scansione del dll da quell'assemblea (doppio caricamento). (Penso che questo sia stato il grosso problema.)
  2. Le nostre versioni NuGet erano pessime, quindi non penso che si stessero caricando correttamente. Stavamo usando 1.0.0-1, che è un formato prerelease non valido. Aggiornato a 1.0.0-b1, e le cose sembravano iniziare a funzionare meglio.

Questo mi ha portato più tempo a capire, e il mio più grande problema a questo punto è che Autofac fallirebbe silenziosamente. Vorrei davvero che esplodesse e mi desse qualche output di debug o qualcosa che indicasse che c'era un problema. Invece, tutto è sembrato scansionare e caricare bene, ma poi quando sei andato a usare il contenitore, nulla sarebbe risolto.

risposta

2

È probabile che gli assiemi vengano caricati in un ordine del genere in cui alcuni tipi non possono essere caricati a causa del mancato caricamento degli assiemi prerequisiti.

Ad esempio, supponiamo di avere un assembly A che contenga l'interfaccia IComponent. Dite anche di avere l'assembly B che contiene una classe Component che implementa IComponent. Se si carica prima l'assieme B, il tipo Component non sarà caricabile perché l'interfaccia implementata non è definita.

Quando si esegue la scansione del tipo, Autofac cerca di essere il più sicuro possibile e non esploderà se viene eseguito in tipi che non possono essere caricati. È possibile vedere nello scanning registration source dove utilizza un metodo di sicurezza speciale per eseguire il caricamento.

Nel codice spike, sto scommettendo che ci sono molti meno assiemi da caricare, quindi hai finito per caricare le cose nel giusto ordine. Felice incidente Quando si entra in progetti più grandi, è molto più facile cadere per controllare l'ordine di caricamento e causare problemi come questo.

+0

Quindi abbiamo finito per specificare un ordine di caricamento dell'assieme (quindi le astrazioni sono andate prima, quindi le classi base, ecc.). Lo stesso comportamento è continuato. Penso che quello che stai dicendo abbia ancora un senso, ma potrebbe essere più granulare di quanto speravo. Sono al punto in cui sto riappropriando le lezioni individualmente fino a quando riesco a ripetere il comportamento e poi decidere come affrontare il problema. Grazie per il puntatore. –

+0

E in realtà, il tuo puntatore al codice mi ha aiutato. Non avevo realizzato che potesse prendere una raccolta di assiemi e quindi creare una raccolta di tutti i tipi caricabili. Questo può aiutare con il problema dell'ordine. Vedrò se posso approfittarne. Aggiornamento –

+0

: Quindi cambiare l'ordine o caricare tutti gli assembly in una volta non ha funzionato. Così ho finito per creare un nuovo progetto che ha un assemblaggio con solo 1 interfaccia e 1 classe. Sperimentare esattamente lo stesso comportamento di cui sopra. Quando tornerò più tardi stasera, potrei spingere questo nuovo progetto a un github e vedere se qualcuno ha dei pensieri su quello che sta succedendo. –