2012-02-01 68 views
2

我有一個應用程序可能需要連接到多個數據庫。但是每個模塊只會連接到一個分貝。所以我認爲將db分離到每個模塊中可能是有意義的,這樣每個模塊都會自動解析數據庫,並且我不需要爲命名註冊而煩惱。但令我驚訝,似乎Autofac的模塊多的邏輯模塊代碼模塊(我錯了嗎?):IA模塊是Autofac的綁定上下文

[Test] 
public void test_module_can_act_as_scope_container() 
{ 
    ContainerBuilder builder = new ContainerBuilder(); 
    builder.RegisterModule(new Module1()); 

    IContainer c = builder.Build(); 
    var o = c.ResolveNamed<CB>("One"); 
    Assert.That(o.A.Name, Is.EqualTo("One")); 

    builder = new ContainerBuilder(); 
    builder.RegisterModule(new Module1()); 
    builder.RegisterModule(new Module2()); 
    c = builder.Build(); 
    var t = c.ResolveNamed<CB>("One"); 
    Assert.That(t.A.Name, Is.EqualTo("Two")); 
} 

和所使用的接口/模塊:

public interface IA 
{ 
    string Name { get; set; } 
} 

public class CA : IA 
{ 
    public string Name { get; set; } 
} 

public class CB 
{ 
    public CB(IA a) 
    { 
     A = a; 
    } 
    public IA A { get; private set; } 
} 

public class Module1 : Module 
{ 
    protected override void Load(ContainerBuilder builder) 
    { 
     builder.Register(c => new CA() { Name = "One" }).As<IA>(); 
     builder.RegisterType<CB>().Named("One", typeof(CB)); 
    } 
} 

public class Module2 : Module 
{ 
    protected override void Load(ContainerBuilder builder) 
    { 
     builder.Register(c => new CA() { Name = "Two" }).As<IA>(); 
     builder.RegisterType<CB>().Named("Two", typeof(CB)); 
    } 
} 

回答

2

是,你是對的。

模塊僅用於將配置拆分爲多個獨立的部分。它們不以任何方式限定配置範圍。擁有模塊實際上與將所有模塊的Load方法代碼合併爲單一配置方法然後構建容器相同。

在你的情況下,你的Module2實際上覆蓋接口的註冊從Module1

我也有興趣找到問題的解決方案。我已經來到了以下方法:

鍵控服務

var key = new object(); 
builder.Register(c => new CA() { Name = "Two" }).Keyed<IA>(key); 
builder.RegisterType<CB>().Named("Two", typeof(CB)) 
    .WithParameter(new ResolvedParameter(
     (pi, ctx) => pi.Type == typeof(IA), 
     (pi, ctx) => ctx.ResolveKeyed<IA>(key) 
)); 

優點:

您可以控制哪些IA實例將每個模塊中注入。

反政府:

  1. 這是一個相當大量的代碼
  2. 它不會使IA組件「內在」的模塊 - 其他模塊仍然可以使用簡單的Resolve<IA>解決。模塊不是孤立的。

希望這有助於

UPDATE

在某些情況下,可能會更容易,並坦言從設計的角度來看更正確,做出這樣說:

代表註冊

builder.Register(ctx => new CB(new CA { Name = "Two" })) 
    .Named("Two", typeof(CB)); 

個優點:

  1. 你不要暴露你的模塊特定CA其他模塊

反政府:

  1. 如果CACB具有複雜的依賴關係和大量的構造函數的參數,你會最終與構建代碼混亂
  2. 如果你需要在內部的幾個地方使用CA一個模塊,你必須找到一種方式,以避免複製粘貼

嵌套容器實例

而另一種選擇是讓每個模塊內的獨立Container。通過這種方式,所有模塊都可以擁有其私有容器配置。但是,AFAIK,Autofac不提供任何內置方式來以某種方式鏈接幾個Container實例。儘管我認爲實施這個應該不是很困難。

+0

接受。 更新前的帖子正是我想要避免的。我也想過更新的版本,但是想知道是否有更好的解決方案。在Autofac可以支持分層模塊之前似乎沒有其他辦法。 Peter的解決方案確實有效,但它太hacky .. – TcMaster 2012-02-02 14:37:41

1

您可以使用nestet生命週期範圍。這些形成了一個層次結構,在這個層次結構中,子域可以解析在超級鏡子中註冊的服此外,還可以在每個子範圍註冊獨特的服務,這樣的:有了這個設置

var cb = new ContainerBuilder(); 
cb.RegisterModule<CommonModule>(); 
var master = cb.Build(); 

var subscope1 = master.BeginLifetimeScope(cb2 => cb2.RegisterModule<Module1>()); 
var subscope2 = master.BeginLifetimeScope(cb2 => cb2.RegisterModule<Module2>()); 

,在Module1服務將只提供給從subscope1解決實例。

+0

這對我來說確實有效,只要我將註冊的組件標記爲單例,那麼一旦生命期範圍被處置,它們就不會被釋放。但從我的觀點來看,這太冒險了。不管怎麼說,還是要謝謝你! – TcMaster 2012-02-02 14:41:37

+0

我同意,這種方法可以在某些情況下使用。但是終生範圍是爲不同目的而設計的。這種方式無法解決一個相當常見的用例:將CB組件暴露給根作用域,同時向其提供來自嵌套模塊作用域的內部組件。實現這一目標的唯一方法是在開始嵌套作用域後更新根容器......並且我無法判斷這是否可行。 – 2012-02-02 17:22:09