web-dev-qa-db-ja.com

.NET Coreシングルトン作成が複数回呼び出されます

.NET Coreでサービスをシングルトンとして登録しています。それでも、シングルトンのコンストラクタが複数回呼び出されるのを見ています。

services.AddSingleton<DbAuthorizationOptions, ContextAuthorizationOptions>();

私のコンテキスト認証オプションは、エンティティタイプのディクショナリでIValidatorsです。コンテキスト認証オプションは、検証を自動的に実行するためにDBContextに渡されます。

サービスの登録時に、DIに登録されたコンテナーに動的バリデーターも登録します。

var useDynamicValidator = serviceOption.ValidatorOptions != null;
if(useDynamicValidator)
{
    //TODO: Extract this to before the register service no sense in building the provider each time
    //TODO: Make this cleaner don't be dependent on Authorization options
    var provider = services.BuildServiceProvider();
    var authOptions = provider.GetService<DbAuthorizationOptions>();
    var validator = BuildDynamicValidatorFactory(serviceOption).Invoke(provider, null);
    authOptions.ValidatorOptions.AddValidatorForSet(validator);
}

プロバイダーでGetServiceを呼び出すと、既存のシングルトンの代わりに新しいシングルトンを受け取ることに気づきました。プロバイダーを構築すると、新しいコンテナーが作成され、すべてのサービスが再登録されますか?

その場合、シングルトンコンテナー内の動的バリデーターを既存のIServiceProviderに登録するメソッドを呼び出すにはどうすればよいですか。サービスコンテナーの構築後に一度登録を呼び出す方法はありますか?

12
johnny 5

プロバイダーを構築すると、新しいコンテナーが作成され、すべてのサービスが再登録されますか?

はい。 ソースコード を参照してください。

その場合、シングルトンコンテナー内の動的バリデーターを既存のIServiceProviderに登録するメソッドを呼び出すにはどうすればよいですか?

なぜこれが問題なのか、私にはよくわかりません。 Composition Root で、アプリケーションの起動時にすべてのサービスを一度登録する必要があります。

次に、DIコンテナーは、アプリケーションのオブジェクトグラフを解決します。アプリケーション自体に依存関係があってはならず、更新する必要もありません。

使用する必要がある場所にinjectingDbAuthorizationOptionsする必要があります。

public class Foo : IFoo
{
    private readonly DbAuthorizationOptions authOptions;

    public Foo(DbAuthorizationOptions authOptions) // <-- Inject parameters
    {
        this.authOptions = authOptions ??
            throw new ArgumentNullException(nameof(authOptions));
    }

    public void DoSomething()
    {
        // TODO: Inject the type that has the BuildDynamicValidatorFactory
        // method and the serviceOption (whatever type that is) here
        // either as a method parameter of this method, or a constructor
        // parameter of this class.
        var validator = BuildDynamicValidatorFactory(serviceOption).Invoke(provider, null);
        // Now we have an instance of authOptions that can be used
        authOptions.ValidatorOptions.AddValidatorForSet(validator);
    }
}

DIコンテナーが自動的にを提供することに注意してください。DIを通じて解決される別の型(コントローラーやフィルターなど)に注入された場合、DbAuthorizationOptionsが提供されます。

注:これを行う必要がある場所の質問からは明確ではありません。あなたはそれを一度だけ起こさせたいと言っています、それは通常はアプリケーションの起動時にそれを置くことを意味します。ただし、ユーザーは起動時に実行されるコードを操作できません。したがって、おそらく filter を使用できます。実際には、アプリケーションのライフサイクルで発生する必要があるwhereに依存しています。

4
NightOwl888

IServiceProviderへの依存関係を宣言できます-ビルドせず、注入してください。

public class SomeController
{
    DbAuthorizationOptions authOptions;
    public SomeController(IServiceProvider provider)
    {
        authOptions = provider.GetSerivce<DbAuthorizationOptions>();
    }
}

しかし、これは service locator アンチパターンです。詳細を説明した後、NightOwl888の投稿にコメントしましたが、おそらくファクトリの方が良いアプローチです。

1
McGuireV10