Search code examples
c#asp.net-coreconfigurationsimple-injector

c# Inject settings in aspnet core external library


I have a project with an entry point that is ASP.NET Core API and an infrastructure project that is a Client for MongoDB. I have a problem, I would inject my interface IDatabaseSettings (that is in a common project) in a project with mongo client, so I create concrete type in my principal project like this:

public class MongoSettings : IDatabaseSettings
{
    private const string Mongo = "Mongo";
    private static IConfiguration _configuration;

    public LogMongoSettings(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    public string ConnectionString { get; } = _configuration.GetValue<string>($"{Mongo}:ConnectionString");
    public string DatabaseName { get; } = _configuration.GetValue<string>($"{Mongo}:Database");
    public string Username { get; } = _configuration.GetValue<string>($"{Mongo}:Username") ?? string.Empty;
    public string Password { get; } = _configuration.GetValue<string>($"{Mongo}:Password") ?? string.Empty;
}

the problem is that _configuration is always null and this code throws an exception. I use SimpleInjector container and my Startup project is like this:

public class Startup
{

    private static readonly Container Container = new Container();
    private static readonly Assembly LogReaderAssembly = Assembly.Load("LogReader.IdP");
    private static readonly Assembly MongoLogReaderAssembly = Assembly.Load("LogReader.Mongo");

    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
        services.AddSimpleInjector(Container, options =>
        {
            options.AddAspNetCore()
                .AddControllerActivation();
            options.AddLogging();
        });
        services.AddSwaggerGen(options =>
        {
            options.SwaggerDoc("LogReader", new OpenApiInfo
            {
                Version = "V1"
            });
        });

       InitializeContainer();
    }


    private static void InitializeContainer()
    {
        Container.RegisterSingleton<IDatabaseClient, DatabaseClient>();
        Container.Register<IFileRepositoryReader, TraceFileRepositoryReader>();
        Container.Register(typeof(IRepositoryReader<>), MongoLogReaderAssembly);
        Container.RegisterSingleton(() => Container.GetInstance<MapperProvider>().GetMapper());
        Container.Register(typeof(IQueryHandler<,>), LogReaderAssembly);
        Container.Register<IDatabaseSettings, MongoSettings>();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        app.UseSimpleInjector(Container);

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        app.UseRouting();
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();

        });
        app.UseSwagger();
        Container.Verify(VerificationOption.VerifyAndDiagnose);
    }
}

Why does this happen? What is the problem? I wouldn't use IOptionMonitor in my Mongo client because I wouldn't that this class depends on concrete TOptions. Is there a better solution to the problem? Thank you.


Solution

  • in the end, I solved the problem with this code:

    public class MongoDatabaseSettings : IDatabaseSettings
    {
        private const string Mongo = "Mongo:";
    
        public MongoDatabaseSettings(IConfiguration configuration)
        {
            Host = configuration.GetValue<string>($"{Mongo}{nameof(Host)}");
            Port = configuration.GetValue<int>($"{Mongo}{nameof(Port)}");
            DatabaseName = configuration.GetValue<string>($"{Mongo}{nameof(DatabaseName)}");
            Username = configuration.GetValue<string>($"{Mongo}{nameof(Username)}");
            Password = configuration.GetValue<string>($"{Mongo}{nameof(Password)}");
        }
    
        public string Host { get; }
        public int Port { get; } 
        public string DatabaseName { get; } 
        public string Username { get; } 
        public string Password { get; } 
    }
    

    I don't understand why in this case the properties are initialized correctly, instead the original question code doesn't work. Do you have any idea why this happens? Thank you