2016-11-25 6 views
0

私は成長し、私が取り組んでいるアプリケーションの開発にかなり追加した、すでにセットアップされたNinject DIベースのアプリケーションで作業しなければならなかったので才能を発揮しました。Ninjectによる依存性注入は異なるインスタンスで同じオブジェクトを共有します

ここで私が訂正したい問題が見つかりました。私は継承を使用して回避することができましたが、よりクリーンなソリューションを望みます。

私は異なるサービスとリポジトリに注入するために2つの接続が必要です。私はその後、同じUnitOfWorkを持つ正しいサービスに正しくリンクされるようにリポジトリを必要とします。

私は、継承と専門化なしでは不可能なことを尋ねているかもしれないと思いますが、それが私が求めている理由です。

メインのRepositoryクラスとUnitOfWorkクラスのサブクラスを作成することでこれを解決することができましたが、基本クラスを実装すること以外は何もしません。 私はちょうどコンストラクタから離れて基本的に空の中括弧を持つスーパークラスの機能に完全に依存しているサブクラスのアイデアが好きではありません、私には、この問題を解決するために真のOOPのように見えません。そこで私は可能な限りDIで1つのクラスのソリューションを利用するより良いソリューションを模索しました。

はあなたが目的であるものを見ることができます下のコードを見て:あなたは私は完全に変更を元に戻すためについて話されているソリューションを無視することができるかどう

は、これは私が残されていますものです。私が知りたいのは何

... 

public class UnitOfWork : IUnitOfWork 
{ 
    private static readonly log4net.ILog log = log4net.LogManager.GetLogger("UnitOfWork"); 
    public DbContext DataContext { get; set; } 

    public UnitOfWork(string connectionString) 
    { 
     DataContext = new DbContext(connectionString); 
    } 

    public void Commit() 
    { 
     ... 
    } 
} 

... 

public class Repository<T> : IRepository<T> where T : class 
{ 
    public IUnitOfWork unitOfWork { get; set; } 
    private readonly IDbSet<T> dbSet; 

    //private static readonly log4net.ILog log = log4net.LogManager.GetLogger("Repository"); 

    public Repository(IUnitOfWork unitOfWork) 
    { 
     this.unitOfWork = unitOfWork; 
     dbSet = this.unitOfWork.DataContext.Set<T>(); 
    } 
    ... 
} 
... 

public class IPOPDataModules : NinjectModule 
{ 
    public override void Load() 
    { 
    Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope().WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["IPOP_BE_TESTEntities"].ConnectionString); 
    Bind<IRepository<tOrder>>().To<Repository<tOrder>>().InRequestScope(); 
    } 
} 

... 

public class DataModules : NinjectModule 
{ 
    public override void Load() 
    { 
    Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope().WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["IPOP_BAPSEntities"].ConnectionString); 
    Bind<IRepository<Data.Quote>>().To<Repository<Data.Quote>>().InRequestScope(); 
    } 
} 

... 

public class QuoteService : IQuoteService 
{ 
    private IUnitOfWork unitOfWork; 
    private IRepository<Data.Quote> quoteRepository; 
    public QuoteService(IUnitOfWork unitOfWork, IRepository<Data.Quote> quoteRepository) 
    { 
     ... 
    } 
} 

... 

public class IPOPService : IIPOPService 
{ 
    private IUnitOfWork unitOfWork; 
    private IRepository<Data.tOrder> tOrderRepository; 

    public IPOPService(IUnitOfWork unitOfWork, IRepository<Data.tOrder>) 
    { 
     ... 
    } 
} 

され、二つの異なる接続によって同じUnitOfWorkRepositoryオブジェクトを共有することが可能であり、それらはIPOP_BAP接続用QuoteService、IPOP_BE_TEST接続用の各サービス(IPOPServiceになど、異なるインスタンスを注入しています)

上記のコードは、私が欲しいと望んでいたものではありませんが、これはこれを動作させるために遊びたいアーキテクチャのようなものです。

答えて

0

あなたの質問は私にとってはっきりしていません。しかし、以下の2つのスコープのドキュメントを確認してください。

  • InCallScopeは、解像度ツリーごとに1つのインスタンスしか作成されません。私は通常、作業範囲のデスクトップアプリケーションでこの範囲を使用します。ドキュメントhereを参照してください。このためにはNinject.Extensions.NamedScope拡張が必要です。
  • InRequestScopeの場合、Webアプリケーションでは、HTTP要求ごとに1つのインスタンスしか作成されません。私は通常この作業範囲を作業単位に使用します。ドキュメントhereを参照してください。これにはNinject.Web.Commonパッケージが必要です。
+0

@ Zoltanの入力をありがとう、私はMVCサイトで作業していると私はうまくいけばいくつかの混乱に対処する必要があります質問にいくつかの変更を加えました。上記の答えに関して、私は何とか正しい 'UnitOfWork'と' Repository'(適切なdb接続で)を上記の2つの異なるサービスにマップしたいと考えています。可能であれば、可能な場合があるいくつかのNinjectロジックが欠けていると思います。 – Saleh

0

あなたが探しているのは、Ninjectバインディングスコープです。バインディングを宣言するたびに、Ninjectは、そのサービスの新しいインスタンスを作成する必要があるかどうか、または以前に構築されたインスタンスを返す必要があるかどうかを確認するために、アクティブ化プロセスが使用するバインディングに代理人を提供します。あなたはNinjectでシングルトンを実装する場合

ので、あなたは、単に宣言することは、このようになりますバインディング:

Bind<IRepository<Data.Quote>>().To<Repository<Data.Quote>>().InSingletonScope(); 

InSingletonScope()InRequestScope()は、単に砂糖です(またはInRequestScope拡張メソッドの場合)しかし、InScope(Func<Ninject.Activation.IContext, object> scope)の方法ではIBindingInSyntax<T>になります。特定の状況でNinjectが同じサービスインスタンスを返すようにしたい場合は、カスタムスコープを実装するだけです。

あなたの質問が正しく理解されている場合、リクエストがアプリケーションにヒットしたときに、アプリケーション内のすべてのサービスにRepository<T>IUnitOfWorkの同じインスタンスが確実に注入されます。この場合、あなたは、単にこのようなバインディング記述する必要があります:

Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope().WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["IPOP_BE_TESTEntities"].ConnectionString); 
Bind<IRepository<tOrder>>().To<Repository<tOrder>>().InRequestScope(); 

をしかし、あなたの問題は、次の2つの別々のバインディングを持つ2つの別々のモジュールを、持っているように見えます。どの接続文字列をシステムのどの部分に提供すべきかを判断するには、コンテキストバインディングを使用して単一のモジュールを使用する必要があることをお勧めします。だからあなたの1つのモジュールは次のようになります。IQuoteServiceを解決するとき

Bind<IUnitOfWork>() 
    .To<UnitOfWork>() 
    .WhenInjectedInto<IIPOPService>() 
    .InRequestScope() 
    .WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["IPOP_BE_TESTEntities"].ConnectionString); 
Bind<IUnitOfWork>() 
    .To<UnitOfWork>() 
    .WhenInjectedInto<IQuoteService>() 
    .InRequestScope() 
    .WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["IPOP_BAPSEntities"].ConnectionString); 

Bind<IRepository<tOrder>>().To<Repository<tOrder>>().InRequestScope(); 

あなたはNinjectがIIPOPServiceを解決されたとき、それは"IPOP_BE_TESTEntities"接続文字列で初期化UnitOfWorkのインスタンスを作成することを確認することができます。この道を、そして、それが使用されます"IPOP_BAPSEntities"接続文字列ですが、そうでない場合はその要求スコープでは、単一のインスタンスだけがNinjectによって構築されます。

これが役に立ちます。

+0

あなたの提案@ s3raph86に感謝します。残念ながら、IIPOPServiceとIQuoteServiceに似た40の奇妙なサービスがあります。できるだけ最小限のコード変更で対応できるなら、より洗練されたソリューションがあれば疑問でした。 – Saleh

+0

これはデッドブレッカーではないはずです@Saleh - Ninjectはコンテキストバインディングのための多くのオプションを提供します。 1つの接続文字列を適用するかどうかを決定する際に使用する必要があるルールについて教えてください。おそらく、あなたのサービスを装飾する属性を定義し、それをあなたのバインディングで使うことができますか? – s3raph86

+0

現時点では、アプリケーションは3つ以上のconnをサポートしています(上記の質問は2の例を示しています)。私はそれが可能かどうかわからない最小限のコード変更で複数のリポジトリとサービスに対して 'IPOP_BAPS'と言うコネクトを持つUnitOfWorkを指定したいと同時に、別のconnを持つ別のUnitOfWorkを別のセットに指定するレポジトリとサービス。また、リポジトリはサービスにインジェクトされるため、サービス内のUnitOfworkとそれが挿入されるリポジトリは同じである必要があります。サービスは再利用する必要はなく、再利用したいリポジトリです。 – Saleh

関連する問題