Is it possible to get ConnectionString from static class in another class library?

Viewed 1372

I've added my connection strings in the appsettings.json file. I need to access the required connection string for background operations but in order to use the connection string I have to access through a static class from different project in same solution. I couldn't access using ConfigurationManager.ConnectionStrings[""].ConnectionString. Kindly advise us, pretty stuck into this. If any documentation kindly send link too.

public static class SystemConstants
{
        public static string ConnectionString = ConfigurationManager.ConnectionStrings[0].ConnectionString;
}
3 Answers

In fact, you can handle any service that has already been injected in .NET Core from provider as follows. But you can't do it for the static class of course.

public FooController(IServiceProvider serviceProvider){
    var fooService = serviceProvider.GetService<IFooService>();
}

Here is a small helper for only services. I'm assuming that services are built from another static class, so we reach any service we need.

We writing an extension to Load() all services.

using Microsoft.Extensions.DependencyInjection;
using Company.Core.Utilities.IoC.DotNetCore;

namespace Company.Core.Extensions {
    public static class ServiceCoreCollectionExtensions {
        
        //You should split seperate files CoreModule and ICoreModule
        public interface ICoreModule {
            void Load(IServiceCollection services);
        }
        
        public class CoreModule : ICoreModule {        

            public void Load(IServiceCollection services) {                 
                //Although you can add each specific service in ConfgiureService()
                //you should move your Core services here, eg.
                //services.AddSingleton<IAuthService, AuthService>();                               
            }
        }       

        public static IServiceCollection AddCoreDI(this IServiceCollection services, ICoreModule[] coreModules) {
            foreach (var coreModule in coreModules) {
                coreModule.Load(services);
            }
            return CoreServiceTool.Load(services);
        }
    }
}

Then we writing a static class to prepare the services.

using Microsoft.Extensions.DependencyInjection;
using System;

namespace Company.Core.Utilities.IoC.DotNetCore {

    public static class CoreServiceTool {
        
        public static IServiceProvider ServiceProvider { get; private set; }

        public static IServiceCollection Load(IServiceCollection services) {                    
            ServiceProvider = services.BuildServiceProvider();

            if(ServiceProvider == null) {
                //I prefer to throw an exception if the developer has not implemented CoreDI()
                throw new ArgumentNullException("You must call AddCoreDI() in the services");
            }
            return services;
        }
    }
}

Finally we are adding the have written helper to the services in .NET Core ConfigureService()

public void ConfigureServices(IServiceCollection services) {

    services.AddCoreDI(new ICoreModule[]{
        new CoreModule()
    });    
}

After all, you can call any service from any layer wherever you want, eg.

static class Foo{

    static Foo(){
        var configuration=CoreServiceTool.ServiceProvider.GetService<IConfigurationBuilder>();
    }
}

It's best to utilize .NET Core dependency injection and let it run magic, this approach is more testable and it doesn't need extra logic and packages inside the class library.

Let's say your appsettings.json file looks like this -

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "ConnectionStrings": {
    "Default": "<CONNECTION_STRING_HERE>"
  }
}

Create a non-static class to hold those app-configurations -

public class AppConfiguration
{
    public string ConnectionString { get; }
    public AppConfiguration(string connectionString)
    {
        ConnectionString = connectionString;
    }
}

Post doing that in the Startup.cs file ConfigureServices method register the instance as a singleton like this -

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton((provider) => 
    {
        AppConfiguration c = new AppConfiguration(Configuration.GetConnectionString("Default"));
        return c;
    });
}

Now lastly you can inject it in the constructor and .NET core IOC container will inject the instance for you.

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    private static readonly string[] Summaries = new[]
    {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

    private readonly ILogger<WeatherForecastController> _logger;
    private readonly AppConfiguration _appConfiguration;

    public WeatherForecastController(ILogger<WeatherForecastController> logger, AppConfiguration appConfiguration)
    {
        _logger = logger;
        _appConfiguration = appConfiguration;
    }
}

You can create a database context class in any project inside your solution and what you need is to inject it in the Startup.ConfigureServices like this

        services.AddDbContext<MyDbContext>(options =>
            options.UseSqlite(
                Configuration.GetConnectionString("connectionString")));

it will read the connectionString from appsettings.json

Related