0

I am using the code below to retrieve the connection string and it works fine. However, the configuration object has to be passed through the layers. Previous versions of .Net would allow me to get the connection string directly in the data layer. So can I still do that (and how do I do that) or do I need to pass the configuration object through the application as I do now?

In startup.cs

public IConfiguration Configuration { get; }

public void ConfigureServices(IServiceCollection services)
{
   ...
   services.AddSingleton(_ => Configuration);
   ...
}

MyController.cs

public class MyController : Controller
{
  protected readonly IConfiguration Configuration;

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

  public IActionResult ListRecords()
  {
      DatabaseContext ctx = new DatabaseContext(Configuration);
      return View();
  }
}

DatabaseContext.cs

public class DatabaseContext : DbContext
{
   private readonly IConfiguration config;
   public DatabaseContext(IConfiguration config)
   {
      this.config = config;
   }

   protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
   {
      optionsBuilder.UseSqlServer(config["ConnectionStrings:Dev"]);
   }
}
user3807918
  • 315
  • 2
  • 19
  • You would do that in the Startup class. Virtually every example found on the internet does it. – insane_developer Dec 03 '20 at 14:30
  • 1
    You should be injecting your database context, not manually creating one. This way it's all configured from the startup class – phuzi Dec 03 '20 at 14:39

3 Answers3

1

Having to explicitly inject IConfiguration is usually seen as a code smell and indicates design issues.

Take advantage of dependency injection

public class MyController : Controller {
    DatabaseContext context;

    public MyController(DatabaseContext context) {
        this.context = context;
    }

    public IActionResult ListRecords() {
        //...use context here
        return View();
    }
}

and inject the database options instead

public class DatabaseContext : DbContext {    
    public DatabaseContext(DbContextOptions<DatabaseContext> options): base(options) {
        //...
    }
}

Then it is only a matter of configuring the context at startup

public IConfiguration Configuration { get; }

public void ConfigureServices(IServiceCollection services) {
    // ...

    services.AddDbContext<DatabaseContext>(options => 
        options.UseSqlServer(Congiguration.GetConnectionString("Dev"));

    // ...
}
Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • thanks and now what happens in the controller if I call other layers such as a business layer - do I pass the context or can their classes be invoked with it as a parameter via DI – user3807918 Dec 03 '20 at 16:34
  • Actually, this question is asked here: https://stackoverflow.com/questions/40862162/get-db-context-inside-data-access-layer – user3807918 Dec 03 '20 at 16:41
  • If the business layer classes need the context, again use DI and inject the context into the BL via constructor injection and inject the BL class into the controller. – Nkosi Dec 03 '20 at 19:04
  • that makes a lot of sense on injecting the BL into the controller but how do I inject the context into the BL? Do I use AddDbContext but don't have a BL constructor with a DBContext? – user3807918 Dec 03 '20 at 22:48
  • @user3807918 I think you misunderstood what I meant. **Do** use `AddDbContext ` and **do** have a BL class with the context in its constructor. When the framework is injecting the BL class into the controller, it will also create the context and inject it into the BL class. – Nkosi Dec 03 '20 at 23:19
  • Thanks. Now I get it. Problem now understood and resolved. – user3807918 Dec 04 '20 at 01:05
  • @user3807918 Glad to help. If this resolves your issue remember to make this as the answer – Nkosi Dec 23 '20 at 10:55
1

Typically the pattern I've used for setting up DBContext, is to configure at startup.

So if this is startup.cs:

        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)
        {
            var sqlConnString = Configuration.GetConnectionString(dbConnectionStringSettingsName);

            services.AddDbContext<DatabaseContext >(opt => opt.UseSqlServer(sqlConnString));

Also, if you pass your context as a service reference, you shouldn't need to give it IConfiguration.

    private readonly DatabaseContext _context;       

    public MyController(DatabaseContext context)
    {
        _context = context;
    }
    public IActionResult ListRecords()
    {
      var dbresults = _context.Table.ToList();
      return View(dbresults );
    }
WiseGuy
  • 409
  • 1
  • 8
  • 19
0

use nugget packaeges

Install-Package Microsoft.Extensions.Configuration.Abstractions

 Install-Package Microsoft.Extensions.Configuration

and then Inject IConfigurationSection in the web application.

https://github.com/geeksarray/read-appsettings-json-in-net-core-class-library-using-dependency-injection

Laxmikant
  • 588
  • 4
  • 11