6

データを永続化するために汎用リポジトリパターンを使用しています。PageLoadで、(IRepositoryから)新しいリポジトリを作成し、PageUnloadで、それを破棄します。

MasterPage / Pageは、プレゼンターに渡すオブジェクトのインスタンス化を担当する必要がありますか、それともプレゼンターがこれを担当する必要がありますか?プレゼンターに渡されるインターフェイスをモックする方が簡単なので、ページ(表示)よりもプレゼンターのテストに関心があります。

サンプルページ

public partial class _Default : System.Web.UI.Page
{
    private IRepository _repo;
    protected void Page_Load(object sender, EventArgs e)
    {
        if (_repo == null)
            _repo = new Repository();
        ConnectPresenter();
    }

    private void ConnectPresenter()
    {
        _DefaultPresenter presenter = new _DefaultPresenter(_repo);
    }

    private void Page_Unload(object sender, EventArgs e)
    {
        if (_repo != null)
            _repo.Dispose();
    }
}

この場合、StructureMapやNinjectなどのDIフレームワークは役に立ちますか?このような物の処分を担当するのでしょうか?

4

2 に答える 2

6

Page クラスもプレゼンターも、その依存関係の構築またはライフサイクルの管理を直接処理する必要はありません。これらはすべて、コンテナーによって処理される必要があります。コンストラクター インジェクションは WebForms では機能しないため、必要な依存関係をクラスのプロパティとして公開する必要があります。たとえば、クラスを次のように変更できます。

public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
    }

    public _DefaultPresenter Presenter { get; set; }
}

ページはプレゼンターに挿入されるため、リポジトリへの参照は必要ありません。

この回答の残りの部分は StructureMap に固有のものです。詳細は他のコンテナーでは異なる場合があります。

セッター インジェクションを有効にするには、データを入力するプロパティを StructureMap に指示する必要があります。1 つの方法は、[SetterProperty] 属性をプロパティ自体に適用することです。ただし、クラス内に StructureMap の詳細を含めると、少し侵略的に感じる可能性があります。もう 1 つの方法は、注入するプロパティ タイプを認識できるように StructureMap を構成することです。例えば:

protected void Application_Start(object sender, EventArgs e)
{
    ObjectFactory.Initialize(x =>
    {
        x.Scan(scan =>
        {
            scan.TheCallingAssembly();
            scan.WithDefaultConventions();
        });
        x.ForRequestedType<IRepository>().TheDefaultIsConcreteType<Repository>().CacheBy(InstanceScope.Hybrid);
        x.SetAllProperties(set => set.WithAnyTypeFromNamespaceContainingType<IRepository>());
    });
}

SetAllProperties メソッドを使用すると、StructureMap に入力する必要があるプロパティを認識する方法を伝えることができます。この場合、StructureMap にすべてのプレゼンターを注入するように指示しています (プレゼンターがすべて同じ名前空間にあると仮定します)。

リクエストごとに setter インジェクションを実行する必要があります。StructureMap では、BuildUp() メソッドを使用して依存関係を既存のインスタンスに注入します。各ページまたはページの基本クラスの Init イベントまたは Load イベントで実行できますが、これも侵略的です。コンテナーをページ クラスから完全に除外するには、アプリケーションの PreRequestHandlerExecute イベントを (global.asax または IHttpModule で) 使用できます。

protected void Application_PreRequestHandlerExecute(object sender, EventArgs e)
{
    var application = (HttpApplication)sender;
    var page = application.Context.CurrentHandler as Page;
    if (page == null) return;
    ObjectFactory.BuildUp(page);
}

最後に、IRepository を明示的に Dispose したい場合は、EndRequest イベントでそれを処理できます。

protected void Application_EndRequest(object sender, EventArgs e)
{
    var disposable = ObjectFactory.GetInstance<IRepository>() as IDisposable;
    if (disposable != null) disposable.Dispose();
}

これは正しく機能することに注意してください。これは、初期化で StructureMap に Hybrid によって IRepository をキャッシュするように指示したためです。これは、「各 HTTP リクエスト (または Web サイト内で実行されていない場合はスレッド) ごとに同じインスタンスを提供する」ことを意味します。EndRequest で IRepository を取得すると、リクエスト全体で使用されたものと同じものを受け取り、それを破棄できます。

于 2009-11-07T17:54:58.023 に答える
2

はい、 ASP.NET で DI を使用するためのウォークスルーの 1 つを調査する価値があります。

はい、適切な時点での要求ごとの動作オブジェクトの破棄は、通常、コンテナーの ASP.NET との統合によって管理されます。

典型的な配置は、オブジェクトの作成が Page およびApplication/ Modules から内部に流れ込むことです。通常、クラスのプロパティをマーク[Inject]しますPageが、トライアドをどのように配置したかによって異なります。プレゼンターは通常、Constructo Injection を使用して、テストまたは ASP.NET コテキストに関係なく、必要なものを宣言できます。その後、実行時に依存関係は DI によって満たされます。テスト時には引き続き DI を使用できますが、それ以外の場合は、SUT と共に多数の Fake を作成し、それらを Presenter に渡す方が自然かもしれません。

トライアド アレンジメント wrt テストに関しては、ASP.NET MVC を対象としているにもかかわらず、Justin Etheredge による xUnit.net での Ninject の使用に関する MSDN Mag の記事が非常に役立つことがわかりました。

于 2009-11-05T16:25:16.563 に答える