Llamar a 'BuildServiceProvider' desde el código de la aplicación da como resultado una copia de la advertencia Singleton. ¿Cómo evito esto?

8

Acabo de pegar las 4 líneas al final de otro proyecto y funciona, pero recibo una advertencia ... Claramente no entiendo DI lo suficientemente bien ... ¿Qué quiere que cambie?

  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);
    }
punkouter
fuente
2
Primero, ¿por qué estás construyendo proveedor? Esto podría ser un problema XY . ¿Puede volver a formatear la pregunta para que tengamos una idea más clara del problema actual y de lo que realmente es? tratando de hacer?
Nkosi
No estoy seguro. ¿Supongo que ya tengo uno y tal vez eso está creando otro?
punkouter
Que quieres decir con WARNING IS HERE ? Proporcione detalles sobre la advertencia. Muéstranos el texto de la advertencia. ¿Es esta una advertencia del compilador? ¿Una advertencia de algún complemento de análisis de código? ¿Si es así, Cuál? ¿Es esta una excepción de tiempo de ejecución? Muéstrenos todos los detalles relevantes de la excepción (mensaje, tipo, seguimiento de pila, excepciones internas).
Steven
@punkouter "¿Qué quiere que cambie?": no cree el proveedor de servicios manualmente invocandoBuildServiceProvider() . Host debe invocar este método solo una vez. El proveedor de servicios duplicados puede provocar algunos errores inesperados.
itminus
La advertencia es el título. Supongo que IServiceCollection es donde debería poner este registrador de alguna manera? Necesito entender mejor IServiceCollection frente a un ServiceProvider.
punkouter

Respuestas:

3

Si se llama BuildServiceProvider () en ConfigureServices, se muestra la advertencia "Al llamar a 'BuildServiceProvider' desde el código de la aplicación, se crea una copia adicional de los servicios Singleton"

Resolví este problema:

Cree otra función (cuyo argumento pasado es IServiceCollection) y en la función llame a BuildServiceProvider ()

ingrese la descripción de la imagen aquí

Por ejemplo, su código debería ser:

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

O use ApplicationServices de IApplicationBuilder. El tipo de ApplicationSerivces es IServiceProvider.

ACTUALIZADO :

Mencioné que esta solución es eliminar advertencia .

Creo que la versión correcta es usar la propiedad ApplicationServices de la aplicación, que es IApplicationBuilder en el parámetro del método Configure. El tipo de ApplicationServices es IServiceProvider.

ingrese la descripción de la imagen aquí

Ramil Aliyev
fuente
Lo intentaré en mi tiempo libre
Nijat Aliyev
1
Buena solución! Estaba preocupado por esta advertencia (S)
Samra
77
Llamar a este método desde otra función no es la solución correcta. Debe evitar llamarlo desde CUALQUIER LUGAR en su código. Esto solo está eliminando la advertencia.
Adys
@Adys Estoy de acuerdo con usted mi amigo, mencioné que esta solución es eliminar la advertencia :) Creo que la versión correcta es llamar a ServiceProvider de la aplicación, cuya aplicación es IApplicationBuilder en el método Configurar
Ramil Aliyev
-1

El único propósito de llamar a 'BuildServiceProvider' es obtener una instancia de proveedor de servicios,

Para eliminar esta llamada y aún poder usar IServiceProvider, cambie el método Configure para obtenerlo como parámetro:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider provider)
Adys
fuente
No necesita inyectar IServiceProvider porque app.ApplicationServices es IServiceProvider. - Ramil Aliyev 24 de febrero a las 11:48
Ramil Aliyev