C# – How to get the connection string from the SqlServerDBContextOptionsExtensions in ASP.Net Core

asp.net-coreasp.net-core-middlewareasp.net-core-mvccentity-framework-core

I am building up an ASP.Net Core API and I have not been able to find a way to get the connection string from the DBContextOptions.

I have the DBContext in my startup.cs as shown below;

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddApplicationInsightsTelemetry(Configuration);

    services.AddEntityFrameworkSqlServer()
        .AddDbContext<MainContext>(options => options.UseSqlServer(Configuration.GetConnectionString("MainConnection")));

    services.AddMvc()
       .AddJsonOptions(opt =>
        {
            opt.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
        });
}

And in my Context class, I have the following constructor;

public MainContext(DbContextOptions<MainContext> options) : base(options)
{

}

but it doesn't work unless I add an actual connection string in the DBContext class, OnConfiguring method, as shown below;

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    //TODO Move connection string to a secure location
    optionsBuilder.UseSqlServer(@"Server= .....");

}

I can see that the Startup.cs is getting the correct connection string from the appsettings.json file when I debug and examine the value in Configuration.GetConnectionString("MainConnection").

I would think that passing the options into the DbContext class via DI would have passed the connection string but the DbContect class doesn't work unless I have that optionBuilder.UseSqlServer() in the OnConfiguring method.

I found this SO post https://stackoverflow.com/questions/33532599/asp-net-5-multiple-dbcontext-problems, that talks about using the following code to extract the connection string from the options property

public ResourceDbContext(DbContextOptions options) : base(options)
{
    _connectionString = ((SqlServerOptionsExtension)options.Extensions.First()).ConnectionString;
}


protected override void OnConfiguring(DbContextOptionsBuilder options)
{
    options.UseSqlServer(_connectionString);
}  

But when I try to use it, I find that there is no longer a First() method in options.Extensions

So, my first question is…

Why doesn't the DBContext class work without having to add the connection string in the OnConfiguring method

My second question is …

If the connection string is required in the OnCOnfiguring method, how can I get it from the DbContextOptions options object rather than having to explicitly provide it in the OnConfiguring method –> optionsBuilder.UseSqlServer(@"Server= …..");

Best Answer

At least for EF Core 1.1, you need to use FindExtension<SqlServerOptionsExtension>()

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure.Internal;

namespace MyNamespace
{
    public class MyContext : DbContext
    {
        public MyContext(DbContextOptions<MyContext> options) : base(options)
        {
            var sqlServerOptionsExtension = 
                   options.FindExtension<SqlServerOptionsExtension>();
            if(sqlServerOptionsExtension != null)
            {
                string connectionString = sqlServerOptionsExtension.ConnectionString;
            }
        }
    }
}

The null check is there in case you're using opt.UseInMemoryDatabase() in your Startup.cs