Reputation: 5457
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.
Upvotes: 14
Views: 23982
Reputation: 605
In my case, my appsettings.json
file isn't formatted correctly, particularly on the connection string section. I'm using SQL Server Express and I didn't include an escape character which made my appsettings.json
invalid.
Here's the adjustments I made to my connection string:
Before: DbConnectionString: Server=localhost\SQLEXPRESS...
After: DbConnectionString: Server=localhost\\SQLEXPRESS...
Upvotes: 0
Reputation: 95
In my case it was because I run command on different project in manager console, changed default project and it worked.
Upvotes: 0
Reputation: 16373
For me, I had to delete my obj and bin folders, then rebuild the project. Then the command worked.
Upvotes: 1
Reputation: 25029
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.
Upvotes: 3
Reputation: 1
You Can Try This and it's working for me
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
Upvotes: 0
Reputation: 1879
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.
Upvotes: 3
Reputation: 720
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.
Upvotes: 0
Reputation: 1345
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.
Upvotes: 2
Reputation: 135
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
Upvotes: -1
Reputation: 2714
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.
Upvotes: 1
Reputation: 10487
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.
Upvotes: 8