Skip to content

Commit 72faac0

Browse files
committed
refactor(data): improve seeding with UseAsyncSeeding
1 parent 33f5b67 commit 72faac0

File tree

4 files changed

+56
-50
lines changed

4 files changed

+56
-50
lines changed

Dotnet.Samples.AspNetCore.WebApi/Program.cs

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using Dotnet.Samples.AspNetCore.WebApi.Data;
33
using Dotnet.Samples.AspNetCore.WebApi.Mappings;
44
using Dotnet.Samples.AspNetCore.WebApi.Services;
5+
using Dotnet.Samples.AspNetCore.WebApi.Utilities;
56
using Microsoft.EntityFrameworkCore;
67
using Microsoft.OpenApi.Models;
78
using Serilog;
@@ -20,26 +21,22 @@
2021
* Logging
2122
* -------------------------------------------------------------------------- */
2223
Log.Logger = new LoggerConfiguration().ReadFrom.Configuration(builder.Configuration).CreateLogger();
23-
2424
builder.Host.UseSerilog();
2525

2626
/* -----------------------------------------------------------------------------
2727
* Services
2828
* -------------------------------------------------------------------------- */
29-
3029
builder.Services.AddControllers();
31-
32-
var dataSource =
33-
$"{AppDomain.CurrentDomain.SetupInformation.ApplicationBase}/Data/players-sqlite3.db";
34-
3530
builder.Services.AddDbContextPool<PlayerDbContext>(options =>
3631
{
32+
var dataSource = Path.Combine(AppContext.BaseDirectory, "Data", "players-sqlite3.db");
3733
options.UseSqlite($"Data Source={dataSource}");
38-
3934
if (builder.Environment.IsDevelopment())
4035
{
4136
options.EnableSensitiveDataLogging();
42-
options.LogTo(Console.WriteLine, LogLevel.Information);
37+
options.LogTo(Log.Logger.Information, LogLevel.Information);
38+
// https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-9.0/whatsnew#improved-data-seeding
39+
options.UseAsyncSeeding(DbContextUtils.SeedAsync);
4340
}
4441
});
4542

@@ -84,16 +81,16 @@
8481
* Middlewares
8582
* https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware
8683
* -------------------------------------------------------------------------- */
87-
88-
app.UseSerilogRequestLogging();
89-
9084
if (app.Environment.IsDevelopment())
9185
{
9286
// https://learn.microsoft.com/en-us/aspnet/core/tutorials/getting-started-with-swashbuckle
9387
app.UseSwagger();
9488
app.UseSwaggerUI();
9589
}
9690

91+
// https://github.com/serilog/serilog-aspnetcore
92+
app.UseSerilogRequestLogging();
93+
9794
// https://learn.microsoft.com/en-us/aspnet/core/security/enforcing-ssl
9895
app.UseHttpsRedirection();
9996

@@ -103,11 +100,4 @@
103100
// https://learn.microsoft.com/en-us/aspnet/core/fundamentals/routing#endpoints
104101
app.MapControllers();
105102

106-
/* -----------------------------------------------------------------------------
107-
* Data Seeding
108-
* https://learn.microsoft.com/en-us/ef/core/modeling/data-seeding
109-
* -------------------------------------------------------------------------- */
110-
111-
app.SeedDbContext();
112-
113103
await app.RunAsync();
Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,38 @@
1-
namespace Dotnet.Samples.AspNetCore.WebApi.Data;
1+
using Dotnet.Samples.AspNetCore.WebApi.Data;
2+
using Microsoft.EntityFrameworkCore;
3+
4+
namespace Dotnet.Samples.AspNetCore.WebApi.Utilities;
25

36
public static class ApplicationBuilderExtensions
47
{
58
/// <summary>
6-
/// Simple extension method to populate the database with an initial set of data.
9+
/// Async extension method to populate the database with initial data
710
/// </summary>
8-
public static void SeedDbContext(this IApplicationBuilder app)
11+
public static async Task SeedDbContextAsync(this IApplicationBuilder app)
912
{
1013
using var scope = app.ApplicationServices.CreateScope();
11-
var dbContext = scope.ServiceProvider.GetService<PlayerDbContext>();
14+
var services = scope.ServiceProvider;
15+
var logger = services.GetRequiredService<ILogger<Program>>();
16+
var dbContext = services.GetRequiredService<PlayerDbContext>();
1217

13-
if (dbContext != null)
18+
try
1419
{
15-
// https://learn.microsoft.com/en-us/ef/core/managing-schemas/ensure-created
16-
dbContext.Database.EnsureCreated();
20+
await dbContext.Database.EnsureCreatedAsync();
1721

18-
if (!dbContext.Players.Any())
22+
if (!await dbContext.Players.AnyAsync())
1923
{
20-
dbContext.Players.AddRange(PlayerData.CreateStarting11());
24+
await dbContext.Players.AddRangeAsync(PlayerData.CreateStarting11());
25+
await dbContext.SaveChangesAsync();
26+
logger.LogInformation("Successfully seeded database with initial data.");
2127
}
2228
}
29+
catch (Exception exception)
30+
{
31+
logger.LogError(exception, "An error occurred while seeding the database");
32+
throw new InvalidOperationException(
33+
"An error occurred while seeding the database",
34+
exception
35+
);
36+
}
2337
}
2438
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using Dotnet.Samples.AspNetCore.WebApi.Data;
2+
using Microsoft.EntityFrameworkCore;
3+
4+
namespace Dotnet.Samples.AspNetCore.WebApi.Utilities;
5+
6+
public static class DbContextUtils
7+
{
8+
public static Task SeedAsync(DbContext context, bool _, CancellationToken cancellationToken)
9+
{
10+
var playerDbContext = (PlayerDbContext)context;
11+
return SeedPlayersAsync(playerDbContext, cancellationToken);
12+
}
13+
14+
private static async Task SeedPlayersAsync(
15+
PlayerDbContext dbContext,
16+
CancellationToken cancellationToken
17+
)
18+
{
19+
if (!await dbContext.Players.AnyAsync(cancellationToken))
20+
{
21+
await dbContext.Players.AddRangeAsync(PlayerData.CreateStarting11(), cancellationToken);
22+
await dbContext.SaveChangesAsync(cancellationToken);
23+
}
24+
}
25+
}

Dotnet.Samples.AspNetCore.WebApi/Utilities/PlayerDataExtensions.cs

Lines changed: 0 additions & 23 deletions
This file was deleted.

0 commit comments

Comments
 (0)