2

私はasp.net-mvcサイトを持っており、IOCを行うためにLinFuを使用しています。いくつかのアクションに依存関係があり、コントローラーに注入したいのですが、依存関係に依存するアクションを呼び出す場合にのみ依存関係を初期化したいという問題が発生しました。

だから私のコントローラーでは、私のコントローラーにこのコードがあります:

   public PersonController
   {

    private IPeopleImporter _peopleImporter;

    public override void Initialize(LinFu.IoC.Interfaces.IServiceContainer source)
    {
        _peopleImporter= source.GetService<IPeopleImporter>();
        base.Initialize(source);
    }

    public JsonResult GetDetails(int id)
    {
        var p = _peopleImporter.Get(id);
        var personDetails = new {p.Id, p.FirstName, p.LastName, StandardId = p.StandardIdLogin, p.PersonNumber};
        return Json(personDetails);
    }
   }

PeopleImporterを開始するにはかなりの費用がかかるため、私の問題は2つのことを解決したいということです。

  1. IPeopleImporterの実装を「プラグイン可能」にして、インターフェイスでコントローラーにIOCできるようにしたい

  2. アクションがたくさんあるので、ユーザーがIPeopleImporterを必要とする特定のアクションを呼び出さない場合に、IPeopleImporterを開始するコストをかけたくありません。上記のコードでは、PersonControllerを呼び出すたびにその開始を行っているようです

私の開始コードは次のようなものです。

this.AddService(typeof(IPeopleImporter), typeof(DatabaseImporter), LifecycleType.Singleton);

これは一般的なパターン/問題のようです。推奨される解決策はありますか?それまでの間、代替案(パフォーマンスへの影響を回避するために、コントローラー内の概念の実装を単純に「新規」にすること(およびIOCを回避すること)はありますか?

4

3 に答える 3

3

最初のステップは、このアクションを別のコントローラーに入れることです。このコントローラーの他のアクションの初期化料金を支払う必要がないようにします。

次に、アンチパターンと見なされる現在使用している Service Locator ではなく、実際の IoC パターンを使用します。IoC では、コントローラーは、使用されている特定の DI フレームワークについて何も認識してはなりません。IoC では、コントローラーはすべての依存関係をコンストラクターの引数として受け取ります

public PersonsController: Controller
{
    private readonly IPeopleImporter _peopleImporter;
    public PersonsController(IPeopleImporter peopleImporter)
    {
        _peopleImporter = peopleImporter;
    }

    public ActionResult GetDetails(int id)
    {
        var p = _peopleImporter.Get(id);
        var personDetails = new { p.Id, p.FirstName, p.LastName, StandardId = p.StandardIdLogin, p.PersonNumber };
        return Json(personDetails, JsonRequestBehavior.AllowGet);
    }
}
于 2012-07-27T13:11:15.357 に答える
1

次のトリックをタスクに使用できます。IPeopleImporter のインスタンスではなく、このタイプのファクトリを注入できます。

private readonly Func<IPeopleImporter> _peopleImporterFactory;

必要なアクションでこのファクトリを使用します。

var peopleImporter = __peopleImporterFactory();

例:

 public PersonController

{

private readonly Func<IPeopleImporter> _peopleImporterFactory;

public PersonController(Func<IPeopleImporter> peopleImporterFactory)
{
    _peopleImporterFactory = peopleImporterFactory;
}

public JsonResult GetDetails(int id)
{
    var peopleImporter = _peopleImporterFactory();
    var p = peopleImporter.Get(id);
    var personDetails = new {p.Id, p.FirstName, p.LastName, StandardId = p.StandardIdLogin, p.PersonNumber};
    return Json(personDetails);
}

}

于 2012-07-30T07:37:03.337 に答える
0

私は通常、依存関係をパラメーターとして自分のアクションに注入することでこれを解決します。一般的または安価な依存関係はクラス レベルで注入できますが、異常または高価な依存関係はパラメーターとして挿入されます。

Enterprise Library Unity のサンプル コードを次に示しますが、変更することができます。

public class UnityActionInvoker : ControllerActionInvoker
{
    readonly IUnityContainer container;

    public UnityActionInvoker(IUnityContainer container)
    {
        this.container = container;
    }

    protected override object GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor)
    {
        Type parameterType = parameterDescriptor.ParameterType;

        if (parameterType != typeof(string) && !parameterType.IsValueType && container.IsRegistered(parameterType))
        {
            return container.Resolve(parameterType).AssertNotNull();
        }

        return base.GetParameterValue(controllerContext, parameterDescriptor);
    }
}

コントローラーのコンストラクター (またはすべてのコントローラーの共通基本クラス) でControllerActionInvoker設定することにより、これをフックできます。Controller.ActionInvoker

コントローラーは次のようになります。

   public PersonController
   {
    public JsonResult GetDetails(int id, IPeopleImporter _peopleImporter /*injected*/)
    {
        ...
    }
   }
于 2012-07-27T13:10:22.677 に答える