2015-11-19 31 views
2

我們使用Autofac for DI創建了WebApi解決方案。我們把我們的autofac引導到一個單獨的項目中。這樣,我們的WebApi項目只會引用我們的Bootstrap和Contracts項目。然後我們的引導程序引用所有其他程序集並將所有內容連接在一起。我喜歡這種設計來分離顧慮。Autofac:如何加載已引用但未直接使用的程序集

我們可以手動加載我們的程序集,如下所示 - 我們的「AutofacModule」類包含註冊每個模塊(程序集)所需的信息。

ContainerBuilder builder = new Autofac.ContainerBuilder(); 
builder.RegisterModule(new Business.AutofacModule()); 
builder.RegisterModule(new Data.AutofacModule()); 
builder.RegisterModule(new Services.AutofacModule()); 
etc... 

這可行,但需要硬編碼每個程序集。我們試圖使這種動態變化,以便我們可以如下遍歷所有引用的程序集。

var assemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>(); 
foreach (var assembly in assemblies) 
{ 
    builder.RegisterAssemblyModules(assembly); 
} 

這應該工作,但沒有。問題是.Net確定各種程序集並沒有從bootstrap項目中實際使用,也沒有加載它們(試圖優化?)。所以我們的一些程序集從不加載。

我也嘗試了以下循環通過bin目錄來查找所有程序集。但是,在編譯期間,.Net不會將未引用的程序集移動到bin目錄中,因此它們也不在其中。

string assemblyPath = System.IO.Path.Combine(
    System.AppDomain.CurrentDomain.BaseDirectory, "bin"); 
var allAssemblies = new List<Assembly>(); 
foreach (string dll in Directory.GetFiles(assemblyPath, "*.dll")) 
{ 
    allAssemblies.Add(Assembly.LoadFile(dll)); 
} 

我已經設置程序集複製本地哪些不起作用。我閱讀了關於「複製本地」的錯誤,並嘗試瞭解決方法,但這種方法也沒有奏效。

有沒有人能夠解決這個問題?這似乎是Autofac將提供一個解決方案,但我發現自己的文檔解決Page: http://autofac.readthedocs.org/en/latest/faq/isolate-autofac.html

下面兩個問題是相似的,但沒有一個提出的解決方案克服了一個事實,即需要組件是不在bin目錄中。

Not all assemblies are being loaded into AppDomain from the bin folder

Loading all referenced assemblies .NET even if not used explicitly in code

最後,我很好奇,這是一個Autofac具體的問題?其他DI容器如何解決這個問題?我發現NInject有類似的問題。 Loading unreferenced dll MVC Ninject

+0

我使用Autofac加載動態上使用「.RegisterAssemblyModules」方法運行時從組件模塊,以及它的工作原理像一個魅力。唯一的要求是任何應該加載的程序集都必須以特定的後綴結尾(對於Directory.GetFiles),如「* .Plugin.dll」。 – Dietz

+0

謝謝@迪斯。我們的問題是引導項目引用,但不直接使用,我們的許多程序集。所以我認爲編譯器認爲它們不是必須的,所以它不會將它們移動到bin目錄中。所以我沒有什麼要加載的。 –

+0

我的所有「* .Plugin.dll」文件都通過正在收集程序集的發佈版的後構建操作移動到\ bin文件夾中。 – Dietz

回答

2

//簡短的回答

你見過這樣的:http://docs.autofac.org/en/latest/faq/iis-restart.html看起來你可以掃描引用的程序集,並強迫他們加載。

//建議(或意見,如果你喜歡)

我個人沒有加載的程序集的未準備使用,只是爲了能夠有對引導一個單獨的項目。我沒有看到它在自己的項目中的好處。請記住,DI就是這樣,你正在注入你的「那個」項目的依賴關係。每個項目都可以擁有自己的依賴關係,關注點的分離來自引導類,而不是它自己的項目。如果您需要將您的業務邏輯項目分解爲公司其他項目將使用的nuget包,那麼您不希望他們也不得不下載DI項目包,而後者現在需要其他可能永遠不會使用的包。如果您的依賴關係包含在需要它們的項目中,則它變得模塊化且可擴展。這部分答案當然是有爭議的,但至少應該考慮。

5

這應該對你有所幫助。它從bin文件夾中獲取所有程序集,以名稱MyModule開頭。

//builder.RegisterType(typeof(IFoo)).AsImplementedInterfaces(); 
     ContainerBuilder builder = new ContainerBuilder(); 

     string[] assemblyScanerPattern = new[] { @"MyModule.*.dll"}; 

     // Make sure process paths are sane... 
     Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory); 

     // begin setup of autofac >> 

     // 1. Scan for assemblies containing autofac modules in the bin folder 
     List<Assembly> assemblies = new List<Assembly>(); 
     assemblies.AddRange(
      Directory.EnumerateFiles(Directory.GetCurrentDirectory(), "*.dll", SearchOption.AllDirectories) 
        .Where(filename => assemblyScanerPattern.Any(pattern => Regex.IsMatch(filename, pattern))) 
        .Select(Assembly.LoadFrom) 
      ); 


     foreach (var assembly in assemblies) 
     { 
      builder.RegisterAssemblyTypes(assembly) 
       .AsImplementedInterfaces(); 
     } 
     var container = builder.Build(); 

這將加載那些甚至沒有被引用的程序集。

+0

builder.RegisterAssemblyTypes接受程序集數組,因爲每個都不是必需的 – hungryMind

2
var assemblies = Directory.EnumerateFiles(AppDomain.CurrentDomain.BaseDirectory, "*.dll", SearchOption.TopDirectoryOnly) 
    .Where(filePath => Path.GetFileName(filePath).StartsWith("your name space")) 
    .Select(Assembly.LoadFrom); 

var builder = new ContainerBuilder(); 

builder.RegisterAssemblyTypes(assemblies.ToArray()) 
    .Where(t => typeof(ITransientDependency).IsAssignableFrom(t)) 
    .AsImplementedInterfaces(); 
1

如果你有你的解決方案多個項目,每一個都有自己的IoC容器類,使用以下方法來加載所有組件,然後註冊在大會各模塊。

這是ContainerBuilder的擴展方法。

public static class ContainerBuilderExtensions 
{ 
    public static void ScanAssembly(this ContainerBuilder builder, string searchPattern = "SolutionName.*.dll") 
    { 
     var path = AppDomain.CurrentDomain.BaseDirectory; 
     foreach (var assembly in Directory.GetFiles(path, searchPattern).Select(Assembly.LoadFrom)) 
     { 
      builder.RegisterAssemblyModules(assembly); 
     } 
    } 
} 

以上可以在您ContainerBuilder的實例如下叫:

builder.ScanAssembly() 
相關問題