2016-08-22 12 views
8

特定のクラスのオブジェクトの異なる実装をどのように注入できますか?私ができる団結で例えば名前による依存性注入の解決

: はIRepository

container.RegisterType<IRepository, TestSuiteRepositor("TestSuiteRepository"); 
container.RegisterType<IRepository, BaseRepository>(); 

の2つの実装を定義し、

public BaselineManager([Dependency("TestSuiteRepository")]IRepository repository) 
+0

ユニットテストでIoCを使用する必要はありません。統合テストの場合は、radu-mateiのように複数のスタートアップクラスを使用する必要があります – Tseng

+0

ビジネスの一部である単体テストではありませんlogic =)TestSuiteはビジネスエンティティ –

+0

解決策を探している人は、[this nuget package](https: /www.nuget.org/packages/Neleus.DependencyInjection.Extensions) – neleus

答えて

11

@Tsengとして指摘されているように、名前付きバインドの組み込みソリューションはありません。しかし、ファクトリメソッドを使用すると、あなたの場合に役立つことがあります。で

public class BaselineManager 
{ 
    private readonly IRepository _repository; 

    public BaselineManager(IRepositoryResolver repositoryResolver) 
    { 
     _repository = repositoryResolver.GetRepositoryByName("TestSuiteRepository"); 
    } 
} 
+0

私は言ったことがありますが、 'GetRepositoryByName()'メソッドでは、私はこのエラーを受け取りました: '非汎用メソッド 'IServiceProvider.GetService(Type)'型引数で使用することはできません! – pejman

+0

Microsoft.Extensions.DependencyInjectionまたは_serviceProvider.GetService(typeof(TestSuiteRepository))が必要です – MorgoZ

+0

DbContextFactoryオブジェクトが必要なので、このソリューションは私のために機能しました。 – Richard

1

実装に必要呼び出すことはできませんと、組み込みのASP.NETコアIoCコンテナ。

これは、のです。ビルトインコンテナは意図的にシンプルで簡単に拡張できるので、他の機能が必要な場合はサードパーティのコンテナをプラグインすることができます。

Autofac(docs参照)のように、これを行うにはサードパーティのコンテナを使用する必要があります。

public BaselineManager([WithKey("TestSuiteRepository")]IRepository repository) 
1

the official documentation for dependency injectionを読んだ後は、このようにすることはできません。

しかし、私が持っている質問は、次の2つの実装が同時に必要なのでしょうか?もしあなたがしなければ、あなたはcreate multiple environments through environment variablesspecific functionality in the Startup class based on the current environment.を持つことができますか、複数のStartup{EnvironmentName}を作成することもできます。

When an ASP.NET Core application starts, the Startup class is used to bootstrap the application, load its configuration settings, etc. (learn more about ASP.NET startup). However, if a class exists named Startup{EnvironmentName} (for example StartupDevelopment), and the ASPNETCORE_ENVIRONMENT environment variable matches that name, then that Startup class is used instead. Thus, you could configure Startup for development, but have a separate StartupProduction that would be used when the app is run in production. Or vice versa.

私はまたwrote an article about injecting dependencies from a JSON fileますので、アプリケーション全体にあなたが実装間で切り替えたいたびに再コンパイルする必要はありません。基本的に、あなたはこのようなサービスでJSON配列を保つ:

"services": [ 
    { 
     "serviceType": "ITest", 
     "implementationType": "Test", 
     "lifetime": "Transient" 
    } 
] 

はその後あなたがこのファイルに必要な実装を変更し、再コンパイルするか、環境変数を変更することはできません。

希望すると便利です。

+0

そして、私たちが** 2つの実装を同時に必要とする場合はどうすればよいでしょうか? – VMAtm

+0

インターフェイスの複数の実装を積み重ねることは、なぜこれをやめたのかを理解しようとしている私の頭を傷つけるような一般的な使用例のようです。しかしそれはMicrosoftのものです。 –

6

を最後にConfigureServices.cs

services.AddSingleton<IRepositoryResolver, RepositoryResolver>(); 
services.AddTransient<TestSuiteRepository>(); 
services.AddTransient<BaseRepository>(); 

任意のクラスでそれを使用して

public interface IRepositoryResolver 
{ 
    IRepository GetRepositoryByName(string name); 
} 

public class RepositoryResolver : IRepositoryResolver 
{ 
    private readonly IServiceProvider _serviceProvider; 
    public RepositoryResolver(IServiceProvider serviceProvider) 
    { 
     _serviceProvider = serviceProvider; 
    } 
    public IRepository GetRepositoryByName(string name) 
    { 
     if(name == "TestSuiteRepository") 
      return _serviceProvider.GetService<TestSuiteRepositor>(); 
     //... other condition 
     else 
      return _serviceProvider.GetService<BaseRepositor>(); 
    } 

} 

登録に必要なサービス:

リポジトリリゾルバを作成します。例は以下のようなものでなければなりません@ adem-caglinの回答に追加私はここにいくつかの再利用可能なタラを掲載したい私は名前ベースの登録のために作成しました。

更新日これはnuget packageとして入手可能です。あなたはStartupクラスに次のコードを追加する必要がありますあなたのサービスを登録するために

 services.AddTransient<ServiceA>(); 
     services.AddTransient<ServiceB>(); 
     services.AddTransient<ServiceC>(); 
     services.AddByName<IService>() 
      .Add<ServiceA>("key1") 
      .Add<ServiceB>("key2") 
      .Add<ServiceC>("key3") 
      .Build(); 

次にあなたがIServiceByNameFactoryインタフェースを介して、それを使用することができます。

public AccountController(IServiceByNameFactory<IService> factory) { 
    _service = factory.GetByName("key2"); 
} 

全拡張子のコードはgithubです。