Das Aufrufen von 'BuildServiceProvider' aus dem Anwendungscode führt zu einer Kopie der Singleton-Warnung. Wie vermeide ich das?


8

Ich habe gerade die 4 Zeilen am Ende eines anderen Projekts eingefügt und es funktioniert, aber ich bekomme eine Warnung. Ich verstehe DI eindeutig nicht gut genug. Was soll ich ändern?

  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
Erstens, warum bauen Sie Anbieter? Dies könnte ein XY-Problem sein . Können Sie die Frage neu formatieren, damit wir ein klareres Bild des aktuellen Problems erhalten und was Sie tatsächlich versuchen zu tun?
— Nkosi

Ich bin mir nicht sicher. Ich glaube, ich habe bereits einen und vielleicht schafft das einen anderen?
— Punkouter

Was meinst du damit WARNING IS HERE? Bitte geben Sie Details zur Warnung an. Zeigen Sie uns den Text der Warnung. Ist das eine Compiler-Warnung? Eine Warnung von einem Code-Analyse-Plugin? Wenn ja, welches? Ist das eine Laufzeitausnahme? Zeigen Sie uns alle relevanten Details der Ausnahme (Nachricht, Typ, Stapelverfolgung, innere Ausnahmen).
— Steven

@punkouter "Was soll ich ändern?": Erstellen Sie den Dienstanbieter nicht manuell durch Aufrufen BuildServiceProvider(). Diese Methode sollte vom Host nur einmal aufgerufen werden. Ein doppelter Dienstanbieter kann zu unerwarteten Fehlern führen.
— Itminus

Die Warnung ist der Titel. Ich denke, IServiceCollection ist, wo ich diesen Logger irgendwie platzieren sollte? Ich muss IServiceCollection besser verstehen als einen ServiceProvider.
— Punkouter

Antworten:


3

Wenn in ConfigureServices BuildServiceProvider () aufgerufen wird, wird die Warnung "Wenn Sie 'BuildServiceProvider' aus dem Anwendungscode aufrufen, wird eine zusätzliche Kopie der Singleton-Dienste erstellt."

Ich habe dieses Problem gelöst:

Erstellen Sie eine weitere Funktion (deren übergebenes Argument IServiceCollection ist) und rufen Sie den Funktionsaufruf BuildServiceProvider () auf.

Geben Sie hier die Bildbeschreibung ein

Zum Beispiel sollte Ihr Code sein:

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;
}

Oder verwenden Sie ApplicationServices von IApplicationBuilder. Der Typ von ApplicationSerivces ist IServiceProvider.

AKTUALISIERT :

Ich erwähnte, dass diese Lösung eine Warnung zum Entfernen ist .

Ich denke, die richtige Version besteht darin, die ApplicationServices-Eigenschaft der App zu verwenden. Diese App ist IApplicationBuilder im Parameter der Configure-Methode. Der Typ von ApplicationServices ist IServiceProvider.

Geben Sie hier die Bildbeschreibung ein


Ich werde es in meiner Freizeit versuchen
— Nijat Aliyev

1
Schöne Lösung! Ich war besorgt über diese Warnung (Y)
— Samra

7
Das Aufrufen dieser Methode von einer anderen Funktion aus ist nicht die richtige Lösung. Sie sollten vermeiden, es von ÜBERALL in Ihrem Code aufzurufen. Dies entfernt nur die Warnung.
— Adys

@Adys Ich stimme dir zu, mein Freund, ich erwähnte, dass diese Lösung eine Warnung zum Entfernen ist :) Ich denke, die richtige Version besteht darin, den ServiceProvider der App aufzurufen. Diese App ist IApplicationBuilder in der Konfigurationsmethode
— Ramil Aliyev

-1

Der EINZIGE Zweck des Aufrufs von 'BuildServiceProvider' besteht darin, eine Dienstanbieterinstanz abzurufen.

Ändern Sie die Configure- Methode, um diesen Aufruf zu entfernen und IServiceProvider weiterhin verwenden zu können , um ihn als Parameter abzurufen :

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

Sie müssen IServiceProvider nicht einfügen, da app.ApplicationServices IServiceProvider ist. - Ramil Aliyev 24. Februar um 11:48 Uhr
— Ramil Aliyev
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.