I would like to pass the connection string to my dbcontext model.
I'm using the Microsoft.EntityFrameworkCore.Sqlite package.
public void ConfigureServices(IServiceCollection services)
{
//Adds Entity FrameWork for SqlLite
var config = Configuration.GetConnectionString("DefaultConnection");
//How to pass the connection string, AddEntityFrameworkSqlite take no extra parameters
//services.AddEntityFrameworkSqlite().AddDbContext<ETLDataBase>(opt => opt.????)
services.AddEntityFrameworkSqlite().AddDbContext<ETLDataBase>();
services.AddMvc();
services.AddScoped<IRepository<User>, AccountRepository>();
}
I didn't find a way to access to the ContentRootPath directly in the my dbcontext. I hardcoded the path of my DB in the appsettings.json, but even like this I can't pass the path to my model.
Here's my context model:
public class ETLDataBase: DbContext
{
public ETLDataBase(DbContextOptions<ETLDataBase> options)
: base(options)
{}
public DbSet<Datasouce> Datasources { get; set; }
public DbSet<User> Users { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// I want to get my connection string in here
//I can't access to the env.ContentRootPath
var connection = new SqliteConnection(connectionString);
optionsBuilder.UseSqlite(connection);
}
}
EDIT
If I do it like this in the Startup.cs:
services.AddEntityFrameworkSqlite().AddDbContext<ETLDataBase>(options=> options.UseSqlite(Configuration["ConnectionStrings:Default‌​Connection"]));
And I remove the OnConfiguring function in the ETLDataBase class.
I have this error:
No database provider has been configured for this DbContext. A provider can be configured by overriding the DbContext.OnConfiguring method or by using AddDbContext on the application service provider. If AddDbContext is used, then also ensure that your DbContext type accepts a DbContextOptions<TContext> object in its constructor and passes it to the base constructor for DbContext.
Related
I have a strange requirement here. We have a ton of databases that are basically idential but with different clients. So each db has the same table structures. With that being said, I can't use the standard way of setting up the connectionstring in the startup. I would like to see if there is a way I can pass the connectionstring in the contructor without it being the DbContextOptions<> object. We use to be able to do that in earlier versions of EF but now it's expecting that option in the base().
The other option is just doing raw ADO with a command object, which I REALLY don't want to do, I would prefer if I could use EF.
So this is what it looks like, but would prefer to have a second constructor that allows the connectionString to be passed in. NO Start Up or NO appsettings.json, just want to pass in a string with the connectionString.
`
public class Context : DbContext
{
public Context(DbContextOptions<Context> options) : base(options) // <== base expects only options
{
Database.SetCommandTimeout(9000);
}
public Context(string connectionString) : base()
{
this.Database.Connection ????? What to do here
}
public DbSet<Transcription> Transcriptions { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.HasDefaultSchema("dbo");
builder.Entity<Transcription>().ToTable("Transcriptions", "dbo");
}
}`
Any idea why this keeps throwing errors or why it won't allow me to set the connectionString instead of using options?
I have looked an keep getting old solutions from 12+ years ago, nothing for EF 6
Possibly more convenient would be to use multitenancy approaches described in the docs but if you still want to use just the ctor you can override the OnConfiguring method and use connection string from the ctor there:
public class Context : DbContext
{
private readonly string _connectionString;
public Context(string connectionString)
{
_connectionString = connectionString;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
// setup options - provider, connection string, etc.
optionsBuilder.UseNpgsql(_connectionString);
}
}
}
Or manually building options from the connection string:
public class Context : DbContext
{
public Context(string connectionString):base(BuildOpts(connectionString))
{
}
private static DbContextOptions<Context> BuildOpts(string connectionString) =>
new DbContextOptionsBuilder<Context>()
.UseNpgsql(connectionString) // setup options - provider, connection string, etc.
.Options;
}
I have this database configuration to at my Startup class in .NET Core 3.1 Web Api project.
public void ConfigureServices(IServiceCollection services)
{
var abcConnString = Configuration.GetConnectionString("abcConnString");
services.RegisterAbcSqlServer<ABCContext>(abcConnString);
var xyzConnString = Configuration.GetConnectionString("xyzConnString");
services.RegisterXyzSqlServer<XYZContext>(xyzConnString);
// code removed for brevity.
}
and
public static class RegisterDbContext
{
public static void RegisterAbcSqlServer<T>(this IServiceCollection services, string connectionString)
where T : DbContext, IAbcContext
{
var migrationsAssembly = typeof(RegisterDbContext).GetTypeInfo().Assembly.GetName().Name;
services.AddDbContext<T>(options => options.UseSqlServer(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly)));
}
public static void RegisterXyzSqlServer<T>(this IServiceCollection services, string connectionString)
where T : DbContext, IXyzContext
{
var migrationsAssembly = typeof(RegisterDbContext).GetTypeInfo().Assembly.GetName().Name;
services.AddDbContext<T>(options => options.UseSqlServer(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly)));
}
}
I can build without error. But when I perform EF Core add-migration, it hits error:
No database provider has been configured for this DbContext. A
provider can be configured by overriding the DbContext.OnConfiguring
method or by using AddDbContext on the application service provider.
If AddDbContext is used, then also ensure that your DbContext type
accepts a DbContextOptions object in its constructor and
passes it to the base constructor for DbContext.
You can get this error when there is no way for the DI framework to configure the provider by injecting a DbContextOptions. So you just need to add a constructor that will accept one, or add a parameter for a DbContextOptions to be passed in. For example:
public class XYZContext : DbContext
{
// Add this constructor
public XYZContext (DbContextOptions options) : base(options)
{
}
}
I am trying to get the DbContext I registered with options via services.AddDbContext(...) on the service provider of the project, but when calling configuration.Get<ModelContext> it can not be constructed as the options apparently weren't provided and therefore also no database provider is given.
I am using ASP.NET Core 2.2 with Entity Framework Core 2.2.3 and my DbContext is defined in a separate project.
My DbContext:
public class ModelContext : DbContext
{
public ModelContext(DbContextOptions<ModelContext> options) : base(options) { }
public ModelContext() { }
}
I did not override OnConfiguring(DbContextOptionsBuilder) in ModelContext.
public class StartUp
{
public void ConfigureServices(IServiceCollection services)
{
public services.AddEntityFrameworkSqlServer();
services.AddDbContext<ModelContext>(options => options.UseSqlServer(modelConnectionString));
}
}
In the controller (or anywhere really) I call public HomeController(IConfiguration configuration) => _modelContext = configuration.Get<ModelContext>(); which throws the unexpected exception.
What I specifically get is an InvalidOperationException with the message:
No database provider has been configured for this DbContext. A provider can be configured by overriding the DbContext.OnConfiguring method or by using AddDbContext on the application service provider. If AddDbContext is used, then also ensure that your DbContext type accepts a DbContextOptions object in its constructor and passes it to the base constructor for DbContext.
According to the documentation I read and examples I looked at, the ModelContext should be created with the options I defined when calling AddDbContext<ModelContext>. Is the Get method the wrong one to use?
After configuring the db context service in "ConfigureServices" method of the Startup.cs file with something like this :
var connectionString = Configuration.GetConnectionString("DefaultConnection");
services.AddDbContext<BottinContext>(options => options.UseSqlServer(connectionString)) ;
Simply add a :
ModelContext db
parameter to the constructor of your controller and let DI magic happen.
If you've got many controllers and wish to simplify things, you can use a base contructor that holds the db context
public BaseController(ModelContext context /* as well as other injections */)
{
_db = context;
}
internal ModelContext _db;
you are trying to get dbContxt instance in a wrong way. Get method is not used to get instance of dbContext object that you registered with dependency injection container.
if you want to get instance of your dbContext class that you registered you can inject it through construction injection for example
public class RepositoryWrapper : IRepositoryWrapper
{
private readonly ModelContext _modelContext;
public RepositoryWrapper(ModelContext modelContext)
{
_modelContext= modelContext;
}
}
is something i am doing in my project.
In a .NET Core Console Application I have the following DbContext:
public class AppDataContext : DbContext
{
public DbSet<ExampleObject> ExampleObjects { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseNpgsql(/* Read Connection String from appsettings.json */);
}
}
Of course I could instantiate the ConfigurationBuilder class and access the connectionString, like this:
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json");
Configuration = builder.Build();
var connString = Configuration.GetConnectionString("data"));
but how can I force Entity Framework to use the IConfigurationRoot instance defined with dependency injection?
Thank you
You're approaching it from the wrong angle. You're currently trying to "bring in" configuration. What you need to be doing is "applying" the configuration at the ServiceCollection level so that the Net Core Dependency Injection can instantiate your DbContext with the correct values automatically. Here is an example of how to do that:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<BloggingContext>(options => options.UseSqlite("Data Source=blog.db"));
}
Of course you can still use the IConfigurationBuilder to get your connection string - that would go in the ConfigureServices section above and "Data Source=blog.db" would be swapped for your value
Your DbContext can then be simplified like this:
public class AppDataContext : DbContext
{
public DbSet<ExampleObject> ExampleObjects { get; set; }
}
App: Asp.NET Core 1.1.1, EF Core
Platform: Visual Studio 2017 5.3.3
Authentication Mode: Individual User Accounts
Following this tutorial from ASP.NET official team, the following command runs successfully:
PM> Add-Migration MyFirstMigration -context BloggingContext
As we know VS2017 by default creates ApplicationDbContext under MyProject\Data folder for creating user tables (ASPNETUsers, ASPNETRoles etc...) for authentication. But for that when I run the following command it first gives me Error-1 below. And when I follow the instructions in first error message, I get Error-2 below. Question: How do I make the following command work without using IDbContextFactory?
PM> Add-Migration MyFirstAuthenMigration -context ApplicationDbContext
Error 1
No parameterless constructor was found on 'ApplicationDbContext'. Either add a parameterless constructor to 'ApplicationDbContext' or add an implementation of 'IDbContextFactory' in the same assembly as 'ApplicationDbContext'.
After I add a parameterless constructor in ApplicationDbContext.cs (shown below) I get the second error shown below:
Error 2
No database provider has been configured for this DbContext. A provider can be configured by overriding the DbContext.OnConfiguring method or by using AddDbContext on the application service provider. If AddDbContext is used, then also ensure that your DbContext type accepts a DbContextOptions object in its constructor and passes it to the base constructor for DbContext.
ApplicationDbContext.cs
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
//NOTE: I added following constructor after Error 1 shown above
public ApplicationDbContext()
{
}
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Customize the ASP.NET Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);
}
}
You can't get it to work.
Because EF needs to know which connectionstring should be used. You can either put the connectionstring into your OnModelCreating method.
Which is bad when you have more than one DB (dev, test and production for example).
Or you implement IDbContextFactory which will be loaded by EF through reflection.
So implementing IDbContextFactory is the better option. Simply create it where you have your ApplicationDbContext.
Sample implementation.
public class DomainContextFactory : IDbContextFactory<DomainContext>
{
public string BasePath { get; protected set; }
public DomainContext Create()
{
var environmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
var basePath = AppContext.BaseDirectory;
return Create(basePath, environmentName);
}
public DomainContext Create(DbContextFactoryOptions options)
=> Create(options.ContentRootPath, options.EnvironmentName);
private DomainContext Create(string basePath, string environmentName)
{
BasePath = basePath;
var configuration = Configuration(basePath, environmentName);
var connectionString = ConnectionString(configuration.Build());
return Create(connectionString);
}
private DomainContext Create(string connectionString)
{
if (string.IsNullOrEmpty(connectionString))
{
throw new ArgumentException($"{nameof(connectionString)} is null or empty", nameof(connectionString));
}
var optionsBuilder = new DbContextOptionsBuilder<DomainContext>();
return Configure(connectionString, optionsBuilder);
}
protected virtual IConfigurationBuilder Configuration(string basePath, string environmentName)
{
var builder = new ConfigurationBuilder()
.SetBasePath(basePath)
.AddJsonFile("constr.json")
.AddJsonFile($"constr.{environmentName}.json", true)
.AddEnvironmentVariables();
return builder;
}
protected virtual string ConnectionString(IConfigurationRoot configuration)
{
string connectionString = configuration["ConnectionStrings:DefaultConnection"];
return connectionString;
}
protected virtual DomainContext Configure(string connectionString, DbContextOptionsBuilder<DomainContext> builder)
{
builder.UseSqlServer(connectionString, opt => opt.UseRowNumberForPaging());
DomainContext db = new DomainContext(builder.Options);
return db;
}
DomainContext IDbContextFactory<DomainContext>.Create(DbContextFactoryOptions options)
=> Create(options.ContentRootPath, options.EnvironmentName);
}
It works with 3 configuration files (final, local and test)
constr.dev-final.json
constr.dev-local.json
constr.dev-test.json
The usage looks like the following:
public override IServiceResult<IList<Rolle>> LoadAllData()
{
using (var db = this.DomainContextFactory.Create())
{
Task<List<Rolle>> rollen = db.Roles
.ToListAsync<Rolle>();
return new ServiceResult<IList<Rolle>>(rollen.Result, rollen.Result.Count);
}
}
And using "Add-Migration" inside MSVC works also.