5

Entity Framework Core: Why you should never name your DbContext 'IdentityDbConte...

 1 year ago
source link: https://alexanderzeitler.com/articles/entity-framework-core-why-you-should-never-name-your-db-context-identitydbcontext/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Entity Framework Core: Why you should never name your DbContext 'IdentityDbContext'

Published on Saturday, March 18, 2023
Don't do this

This is more or less a follow up to the previous post.

As said in the post already, I was playing around with Startup.cs style of application start up together with Entity Framework Core / ASP.NET Identity scaffolding.

So after I got Identity scaffolded, I re-added the Startup.cs and wanted to move on with migrations.

My Program.cs looked like this:

public class Program
{
public static void Main(
string[] args
)
{
CreateHostBuilder(args)
.Build()
.Run();
}

public static IHostBuilder CreateHostBuilder(
string[] args
) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
}

This was the Startup.cs:

public class Startup
{
public IConfiguration Configuration { get; }

public Startup(
IHostEnvironment env
)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile(
"appsettings.json",
optional: false,
reloadOnChange: true
)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}


// This method gets called by the runtime. Use this method to add services to the container
public void ConfigureServices(
IServiceCollection services
)
{
var connectionString = Configuration.GetConnectionString("IdentityDbContextConnection") ??
throw new InvalidOperationException(
"Connection string 'IdentityDbContextConnection' not found."
);

services.AddDbContext<IdentityDbContext>(options => options.UseNpgsql(connectionString));

services.AddDefaultIdentity<AppUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<IdentityDbContext>();

services.AddControllersWithViews();
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline
public void Configure(
IApplicationBuilder app,
IWebHostEnvironment env
)
{
// Configure the HTTP request pipeline.
if (!env.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.UseEndpoints(
endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}"
);
}
);
}
}

The next step would be to create the first migration and seed the database:

dotnet ef migrations add CreateIdentitySchema

Straight forward, one might think... but no:

More than one DbContext was found. Specify which one to use. Use the '-Context' parameter for PowerShell commands and the '--context' parameter for dotnet commands.

So, let's get a list of the contexts available using dotnet ef dbcontext list:

dotnet ef dbcontext list
Build started...
Build succeeded.
Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityDbContext
WebAppWithIdentity.Areas.Identity.Data.IdentityDbContext

Ok, let's try to use a full qualified name then:

dotnet ef database update --context WebAppWithIdentity.Areas.Identity.Data.IdentityDbContext

Build started... Build succeeded. Unable to create an object of type 'IdentityDbContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728

That's not funny, tbh.

Well, let's go back to scaffolding and try this one (still with Startup.cs in use):

dotnet aspnet-codegenerator identity -dc SecurityDbContext -u AppUser -f -gl -dbProvider sqlite

Result:

Building project ...
Finding the generator 'identity'...
Running the generator 'identity'...
RunTime 00:00:17.25

Umm... no let's list the contexts again:

dotnet ef dbcontext list
Build started...
Build succeeded.
WebAppWithIdentity.Areas.Identity.Data.SecurityDbContext

Well, that's interesting.

Now, let's try to run the migrations:

dotnet ef migrations add CreateIdentitySchema
Build started...
Build succeeded.
Done. To undo this action, use 'ef migrations remove'

And the final step: apply the changes to the actual database:

dotnet ef database update

Build started...
Build succeeded.

# shortened the output a bit here
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (14ms) [Parameters=[], CommandType='Text', CommandTimeout='20']
CREATE UNIQUE INDEX "UserNameIndex" ON "AspNetUsers" ("NormalizedUserName");
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (14ms) [Parameters=[], CommandType='Text', CommandTimeout='20']
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
VALUES ('20230318144833_CreateIdentitySchema', '7.0.4');
Done.

Ok, lessons learned:

Never name your DbContent IdentityDbContext


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK