admin管理员组

文章数量:1312678

Due to some restrictions on development when using .NET 8, I need to manage some reusable service. Those need to be either transient or singleton, but 1 of 3 service is depend on the rest.

public static IServiceCollection SetupLoggerFactory(this IServiceCollection services)
{
    services.AddSingleton<ILoggerFactory>(new LoggerFactory());
    return services;
}

public static IServiceCollection SetupKafkaProducerForFoo(this IServiceCollection services, IConfiguration config)
{
    services.AddSingleton<IProducerService>(new ProducerService());
    return services;
}

The last service

public static IServiceCollection GetAppLogger(this IServiceCollection services, IServiceProvider serviceProvider)
{
    services.AddSingleton<IAppLogger<Badboy.Models.LoggingEvent>>
            (new LoggerAdapter<Badboy.Models.LoggingEvent>(
                serviceProvider.GetService<ILoggerFactory>(), serviceProvider.GetService<IProducerService>()));
    return services;
}

I need to pass the Service provider argument, but I don't know how.

The startup.cs file:

var builder = WebApplication.CreateBuilder(args);

builder.Services.SetupLoggerFactory();
builder.Services.SetupKafkaProducerForFoo(builder.Configuration);
builder.Services.GetAppLogger(missingArg);

Somehow I cannot get the getRequiredService method, but when I do

var serviceProvider = app.Services;

builder.Services.GetAppLogger(serviceProvider);

it throws an error:

Unhandled exception. System.InvalidOperationException: The service collection cannot be modified because it is read-only.

at Microsoft.Extensions.DependencyInjection.ServiceCollection.ThrowReadOnlyException()
at Microsoft.Extensions.DependencyInjection.ServiceCollection.System.Collections.Generic.ICollection<Microsoft.Extensions.DependencyInjection.ServiceDescriptor>.Add(ServiceDescriptor item)
at Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(IServiceCollection services, Type serviceType, Object implementationInstance)

Due to some restrictions on development when using .NET 8, I need to manage some reusable service. Those need to be either transient or singleton, but 1 of 3 service is depend on the rest.

public static IServiceCollection SetupLoggerFactory(this IServiceCollection services)
{
    services.AddSingleton<ILoggerFactory>(new LoggerFactory());
    return services;
}

public static IServiceCollection SetupKafkaProducerForFoo(this IServiceCollection services, IConfiguration config)
{
    services.AddSingleton<IProducerService>(new ProducerService());
    return services;
}

The last service

public static IServiceCollection GetAppLogger(this IServiceCollection services, IServiceProvider serviceProvider)
{
    services.AddSingleton<IAppLogger<Badboy.Models.LoggingEvent>>
            (new LoggerAdapter<Badboy.Models.LoggingEvent>(
                serviceProvider.GetService<ILoggerFactory>(), serviceProvider.GetService<IProducerService>()));
    return services;
}

I need to pass the Service provider argument, but I don't know how.

The startup.cs file:

var builder = WebApplication.CreateBuilder(args);

builder.Services.SetupLoggerFactory();
builder.Services.SetupKafkaProducerForFoo(builder.Configuration);
builder.Services.GetAppLogger(missingArg);

Somehow I cannot get the getRequiredService method, but when I do

var serviceProvider = app.Services;

builder.Services.GetAppLogger(serviceProvider);

it throws an error:

Unhandled exception. System.InvalidOperationException: The service collection cannot be modified because it is read-only.

at Microsoft.Extensions.DependencyInjection.ServiceCollection.ThrowReadOnlyException()
at Microsoft.Extensions.DependencyInjection.ServiceCollection.System.Collections.Generic.ICollection<Microsoft.Extensions.DependencyInjection.ServiceDescriptor>.Add(ServiceDescriptor item)
at Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(IServiceCollection services, Type serviceType, Object implementationInstance)

Share Improve this question edited Feb 1 at 7:26 marc_s 756k184 gold badges1.4k silver badges1.5k bronze badges asked Feb 1 at 6:41 Adi PrasetyoAdi Prasetyo 1,0421 gold badge16 silver badges43 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 1

You can use AddSingleton accepting lambda:

services.AddSingleton<IAppLogger<Badboy.Models.LoggingEvent>>
(sp => new LoggerAdapter<Badboy.Models.LoggingEvent>(
    sp.GetService<ILoggerFactory>(), sp.GetService<IProducerService>()))

So you will not need to pass the service provider to the GetAppLogger (arguably it should be AddAppLogger) and you can call it before invoking the builder.Build which makes the service collection immutable (hence the exception).

Note that based on the provided code just doing:

services.AddSingleton<IAppLogger<Badboy.Models.LoggingEvent>,
    LoggerAdapter<Badboy.Models.LoggingEvent>>();

Should also do the trick.

Or using open generic registration:

services.AddSingleton(typeof(IAppLogger<>), typeof(LoggerAdapter<>));

本文标签: