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のコンストラクターが、コンテナーが新しいページを作成するためではなく、特定のページを予期していることです。

この解像度だけで、ビューの特定のインスタンスである現在のページをコンテナーに提供できますか?それは理にかなっていますか、それとも私はこれを別の方法で行う必要がありますか?

4

2 に答える 2

2

Autofacで依存関係を解決するときに、データパラメータと呼ぶのが好きなものを渡すことを解決する方法は、生成されたファクトリを使用することです。

(更新:この質問では同じ問題について説明しています。私の記事では、大量のファクトリデリゲートを回避する方法を示しています)。

問題の解決策は次のようになります。

まず、データパラメータのみを受け入れるファクトリデリゲートを宣言します。

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

これで、ページで2行のコードで、最初にファクトリを取得し、次にファクトリを呼び出して解決を行うことで、プレゼンターを解決できます。

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

    public Foo() {
        var factory = IoCResolve<FooPresenterFactory>();
        this.presenter = factory(this);
    }
}
于 2009-12-18T07:25:28.190 に答える
0

私は実際にこの正確な問題を解決し、その周りにフレームワークを構築しました。Autofacパラメーターを使用して、既存のビューをプレゼンター解決呼び出しに渡しました。

まず、Autofacから派生したカスタム解像度インターフェイスを定義しました。

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

これにより、ビューを解決するプレゼンターを登録できました。

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

AutofacIContextを次の実装でラップする拡張メソッドを使用し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));
    }
}
于 2009-12-18T06:20:20.153 に答える