2017-12-06 5 views
2

スコープ付きの有効期間で解決したいサービスがあるとします。しかし、いつか私はそれをインターフェースタイプとして、そして時には実装タイプとして解決しようとします。ASP.NETコアDI:スコープ付きサービスがサービスタイプと実装タイプの両方として登録されている場合、同じインスタンスを解決する

私がしようとした最初の事はだったこの:

ServiceCollection services; 
services.AddScoped<MyClass>(); 
services.AddScoped<IMyInterface, MyClass>(); 

上記のサンプルでの問題、私はIMyInterfaceという解決し、よりMyClassのを解決する場合は、別のインスタンスが使用されていることです。基本的に、2つの有効範囲のインスタンスが同時に存在する可能性があります。

この問題を回避するには、次の方法があります。しかし、これは非常に誤りがちです。なぜなら、これを1か所で簡単に忘れることができるからです。気づくのは本当に難しいです。

serviceCollection.AddScoped<MyClass>(); 
serviceCollection.AddScoped<IMyInterface, MyClass>(sp => sp.GetRequiredService<MyClass>()); 

エラーが発生しにくい方法で目的を達成する方法はありますか?好ましくは、必ずしもそうではないが、単一登録で好ましいか?

I.e. xUnitのテストとして:

public class Tests 
{ 
    [Fact] 
    public void ReturnsSameInstanceForImplementationAndServiceType() 
    { 
     var serviceCollection = new ServiceCollection(); 

     // TODO: Change these lines so they're less error prone. 
     serviceCollection.AddScoped<MyClass>(); 
     serviceCollection.AddScoped<IMyInterface, MyClass>(sp => sp.GetRequiredService<MyClass>()); 

     var services = serviceCollection.BuildServiceProvider(); 
     var myInt = services.GetRequiredService<IMyInterface>(); 
     var myCls = services.GetRequiredService<MyClass>(); 

     Assert.Equal(myCls, myInt); 
    } 

    class MyClass : IMyInterface { } 
    interface IMyInterface { } 
} 
+3

なぜ実装を登録するのですか? –

+0

@CamiloTerevinto私はそれがベストプラクティスではないことに同意しますが。私は実装が多くの場所で注入されている、古いコードベースの種類のもので動作します。現時点ではこれをインタフェースに変更することはできません。 –

答えて

5

1つのオプションは、あなたの質問に示してきた2つの行を包み込む独自の拡張メソッドを作成することです。たとえば:

public static class ServiceCollectionExtensions 
{ 
    public static void AddScopedInterfaceAndClass<TInterface, TClass>(this IServiceCollection serviceCollection) 
     where TInterface : class 
     where TClass : class, TInterface 
    { 
     serviceCollection.AddScoped<TClass>(); 
     serviceCollection.AddScoped<TInterface, TClass>(sp => sp.GetRequiredService<TClass>()); 
    } 
} 

あなたはそうのように、これを呼び出すことができます。

serviceCollection.AddScopedInterfaceAndClass<IMyInterface, MyClass>(); 

を私はAddScopedInterfaceAndClassは完璧な名前ではないことを理解する - それはアイデアを実証するだけの例です。また、AddScopedではなく、を覚えておいてというこの拡張子を使用しなければならないという欠点はまだあります。

注:2番目のジェネリック(TClass)を削除することで、拡張メソッドの2番目のAddScopedを簡略化できます。これは、コンパイラによって推論されます。

+0

ええ、これよりも良い方法はないようです。レガシーコードのこのビットを支払う代償だと思います。それを書き換える動機を与えます。 ;) –

関連する問題