2009-12-18 79 views
2

我有一個演示,需要一個服務和視聽合同作爲其構造函數的參數:依賴注入演示

public FooPresenter : IFooPresenter { 
    private IFooView view; 
    private readonly IFooService service; 

    public FooPresenter(IFooView view, IFooService service) { 
     this.view = view; 
     this.service = service; 
    } 
} 

我解決我的Autofac服務:

private ContainerProvider BuildDependencies() { 
    var builder = new ContainerBuilder(); 
    builder.Register<FooService>().As<IFooService>().FactoryScoped(); 

    return new ContainerProvider(builder.Build()); 
} 

在我的ASPX頁面(查看執行):

public partial class Foo : Page, IFooView { 
    private FooPresenter presenter; 

    public Foo() { 
     // this is straightforward but not really ideal 
     // (IoCResolve is a holder for how I hit the container in global.asax) 
     this.presenter = new FooPresenter(this, IoCResolve<IFooService>()); 

     // I would rather have an interface IFooPresenter so I can do 
     this.presenter = IoCResolve<IFooPresenter>(); 
     // this allows me to add more services as needed without having to 
     // come back and manually update this constructor call here 
    } 
} 

問題是FooPresenter的構造函數期望特定的Page,不是爲容器創建一個新的。

我可以提供一個視圖的特定實例,即當前頁面,僅用於此分辨率的容器?這是否有意義,或者我應該以另一種方式做到這一點?

回答

2

解決通過什麼我喜歡叫的方式數據解決Autofac中依賴關係時的參數是通過使用生成的工廠

(更新:this question討論相同的問題,my article顯示如何避免大量的工廠代表)。

你的問題的解決方案將是這個樣子:

首先聲明一個工廠委託thath 接受數據參數:

public delegate IFooPresenter FooPresenterFactory(IFooView view); 

主講雲不變:

public FooPresenter : IFooPresenter { 
    private IFooView view; 
    private readonly IFooService service; 

    public FooPresenter(IFooView view, IFooService service) { 
     this.view = view; 
     this.service = service; 
    } 
} 

下一步Autofac容器設置:

var builder = new ContainerBuilder(); 
builder.Register<FooService>().As<IFooService>().FactoryScoped(); 
builder.Register<FooPresenter>().As<IFooPresenter>().FactoryScoped(); 
builder.RegisterGeneratedFactory<FooPresenterFactory>(); 

現在在你的頁面,您可以在代碼兩行首先,把工廠,然後調用工廠做的分辨率您解決主持人:

public partial class Foo : Page, IFooView { 
    private FooPresenter presenter; 

    public Foo() { 
     var factory = IoCResolve<FooPresenterFactory>(); 
     this.presenter = factory(this); 
    } 
} 
+0

優秀的解決方案。感謝您指出。直到現在我還沒有真正掌握生成的工廠。 – 2009-12-18 08:03:13

+0

我正在研究如何在抽象層次上做到這一點。我當前的框架允許用'[Presenter(typeof(FooPresenter))]'修飾視圖(因此消除了樣板解析代碼)。對於生成的工廠,如果沒有更多的元數據,我不會知道需要解決哪個工廠類型。我可能會使用'builder.RegisterGeneratedFactory >();'在通過反射發現視圖類型的擴展方法'RegisterPresenter '後面。無論如何,謝謝你的靈感! – 2009-12-18 08:24:54

+0

你也可以嘗試我的通用工廠示例(鏈接到我的示例中的文章)。您只需註冊一個可以動態構建任何演示者的通用工廠。應該甚至可以將它與Presenter屬性相耦合,以最小化樣板解析代碼和樣板容器設置:) – 2009-12-18 08:43:29

0

我真的解決了這個確切的問題,並圍繞它構建了一個框架。我使用Autofac parameters將現有視圖傳遞給演示者分辨率調用。

首先,我所定義從Autofac的派生的自定義解決界面:

public interface IMvpContext : IContext 
{ 
    T View<T>(); 
} 

這使我要註冊的解析視圖演示:使用它包裝Autofac的IContext擴展方法

builder.RegisterPresenter(c => new FooPresenter(
    c.View<IFooView>(), 
    c.Resolve<IFooService>())); 

IMvpContext的執行中:

public static IConcreteRegistrar RegisterPresenter<T>(
    this ContainerBuilder builder, 
    Func<IMvpContext, T> creator) 
{ 
    return builder 
     .Register((context, parameters) => creator(new MvpContext(context, parameters))) 
     .FactoryScoped(); 
} 

我定義表示視圖參數的參數類型:

public class MvpViewParameter : NamedParameter 
{ 
    public static readonly string ParameterName = typeof(MvpViewParameter).AssemblyQualifiedName; 

    public MvpViewParameter(object view) : base(ParameterName, view) 
    {} 
} 

它使用自己的組件限定的類型名稱作爲參數名稱。這與合法參數衝突的可能性非常低。

MvpContext將所有標準分辨率調用傳遞給基本上下文。對於視圖,它解決了與著名的名稱的參數:

public sealed class MvpContext : IMvpContext 
{ 
    private IContext _context; 
    private IEnumerable<Parameter> _resolutionParameters; 

    public MvpContext(IContext context, IEnumerable<Parameter> resolutionParameters) 
    { 
     _context = context; 
     _resolutionParameters = resolutionParameters; 
    } 

    #region IContext 

    // Pass through all calls to _context 

    #endregion 

    #region IMvpContext 

    public T View<T>() 
    { 
     return _resolutionParameters.Named<T>(MvpViewParameter.ParameterName); 
    } 
    #endregion 
} 

解決主持人的調用提供視圖參數:

public partial class Foo : Page, IFooView 
{ 
    private readonly FooPresenter presenter; 

    public Foo() 
    { 
     this.presenter = IoCResolve<IFooPresenter>(new MvpViewParameter(this)); 
    } 
} 
+0

這是不必要的複雜。使用內置生成的工廠內容來完成此操作,您可以刪除整個MvpContext參數。 – 2009-12-18 07:28:16

+0

(請參閱@Peter回答關於此方法的進一步討論的評論。) – 2009-12-22 15:40:29