I'm starting a new project using asp.net 5 and EF 7 VS2015.
I selected the project template with the user mangagement.
Now I want to add some classes to the dbContext and have a new schema created with my new classes.
This is wat my ApplicationDbContext looks like:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public DbSet<Candidate> Candidates { get; set; }
public DbSet<Manager> Managers { get; set; }
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);
builder.Entity<Candidate>().Key(x => x.Id);
builder.Entity<Manager>().Key(x => x.Id);
}
}
I have not been able to recreate or migrate my database to a version with my Candidates and Managers table.
Which commands do I have to enter where to make my DB appear? My friend Google and Bing have pointed me in every direction, but none of the things I found worked.
You need to use the new dnx commands, for example:
dnx . ef migration add NameOfMigration
And to run the migration:
dnx . ef migration apply
I found this CodeProject article that shows how to deal with migration on ASP .NET 5 project but in summary you need to apply the commands that #DavidG recommended in his answer.
I know this is not your case, but if you were working with a Class Library project, then the commands you would need to run are these:
Open the Package Manager Console:
Run Add-Migration MigrationName If it is the first time, it will to scaffold a migration to create the initial set of tables for your model, otherwise it will scaffold the next migration based on changes you have made to your model since the last migration was created.
Run Apply-Migration to apply the new migration to the database.
If your database doesn’t exist yet, it will be created for you
before the migration is applied.
To apply these commands you need to configure a database provider first. You can do this by overriding OnConfiguring in your DbContext class or in the AddDbContext method when setting up services.
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(#"Server=(localdb)\mssqllocaldb;Database=EFGetStarted.ConsoleApp;Trusted_Connection=True;");
}
As per ASP.NET 5 and Entity 7 RC1 the steps would be:
Add a dependency to the Entity Commands nuget package in your main project. So in your project.json you should see this dependency
"EntityFramework.Commands": "7.0.0-rc1-final"
Add an alias command to use from console later on. So in your project.json you would have the following ef command:
"commands": {
"ef": "EntityFramework.Commands",
"web": "Microsoft.AspNet.Server.Kestrel"
}
Open a console and run the migration commands. For example:
D:\Projects\MyProject\src\MyProject.Web.Api>dnx ef migrations add Initial --targetProject MyProject.Data.SqlServer
Then review the Migration that ef will create in your project and apply the changes to your database (the database that is configured for your project) with the following command:
D:\Projects\MyProject\src\MyProject.Web.Api>dnx ef database update
Notice that the attribute --targetProject allows you to specify the project where your DbContext is and where the folder Migrations would be created. If your DbContext is in your main project you can omit that (but I recommend to have a class library project for everything persistance related so this command would be handy)
In your Startup.cs is where you usually would have the configuration for Entity including the connection string. This is a basic example:
public Startup(IHostingEnvironment env)
{
// Set up configuration sources.
var builder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
builder.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; private set; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<KuneDbContext>(options => {
options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]);
});
// Add identity here http://docs.asp.net/en/latest/tutorials/your-first-aspnet-application.html
services.AddMvc();
// Add application services
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
app.UseBrowserLink();
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// For more details on creating database during deployment see http://go.microsoft.com/fwlink/?LinkID=615859
try
{
using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>()
.CreateScope())
{
serviceScope.ServiceProvider.GetService<KuneDbContext>()
.Database.Migrate();
}
}
catch { }
}
app.UseIISPlatformHandler();
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
//Seed Data if you want to load some test data in the DB
//SeedData.Initialize(app.ApplicationServices);
}
// Entry point for the application.
public static void Main(string[] args) => WebApplication.Run<Startup>(args);
}
Related
I've created an ASP.NET core 5 Solution and it consists of different projects. The Startup class and DataContext class are not in the same project so when I'm going to add a new migration on the Data project where DataContext is located I get the following error.
Unable to create an object of type 'DataContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728
It is the structure of the Solution:
I managed to solve the problem by adding the Startup project's name while adding a new migration, but this way seems annoying to add the project's name every time creating a new migration.
dotnet ef migrations add initialcreation -s ..\API\API.csproj
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.
I also add a new constructor with no parameter in the DataContext class and the result was the following 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.
Finally, I added the OnConfiguring function on DataContext and now it is like this:
public class DataContext : DbContext
{
public DataContext() {}
public DataContext(DbContextOptions<DataContext> options) : base(options)
{
this.ChangeTracker.LazyLoadingEnabled = false;
}
public DbSet<AppUser> Users { get; set; }
public DbSet<UserPhoto> Photos { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlite("name=DefaultConnection");
}
}
}
And again I got a new error while creating a new migration:
A named connection string was used, but the name 'DefaultConnection'
was not found in the application's configuration. Note that named
connection strings are only supported when using 'IConfiguration' and
a service provider, such as in a typical ASP.NET Core application. See
https://go.microsoft.com/fwlink/?linkid=850912 for more information.
UPDATE:
Here is appsettings.json file:
"ConnectionStrings": {
"DefaultConnection": "Data Source=database1.db"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
In Entity Framework Core, is it possible to see the SQL that will be applied when the SaveChanges() method is called on the DbContext?
EF Core 5.0+
There are a simple builtin solution, add the following function to the DbContext class.
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.LogTo(Console.WriteLine);
this will log both queries and commands.
See here for mote details: Simple Logging
Here are the docs on creating a LoggerFactory in Core 3. In short:
var loggerFactory = LoggerFactory.Create(builder =>
{
builder
.AddFilter("Microsoft", LogLevel.Warning)
.AddFilter("System", LogLevel.Warning)
.AddFilter("LoggingConsoleApp.Program", LogLevel.Debug)
.AddConsole()
.AddEventLog();
});
You may need to add a reference to Microsoft.Extensions.Logging.Console.
Use the DbContextOptionsBuilder to enable logging for a context.
optionsBuilder.UseLoggerFactory(loggerFactory)
I'll repeat the warning from here:
It is very important that applications do not create a new ILoggerFactory instance for each context instance. Doing so will result in a memory leak and poor performance.
Therefore, they recommend using a singleton/global instance:
public static readonly ILoggerFactory MyLoggerFactory =
LoggerFactory.Create(builder => { builder.AddConsole(); });
you can use console logger "EF Core logging automatically integrates with the logging mechanisms of .NET Core "
you can read about here :
https://www.entityframeworktutorial.net/efcore/logging-in-entityframework-core.aspx
You can use DbContextOptionsBuilder.UseLoggerFactory(loggerFactory) method to log all sql output.By using constructor Injection like below
public class DemoContext : ObjContext
{
private readonly ILoggerFactory _loggerFactory;
public DemoContext() { }
public DemoContext(ILoggerFactory loggerFactory)
{
_loggerFactory = loggerFactory;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
optionsBuilder.UseLoggerFactory(_loggerFactory);
}
}
using (var context = new DemoContext(_loggerFactory))
{
var Employees = context.Employee.ToList();
}
Or
I suggest a few other ways of viewing the SQL generated is to use reflection to create an ObjectQuery object and then call the ToTraceString() method to actually store the query results.
using (var context = new EntityContext())
{
var query = context.Customers.Where(c => c.Id == 1);
var sql = ((System.Data.Objects.ObjectQuery)query).ToTraceString();
}
Use SQL Logging
Using The DbContext.Database.Log property can be set to a delegate for any method that takes a string.
Log SQL to the Console.
using (var context = new EntityContext())
{
context.Database.Log = Console.Write;
}
Log SQL to Visual Studio Output panel.
using (var context = new EntityContext())
{
context.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
}
It's a bit tricky to log EF Core's SQL in an ASP.NET MVC web app. Unlike Entity Framework, EF Core lacks the easy-to-use DBContext.Database.Log property. As #DharmaTurtle mentioned, you can use LoggerFactory.Create, and this can work, but it does create a separate ILoggerFactory than the one that the rest of the app uses for logging (one that is apparently not using appsettings.json for options.)
The following approach is required if you want to use the same log factory for DBContext that the rest of the ASP.NET MVC web app uses:
Create a derived class of DbContext (or, if this was already done, modify the existing class appropriately). Note: this example will only log SQL in Debug builds, not Release builds.
public class DbContextWithLogging : Microsoft.EntityFrameworkCore.DbContext
{
ILoggerFactory _loggerFactory;
IConfiguration _configuration; // Provides access to appsettings.json
public DbContextWithLogging(ILoggerFactory loggerFactory, IConfiguration configuration)
=> (_loggerFactory, _configuration) = (loggerFactory, configuration);
protected override void OnConfiguring(DbContextOptionsBuilder builder)
{
#if DEBUG
builder.UseLoggerFactory(_loggerFactory);
// This line causes parameter values to be logged:
builder.EnableSensitiveDataLogging();
#endif
}
}
Note: this approach is not compatible with calling AddDbContext in Startup.ConfigureServices, so if there is already a call to AddDbContext, disable/remove it. In my case, the existing derived class of DbContext had a constructor that accepted (DbContextOptions<BarreleyeDbContext> options), which I removed.
In your Startup.ConfigureServices method, configure logging (e.g. to print to console) and enable the custom DbContext:
public void ConfigureServices(IServiceCollection services)
{
services.AddLogging((ILoggingBuilder builder) => {
builder.AddConsole();
});
// In ASP.NET Core apps, a Scope is created around each server request.
// So AddScoped<X, Y>() will recreate class Y for each HTTP request.
services.AddScoped<DbContext, DbContextWithLogging>();
... // leave the rest as before
}
Whatever uses DbContext (e.g. controllers, or 'repositories' in the Repository pattern) should obtain it automagically via constructor injection.
EF Core uses LogLevel.Information when printing the SQL, so you need the Information level to be enabled. If you look at your appsettings.json file, you'll want to see something like this:
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Information",
"Microsoft.Hosting.Lifetime": "Information"
}
},
In particular, EF Core log filtering can be controlled with a key like
"Microsoft.EntityFrameworkCore": "Information",
but if this key is missing, the "Microsoft" key is used instead.
This might not work! Look for a second file called appsettings.Development.json - watch out, Visual Studio might hide this file "inside" appsettings.json. If appsettings.Development.json exists, its contents override appsettings.json (at the granularity of individual keys).
Once it's working, you'll see log info that looks like this (yes, SELECT statements are logged as well as INSERT, UPDATE and DELETE):
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (0ms) [Parameters=[#__p_0='297'], CommandType='Text', CommandTimeout='30']
SELECT e.id, e.config, e.end_date, e.entity_name, e.entity_type, e.location, e.start_date
FROM entities AS e
WHERE e.id = #__p_0
LIMIT 1
I am trying to hook up persistence to my identity server by adding entity framework. Currently, when trying to add a migration I am receiving the error
No DbContext named 'ConfigurationDbContext' was found.
Before running the migration, I have cd'd into the directory my .csproj file sits in and am running dotnet ef migrations add InitConfigration -c ConfigurationDbContext -o Data/Migrations/IdentityServer/Configuration to attempt to add the migration.
My Startup.cs class looks as follows:
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.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
var migrationsAssembly = typeof(ApplicationDbContext).GetTypeInfo().Assembly.GetName().Name;
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddAspNetIdentity<ApplicationUser>()
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = builder =>
builder.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
db => db.MigrationsAssembly(migrationsAssembly));
})
.AddOperationalStore(options =>
{
options.ConfigureDbContext = builder =>
builder.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
db => db.MigrationsAssembly(migrationsAssembly));
});
}
// 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.UseIdentityServer();
app.UseMvc();
}
}
How can I resolve this issue?
EDIT: After further investigation, when i use the --project flag when generating the migration as follows: dotnet ef migrations add InitConfigration -c ConfigurationDbContext -o Data/Migrations/IdentityServer/Configuration --project BleacherBuddy.IdentityServerService, I receive the error:
MSBUILD : error MSB1009: Project file does not exist. Unable to
retrieve project metadata. Ensure it's an MSBuild-based .NET Core
project
My current guess is that because this is a service fabric project (stateless .net core), the build process is failing here and not allowing me to generate the migration. After some research, I'm still unsure how to overcome this or if this is the actual issue. I recreated the simple identity server project as a web api (not using service fabric) and I was able to generate the classes as expected. All help is appreciated.
dotnet ef migrations add InitConfigration -c ConfigurationDbContext -o Data/Migrations/IdentityServer/Configuration
In this command you explicitly ask dotnet ef to use ConfigurationDbContext class as a database context. You don't have it in your Startup.cs, so I assume you have it elsewhere. In that case you'll need to give a fully qualified class name to the tool, including the namespace, so your command should look like this:
dotnet ef migrations add InitConfigration -c Fully.Qualified.Namespaces.ConfigurationDbContext -o Data/Migrations/IdentityServer/Configuration
- replace Fully.Qualified.Namespaces. with the actual path to your ConfigurationDbContext class.
UPD:
Alternatively, since you actually setup your identity service with ApplicationDbContext as EF store, you might need to use the same context in your command:
dotnet ef migrations add InitConfigration -c ApplicationDbContext -o Data/Migrations/IdentityServer/Configuration
In this case you also might need to specify fully qualified namespace before the context class name.
I am using Identity Server 4. After making all kind of configurations in code, I visited this headline.
The point to note is that trying from Visual Studio will not help. So, it is better to open your IdentityServer project directory in command prompt and try following commands first
dotnet tool install --global dotnet-ef
dotnet add package Microsoft.EntityFrameworkCore.Design
and then try following
dotnet ef migrations add InitialIdentityServerPersistedGrantDbMigration -c PersistedGrantDbContext -o Migrations/IdentityServer/PersistedGrantDb
dotnet ef migrations add InitialIdentityServerConfigurationDbMigration -c ConfigurationDbContext -o Migrations/IdentityServer/ConfigurationDb
You will get your issue resolved out.
Here's what I did. Installed the following packages:
IdentityServer4
IdentityServer4.AspNetIdentity
IdentityServer4.EntityFramework
Microsoft.AspNetCore.Identity.EntityFrameworkCore
Microsoft.EntityFrameworkCore.Design
Microsoft.EntityFrameworkCore.SqlServer
And then, instead of just building the web project with these references, I ran the project and stopped it and then tried the
dotnet ef database update --context ConfigurationDbContext command and it worked.
I am guessing the issue could be with generating the object files or a complete NuGet package restore.
The issue will happen in three cases:
Even you are putting your migrations in separate class library so in this case you have to implement the design time interface and follow the Microsoft instructions.
Or you are installing this Nuget package to a class library by mistake IdentityServer4.EntityFrameWork.
You may have the docker-compose enable via visual studio which may cause the same issue as i described here: Add-Migration while using database in separate Docker container throws an error
In all cases make sure to clean then build the solution before run the command again.
I had the exact same problem, AFTER adding
services.AddDbContext<IdentityDbContext>(o => { o.UseSqlServer(Configuration.GetConnectionString("IdentityConnection")); });
When I commented that out, it could find the context again.
You Can Try This and it's working for me
dotnet add package IdentityServer4.EntityFramework
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
Add this line of code into Startup.cs
const string connectionString = #"Data Source=(LocalDb)\MSSQLLocalDB;database=IdentityServer4.Quickstart.EntityFramework-3.0.0;trusted_connection=yes;";
var migrationAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryApiResources(Config.GetAllApiResources())
.AddInMemoryClients(Config.GetClients())
.AddTestUsers(Config.GetUsers())
//Configuration Store: clients and resources
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = b =>
b.UseSqlServer(connectionString ,
sql => sql.MigrationsAssembly(migrationAssembly ));
})
//Operational Store: tokens, consents, codes, etc
.AddOperationalStore(options =>
{
options.ConfigureDbContext = b =>
b.UseSqlServer(connectionString,
sql => sql.MigrationsAssembly(migrationAssembly ));
});
Now, Finally try to add migrations
Add-Migration Initial_Configuration -c ConfigurationDbContext -o Migrations/IdentityServer4/ConfigurationDb
Add-Migration Initial_Persisted -c PersistedGrantDbContext -o Migrations/IdentityServer4/PersistedDb
This issue is a Bear.
None of the other answers here worked for me. There is a hint in one of the answers that you need to implement a Design Time DbContext, but there is no info on how to do that.
Anyway, here is the answer that helped me. I've done this type of stuff before, but nothing like this and I can't claim to have come up with this code. I found this answer highly rated on github:
https://github.com/IdentityServer/IdentityServer4/issues/2235#issuecomment-402467103
It is a lot of code, but here it is:
using System;
using System.IO;
using System.Reflection;
using Duende.IdentityServer.EntityFramework.DbContexts;
using Duende.IdentityServer.EntityFramework.Options;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Configuration;
namespace Awesome.IdentityServer.Infrastructure
{
public class ConfigurationContextDesignTimeFactory : DesignTimeDbContextFactoryBase<ConfigurationDbContext>
{
public ConfigurationContextDesignTimeFactory()
: base("AwesomeIdentity", typeof(Startup).GetTypeInfo().Assembly.GetName().Name)
{
}
protected override ConfigurationDbContext CreateNewInstance(DbContextOptions<ConfigurationDbContext> options)
{
return new ConfigurationDbContext(options, new ConfigurationStoreOptions());
}
}
public class PersistedGrantContextDesignTimeFactory : DesignTimeDbContextFactoryBase<PersistedGrantDbContext>
{
public PersistedGrantContextDesignTimeFactory()
: base("AwesomeIdentity", typeof(Startup).GetTypeInfo().Assembly.GetName().Name)
{
}
protected override PersistedGrantDbContext CreateNewInstance(DbContextOptions<PersistedGrantDbContext> options)
{
return new PersistedGrantDbContext(options, new OperationalStoreOptions());
}
}
public abstract class DesignTimeDbContextFactoryBase<TContext> : IDesignTimeDbContextFactory<TContext> where TContext : DbContext
{
protected string ConnectionStringName { get; }
protected String MigrationsAssemblyName { get; }
public DesignTimeDbContextFactoryBase(string connectionStringName, string migrationsAssemblyName)
{
ConnectionStringName = connectionStringName;
MigrationsAssemblyName = migrationsAssemblyName;
}
public TContext CreateDbContext(string[] args)
{
return Create(
Directory.GetCurrentDirectory(),
Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"),
ConnectionStringName, MigrationsAssemblyName);
}
protected abstract TContext CreateNewInstance(
DbContextOptions<TContext> options);
public TContext CreateWithConnectionStringName(string connectionStringName, string migrationsAssemblyName)
{
var environmentName =
Environment.GetEnvironmentVariable(
"ASPNETCORE_ENVIRONMENT");
var basePath = AppContext.BaseDirectory;
return Create(basePath, environmentName, connectionStringName, migrationsAssemblyName);
}
private TContext Create(string basePath, string environmentName, string connectionStringName, string migrationsAssemblyName)
{
var builder = new ConfigurationBuilder()
.SetBasePath(basePath)
.AddJsonFile("appsettings.json")
.AddJsonFile($"appsettings.{environmentName}.json", true)
.AddEnvironmentVariables();
var config = builder.Build();
var connstr = config.GetConnectionString(connectionStringName);
if (String.IsNullOrWhiteSpace(connstr) == true)
{
throw new InvalidOperationException(
"Could not find a connection string named 'default'.");
}
else
{
return CreateWithConnectionString(connstr, migrationsAssemblyName);
}
}
private TContext CreateWithConnectionString(string connectionString, string migrationsAssemblyName)
{
if (string.IsNullOrEmpty(connectionString))
throw new ArgumentException(
$"{nameof(connectionString)} is null or empty.",
nameof(connectionString));
var optionsBuilder =
new DbContextOptionsBuilder<TContext>();
Console.WriteLine(
"MyDesignTimeDbContextFactory.Create(string): Connection string: {0}",
connectionString);
optionsBuilder.UseSqlServer(connectionString, sqlServerOptions => sqlServerOptions.MigrationsAssembly(migrationsAssemblyName));
DbContextOptions<TContext> options = optionsBuilder.Options;
return CreateNewInstance(options);
}
}
}
Add this code to your Web project.
Make sure to have a good connection string name in your appsettings.json (Not appsetting.Development.json).
BTW, I was using this to upgrade IdentityServer4 to Duende Identity Server 5.
For me, I had to delete my obj and bin folders, then rebuild the project. Then the command worked.
this may help. this solved my problem as i have docker-compose in my project. i had to remove docker-compose and add it again.
https://stackoverflow.com/a/60320410/4977086
By default the tables's schema of Identity Server 4 is dbo, i want change it to security, so i create ConfigurationContext which inherit from ConfigurationDbContext:
public class ConfigurationContext : ConfigurationDbContext
{
public ConfigurationContext(DbContextOptions<ConfigurationDbContext> options, ConfigurationStoreOptions storeOptions) : base(options, storeOptions)
{ }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.HasDefaultSchema("Security");
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var relationalOptions = RelationalOptionsExtension.Extract(optionsBuilder.Options);
relationalOptions.MigrationsHistoryTableSchema = "Security";
}
}
and in add-migration i use ConfigurationContext :
Add-Migration -c ConfigurationContext
but i got this error:
No parameterless constructor was found on 'ConfigurationContext'. Either add a parameterless constructor to 'ConfigurationContext' or add an implementation of 'IDbContextFactory' in the same assembly as 'ConfigurationContext'.
what is the problem?
IdentityServer4 provides this option. In ConfigureServices,
services.AddIdentityServer()
.AddOperationalStore(builder => builder.UseSqlServer(cnStr, options =>
options.MigrationsAssembly(migAssembly)),
storeOption => storeOption.DefaultSchema = "security")
This way, you can continue to use the IDbContextFactory as suggested in the quickstarts.
I know this is quite an old question, but I recently had a similar issue; June Lau's answer does provide some of the info you need to resolve this, but the important part is that migrations don't inspect the database context at runtime, so you need to define the schema before you create your database migration.
Don't worry about extending ConfigurationDbContext either, as that's not needed, just add something like this to your ConfigureServices method in Startup.cs:
var identityServerBuilder = services.AddIdentityServer(options =>
{
// ...
});
var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
identityServerBuilder.AddConfigurationStore(options =>
{
options.DefaultSchema = "config";
options.ConfigureDbContext = b => b.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly));
});
Once you've added that code, create a migration for the relevant database context:
Add-Migration CreateInitialSchema -Context ConfigurationDbContext
You should see that the created migration starts like this:
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.EnsureSchema(
name: "config");
migrationBuilder.CreateTable(
name: "ApiResources",
schema: "config",
columns: table => new ...
The problem is that Add-Migration -c ConfigurationContext command does not startup your application and thus does not know how to resolve the classes in your constructor:
public ConfigurationContext( //How do i resolve this, i dont know?
DbContextOptions<ConfigurationDbContext> options,
ConfigurationStoreOptions storeOptions)
: base(options, storeOptions)
{ }
You need to add a parameterless constructor, as the error suggests:
public ConfigurationContext()
: base(/* todo default static logic here */)
{ /* and here */ }
Why
The database migration tries to create an instance of the ConfigurationContext to determine the 'desired' state (the state you want your database to be after the database migration has been executed).
This migration is a static file inside your project saying which Columns and which indexes etc need to be added or removed to the database to create the 'desired' state.
This Add-Migration command simply reflects your code to find the right context, it does not go through your startup class to see which dependencies you have the find (this would become way to complex since there could also be runtime dependencies or dependencies based on App-settings, etc)
Is there a way how to specify which DataProvider(SQL Server) and ConnectionString to use just for generating a migrations(Add-Migration) and updating a database(Update-Database)? I do not want to hardcode the data provider selection and connection string loading into DbContext (.UseSqlServer()).
I think EF6 can pick a connection string directly from web.config, is there something similar in EF7?
No you have to use optionsBuilder:
example:
string oldConnectionString =#"Server = .\;Initial Catalog=EFTutorial; AttachDbFilename=|DataDirectory|\EFTutorial.mdf; Trusted_Connection = True; MultipleActiveResultSets = true";
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(oldConnectionString );
base.OnConfiguring(optionsBuilder);
}
you can also load as json and load it directly from app.config or web.config.
If you are using .Net Core:
you can define in your appsettings.json the conenction string as following:
{
{
....
},
"Data": {
"ConnectionString": "..."
}
}
on App starting you have to load it:
// Set up configuration sources.
var builder = new ConfigurationBuilder().AddJsonFile("appsettings.json");
builder.AddEnvironmentVariables();
Configuration = builder.Build().ReloadOnChanged("appsettings.json");
After that you also have to configure Entity Framework in Startup.cs.
public void ConfigureServices(IServiceCollection services)
{
...
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<AppContext>(options =>
{
options.UseSqlServer(Configuration "Data:ConnectionString"]); });
services.AddScoped<AppContext, AppContext>();
...
}
}
The improtant thing here:
services.AddScoped((_) => new AppContext(Configuration["Data:DefaultConnection:ConnectionString"]));
https://docs.asp.net/en/latest/data/entity-framework-6.html
Examples to conenction string in Entity Framework Core 1.0 / 7:
https://docs.asp.net/en/latest/fundamentals/configuration.html
The old way(You can do that also with EF Core) we have load the conenctionString from App.config or web.config
and by the Migration process Add-Migration/Update-Database, EF will automatically found the Connection string.
But you can also provide the conenction string to Add-Migration in the NuGet comamnd line as parameter.
I hope this will solve your Problem!