7

In my solution, I have a ASP.NET Core web project and a .NET Standard class library project. Class library project is the data access layer and I want to read the connection string from my appsettings.json (ASP.NET Core project) in my data access layer.

I have found few answers such as by Andrii Litvinov which looks like quite straight forward to implement but he also mentioned about implementing through Dependency Injection. I don't want to choose the easy shortcut way but looking for the dependency injection implementation?

I am not sure if having appsettings.json in my class library and then registering it through IConfigurationRoot is the better option (as explained here by JRB) but in my scenario, the connection string is in the appsettings.json file of the web project and I wan't constructor dependency injection implementation in my class library project to consume the connection string.

7
  • 1
    Would anyone mind telling me the reason for the down vote? Commented Jul 12, 2018 at 11:55
  • Possible duplicate of How to read connection string in .NET Core? Commented Jul 12, 2018 at 11:57
  • 1
    @Christian i can see in that question where it is mentioned about reading it in a class library project? Commented Jul 12, 2018 at 11:59
  • 1
    As per my understanding, it refers to the scenario of creating a appsettings.json file in class library project and than registering it to the IConfigurationRoot. In my case my I don't have any appsettings file in my class library project and I also don't need to register the one that IConfiguration already able to access in my web project. Please correct me if I am wrong? Commented Jul 12, 2018 at 12:06
  • 1
    @Nkosi on coupling issue: I don't know which approach is more authentic, having an appsetting in class library and then registering it with the IConfigurationRoot or just reading it from the web project through IConfiguration constructor dependency injection, as answered by Alex. XY Problem issue: yes I can say it is gone into XY problem side with the answer of Christian while I believe my question was clear enough where I asked how I can read asp.net Core appsettings file for the connection string in my class library project. Commented Jul 12, 2018 at 12:15

4 Answers 4

9

You can inject an instance of a class that implements IConfiguration See Here
Let's assume in your .net core app, you have a configuration file that looks something like this:

{
  "App": {
    "Connection": {
      "Value": "connectionstring"
    }
  }
}

In your data access layer (class library) you can take a dependency on IConfiguration

public class DataAccess : IDataAccess
{
    private IConfiguration _config;

    public DataAccess(IConfiguration config)
    {
        _config = config;
    }

    public void Method()
    {
        var connectionString = _config.GetValue<string>("App:Connection:Value"); //notice the structure of this string
        //do whatever with connection string
    }
}

Now, in your ASP.net Core web project, you need to 'wire up' your dependency. In Startup.cs, I'm using this (from the default boilerplate template)

public class Startup
{
    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.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
        services.AddSingleton<IConfiguration>(Configuration); //add Configuration to our services collection
        services.AddTransient<IDataAccess, DataAccess>(); // register our IDataAccess class (from class library)
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseMvc();
    }
}

Now, when your code in your class library gets executed, the ctor gets handed the instance of IConfiguration you have set up in your web app

Note: You can create strongly typed settings class if you'd prefer, see here for more information

Sign up to request clarification or add additional context in comments.

5 Comments

In order to use IConfiguration, do I need Microsoft.Extensions.Configuration package in my data access layer project?
@LearningCurve yes, you will
An update if someone is looking for the same solution. _config.GetValue is not available anymore rather it is _config.GetSection.
@Alex, I think I am using your suggestion wrong, as somehow. After wiring up in Startup.cs, I was expecting the constructor to be "handed the instance of IConfiguration" but this does not seem to be happening, as I get the following error when the constructor thinks it is not getting handed what it needs: "There is no argument given that corresponds to the required formal parameter 'config' of 'ConnectionManager.ConnectionManager(IConfiguration)' " Do I have to manually pass in "config" somehow?
.net 6+ no longer have startup.cs. But Program.cs . How to implement void ConfigureServices() method in Program.cs?
4

I would suggest Options pattern. You can create the class with configuration data, e.g.:

public class ConnectionStringConfig
{
    public string ConnectionString { get; set; }
}

Register it on Startup:

public void ConfigureServices(IServiceCollection services)
{
   ...    
   services.Configure<ConnectionStringConfig>(Configuration);
}

and inject in your data access layer

private readonly ConnectionStringConfig config;

public Repository(IOptions<ConnectionStringConfig> config) 
{
    this.config = config.Value;
}

6 Comments

I already have mentioned about this approach (referred Andrii Litvinov) in my question. To my curiosity, why do you think this approach is better while Andrii by himself suggested the dependency injection?
@LearningCurve it's a dependency injection approach, while Andrii's solution is rather sharing value via static class. DI approach is better in terms of testability of the application
I meant to say dependency injection through constructor.
I would advise against using IOptions<T> in anything but the application's Composition Root and instead let the Repository class depend directly on ConnectionStringConfig, as described here.
@AlexRiabov I am looking at your example and its seems the good route but how to a define which connection string name to use that bit is not clear.
|
0

It's pretty simple...use IOptions at the composition root like so in startup.cs or in a separate class library project:

  services.AddScoped<IDbConnection, OracleConnection>();
        services.AddScoped<IDbConnection, SqlConnection>();
        services.Configure<DatabaseConnections>(configuration.GetSection("DatabaseConnections"));
        services.AddScoped(resolver =>
        {
            var databaseConnections = resolver.GetService<IOptions<DatabaseConnections>>().Value;
            var iDbConnections = resolver.GetServices<IDbConnection>();
            databaseConnections.OracleConnections.ToList().ForEach(ora =>
            {
                ora.dbConnection = iDbConnections.Where(w => w.GetType() == typeof(OracleConnection)).FirstOrDefault();
                ora.dbConnection.ConnectionString = ora.ConnectionString;
                //ora.Guid = Guid.NewGuid();
            });
            databaseConnections.MSSqlConnections.ToList().ForEach(sql =>
            {
                sql.dbConnection = iDbConnections.Where(w => w.GetType() == typeof(SqlConnection)).FirstOrDefault();
                sql.dbConnection.ConnectionString = sql.ConnectionString;
                //sql.Guid = Guid.NewGuid();
            });
            return databaseConnections;
        });

Above uses the Configuration class to map the appsettings.json section that houses your connection strings. Here's an example of the appsettings.json file:

      "DatabaseConnections": {
"OracleConnections": [
  {
    "Alias": "TestConnection1",        
    "ConnectionString": "Data Source=(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP) (HOST = ) (PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = ) ) );User Id=;Password=;"
  },
  {
    "Alias": "TestConnection2",        
    "ConnectionString": "Data Source=(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP) (HOST = ) (PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = ) ) );User Id=;Password=;"
  }
],
"MSSqlConnections": [
  {
    "Alias": "Music",
    "ConnectionString": "Data Source=(LocalDB)\\MSSQLLocalDB;AttachDbFilename=C:\\Users\\MusicLibrary.mdf;Integrated Security=True;Connect Timeout=30"
  }
]
}

IOptions now gives me the ability to set my connection string at runtime in startup.cs close to the composition root.

Here's my class I'm using to map my connection strings:

        public class DatabaseConnections : IDatabaseConnections
        {
            public IEnumerable<Connection> OracleConnections { get; set; }
            public IEnumerable<Connection> MSSqlConnections { get; set; }
        }

Now any service layer has access to multiple db connections and provider per request!

Github project: https://github.com/B-Richie/Dapper_DAL

1 Comment

Does this solution require using Dapper DAL?
0

This was solved for me in my program.cs file just adding this:

    builder.Services.AddDbContext<YourContextClassHere>(options =>
    {
        options.UseSqlServer(builder.Configuration.GetConnectionString("Web_Project_app_settings_connection_string_here"));
    });

1 Comment

Note that in my project, my context class was in a class library that I referenced from the web project. This is for .Net core 6. None of the existing answers put the solution this plainly so that's why I felt it worth adding here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.