アプリケーションコードから「BuildServiceProvider」を呼び出すと、シングルトン警告のコピーが生成されます。どうすればこれを回避できますか?


8

別のプロジェクトの最後に4行を貼り付けたところ、うまくいきましたが、警告が表示されます。DIが十分に理解されていないことは明らかです。

  public void ConfigureServices(IServiceCollection services)
        {
            if (HostingEnvironment.EnvironmentName == "Local")
            {
                services.AddHealthChecksUI()
               .AddHealthChecks()
               .AddCheck<TestWebApiControllerHealthCheck>("HomePageHealthCheck")
               .AddCheck<DatabaseHealthCheck>("DatabaseHealthCheck");
            }

        services.Configure<PwdrsSettings>(Configuration.GetSection("MySettings"));
        services.AddDbContext<PwdrsContext>(o => o.UseSqlServer(Configuration.GetConnectionString("PwdrsConnectionRoot")));

        services.AddMvc(o =>
        {
            o.Filters.Add<CustomExceptionFilter>();
        });

        services.AddCors(options =>
        {
            options.AddPolicy("CorsPolicy", b => b
                .SetIsOriginAllowed((host) => true)
                .AllowAnyMethod()
                .AllowAnyHeader()
                .AllowCredentials());
        });

        services.AddSwaggerDocument();
        services.AddHttpContextAccessor();

        services.AddAutoMapper(typeof(ObjectMapperProfile));
        services.AddTransient<IEmailSender, EmailSender>();
        services.AddScoped(typeof(IAppLogger<>), typeof(LoggerAdapter<>));
        services.AddScoped(typeof(IAsyncRepository<>), typeof(Repository<>));
        services.AddScoped<IRfReportTypeRepository, RfReportTypeRepository>();
        services.AddScoped<IRfReportRepository, RfReportRepository>();
        services.AddScoped<IRfReportLookupsService, RfReportLookupsService>();
        services.AddScoped<IRfReportService, RfReportService>();

        services.Configure<RAFLogging>(Configuration.GetSection("RAFLogging"));
        ServiceProvider serviceProvider = services.BuildServiceProvider(); //WARNING IS HERE
        IOptions<RAFLogging> RAFLogger = serviceProvider.GetRequiredService<IOptions<RAFLogging>>();
        RegisterSerilogLogger logger = new RegisterSerilogLogger(RAFLogger);
    }

2
まず、なぜプロバイダーを構築しているのですか?これはXYの問題である可能性があります。現在の問題と実際に何をしようとしているのかをより明確に把握できるように、質問を再フォーマットできますか?
Nkosi

よく分かりません。私はすでに持っていると思いますが、おそらくそれが別のものを作成していますか?
punkouter

どういう意味WARNING IS HEREですか?警告の詳細を入力してください。警告のテキストを見せてください。これはコンパイラの警告ですか?一部のコード分析プラグインからの警告?もしそうなら、どれですか?これはランタイム例外ですか?例外に関連するすべての詳細(メッセージ、タイプ、スタックトレース、内部例外)を表示します。
スティーブン

@punkouter「何を変更する必要があるか」:を呼び出してサービスプロバイダーを手動で構築しないでくださいBuildServiceProvider()。このメソッドは、ホストによって1回だけ呼び出される必要があります。サービスプロバイダーが重複していると、予期しないバグが発生する可能性があります。
itminus

警告はタイトルです。IServiceCollectionは、このロガーをどこかに配置する必要があると思いますか?IServiceCollectionとServiceProviderをよく理解する必要があります。
punkouter

回答:


3

ConfigureServicesでBuildServiceProvider()を呼び出すと、「アプリケーションコードから「BuildServiceProvider」を呼び出すと、シングルトンサービスの追加コピーが作成される」という警告が表示される

私はこの問題を解決しました:

別の関数(渡された引数はIServiceCollection)を作成し、関数呼び出しBuildServiceProvider()に入れます。

ここに画像の説明を入力してください

たとえば、コードは次のようになります。

public void ConfigureServices(IServiceCollection services)
    {
        if (HostingEnvironment.EnvironmentName == "Local")
        {
            services.AddHealthChecksUI()
           .AddHealthChecks()
           .AddCheck<TestWebApiControllerHealthCheck>("HomePageHealthCheck")
           .AddCheck<DatabaseHealthCheck>("DatabaseHealthCheck");
        }

    services.Configure<PwdrsSettings>(Configuration.GetSection("MySettings"));
    services.AddDbContext<PwdrsContext>(o => o.UseSqlServer(Configuration.GetConnectionString("PwdrsConnectionRoot")));

    services.AddMvc(o =>
    {
        o.Filters.Add<CustomExceptionFilter>();
    });

    services.AddCors(options =>
    {
        options.AddPolicy("CorsPolicy", b => b
            .SetIsOriginAllowed((host) => true)
            .AllowAnyMethod()
            .AllowAnyHeader()
            .AllowCredentials());
    });

    services.AddSwaggerDocument();
    services.AddHttpContextAccessor();

    services.AddAutoMapper(typeof(ObjectMapperProfile));
    services.AddTransient<IEmailSender, EmailSender>();
    services.AddScoped(typeof(IAppLogger<>), typeof(LoggerAdapter<>));
    services.AddScoped(typeof(IAsyncRepository<>), typeof(Repository<>));
    services.AddScoped<IRfReportTypeRepository, RfReportTypeRepository>();
    services.AddScoped<IRfReportRepository, RfReportRepository>();
    services.AddScoped<IRfReportLookupsService, RfReportLookupsService>();
    services.AddScoped<IRfReportService, RfReportService>();

    RegisterSerilogLogger logger = CreateRegisterSerilogLogger(services);
}

private RegisterSerilogLogger CreateRegisterSerilogLogger(IServiceCollection services){
        services.Configure<RAFLogging>(Configuration.GetSection("RAFLogging"));
        ServiceProvider serviceProvider = services.BuildServiceProvider(); //No warning here ))
        IOptions<RAFLogging> RAFLogger = serviceProvider.GetRequiredService<IOptions<RAFLogging>>();
        RegisterSerilogLogger logger = new RegisterSerilogLogger(RAFLogger);
    return logger;
}

または、IApplicationBuilderのApplicationServicesを使用します。ApplicationSerivcesのタイプはIServiceProviderです。

更新しました

私はこの解決策が警告を削除すると述べました

正しいバージョンは、アプリのApplicationServicesプロパティを使用することだと思います。このアプリは、ConfigureメソッドのパラメーターのIApplicationBuilderです。ApplicationServicesのタイプはIServiceProviderです。

ここに画像の説明を入力してください


私は自由な時間にそれを試してみる
Nijat Aliyev

1
素敵な解決策!私はこの警告を心配していました(Y)
Samra

7
別の関数からこのメソッドを呼び出すことは、適切な解決策ではありません。コードのどこからでも呼び出さないでください。これは警告を削除するだけです。
Adys

@Adys私はあなたの友人に同意します。この解決策は警告を削除することだと言いました:)正しいバージョンはアプリのServiceProviderを呼び出すことだと思います。このアプリはConfigureメソッドのIApplicationBuilderです
Ramil Aliyev

-1

ONLY「BuildServiceProvider」呼び出しの目的は、サービスプロバイダのインスタンスを取得することで、

この呼び出しを削除してもIServiceProviderを使用できるようにするには、Configureメソッドを変更してパラメーターとして取得します。

public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider provider)

app.ApplicationServicesはIServiceProviderであるため、IServiceProviderを注入する必要はありません。–ラミルアリエフ2月24日11:48
ラミルアリエフ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.