I should point out I'm new to .NET...
I have the following appsettings.json file:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ConnectionStrings": {
"MyContext": "Host=localhost;Database=test;Username=user;Password=''"
}
}
In the MyContext.cs file I want to read the connection string from the appsettings.json config:
using Microsoft.EntityFrameworkCore;
using System;
using System.Configuration;
namespace My.Models
{
public partial class MyContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
Console.WriteLine(ConfigurationManager.ConnectionStrings.Count);
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseNpgsql(ConfigurationManager.ConnectionStrings["MyContext"].ConnectionString);
}
}
}
But ConfigurationManager.ConnectionStrings["MyContext"].ConnectionString
is null, any ideas why?
I'm using the config file successfully in Startup.cs via Configuration.GetConnectionString("MyContext")
, but here I want to read the connection string from this config for situations outside of the ASP.NET application (i.e. in EF migrations I want to do using var db = new MyContext();
), but have no idea why the above is returning null.
Is ConfigurationManager not reading from my appsettings.json file? Not sure how to tell, as ConfigurationManager.ConnectionStrings.Count
returns 1, so I'm pretty confused. Is there anything obviously wrong someone can see?
I'm using .NET Core 5 and EF Core version 5
CodePudding user response:
the common way to define connection string in ef core is
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseNpgsql(@"Host=localhost;Database=test;Username=user;Password=password");
}
there is another way , but much more complicated.
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
IConfigurationRoot configuration = new ConfigurationBuilder()
.SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
.AddJsonFile("appsettings.json")
.Build();
optionsBuilder.UseNpgsql(configuration.GetConnectionString("DefaultConnection"));
}
you will have to copy appsetings.json if you Ef core is in a special project.
CodePudding user response:
I'm assuming that you're running either an API or a Blazor/Razor application since you mentioned a Startup.cs
file :)
The recommendation (official docs about this), in this case, is to use Entity Framework's own libraries to setup your MyContext
within Startup.ConfigureServices
. There you'll have access to both the ConnectionStrings
within your application's IConfiguration
and to extension methods that allow you to register a DbContext
with a specific connection string.
It'll probably look something like this, just adapt from my call to Sqlite
into whatever Database driver you're using:
public class Startup
{
Startup(IConfiguration configuration)
{
_configuration = configuration;
}
void ConfigureServices(IServiceCollection services)
{
// Other dependencies go here
string connString = _configuration.GetConnectionString("MyContext");
services.AddDbContext<MyContext>(opt => opt.UseSqlite(connString));
// Other dependencies, et cetera
}
}
This allows you to keep the Configuration logic from "leaking" into your "Model" namespace, thus your MyContext
concern is just related to persistence of data and not accessing system files and environment variables.
In order to use an Instance of MyContext
on a Controller or anything else created by .NET's dependency injection system all you need to do is ask for it within a class' constructor, like:
public class MyAwesomeController : ControllerBase
{
private readonly MyContext _context;
// This tells .NET to inject an instance of MyContext into your controller
public MyAwesomeController(MyContext context)
{
_context = context ?? throw new ArgumentNullException();
}
// Now all you gotta do is actually use that instance - no matter where it's connecting to
[HttpGet]
public Task ListEverything() => _context.MySet.ToListAsync();
}