微服务中ApplicationDbContext重复创建致内存数据库种子数据丢失问题
问题描述
我正在开发一个微服务项目:
- 项目1:
CustomerService(提供客户编辑API) - 项目2:
CoreService(为.NET Core微服务提供基础配置,包含供项目1使用的ApplicationDbContext,以及ICustomerRepository及其实现CustomerRepostory等仓储)
注:使用内存数据库。
现有代码
CustomerService(项目1)的Program.cs
var builder = WebApplication.CreateBuilder(args); var serviceProvider = builder.Services.AddDbContext<ApplicationDbContext>().BuildServiceProvider(); using (var context = serviceProvider.GetRequiredService<ApplicationDbContext>()) { context.SeedData(); } builder.Services.AddHttpContextAccessor(); builder.Services.AddHttpClient(); builder.Services.AddScoped<IBaseService, BaseService>();
CoreService(项目2)的Program.cs
//add database related services builder.Services.AddDbContext<ApplicationDbContext>(options => { options.UseInMemoryDatabase("InMemoryDB"); });
CoreService中的ApplicationDbContext
public class ApplicationDbContext : DbContext { public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options): base(options) { } public DbSet<Customer> Customers { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseInMemoryDatabase("InMemoryDB"); } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Entity<Customer>().HasKey(b => b.Id); // declaring Id as Primary key } public void SeedData() { // Ensure the database is created this.Database.EnsureCreated(); if (!this.Customers.Any()) { // Add initial data if the Bookings table is empty this.Customers.AddRange( new Customer { Name = "Srijani", Email = "abc@gmail.com", Address = "Abcstraße 4, 123Hamburg", ContactNumber = "9876541232" } ); // Save changes after seeding data this.SaveChanges(); } } }
问题:运行项目时,调用CustomerService的API无法看到初始化的种子数据,推测是调用API时重新创建了ApplicationDbContext实例。如何避免这种情况,确保种子数据能被API访问到?
解决方案
核心问题是种子数据所在的内存数据库实例和API使用的不是同一个,加上DbContext注册与初始化方式有误,按以下步骤修复:
1. 清理ApplicationDbContext的冗余配置
移除OnConfiguring方法中的硬编码配置,因为已经在Program.cs中通过DbContextOptions注入了配置,重复配置会导致创建独立的数据库实例:
// 删除这段代码 protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseInMemoryDatabase("InMemoryDB"); }
2. 修正CustomerService中DbContext的注册与种子初始化逻辑
不要提前构建ServiceProvider执行种子操作,而是在应用启动完成后,从容器获取DbContext实例执行初始化,确保使用的是和API一致的注册实例:
修改CustomerService的Program.cs:
var builder = WebApplication.CreateBuilder(args); // 先注册DbContext,确保配置与CoreService一致 builder.Services.AddDbContext<ApplicationDbContext>(options => { options.UseInMemoryDatabase("InMemoryDB"); }); builder.Services.AddHttpContextAccessor(); builder.Services.AddHttpClient(); builder.Services.AddScoped<IBaseService, BaseService>(); var app = builder.Build(); // 应用启动后,通过作用域获取DbContext执行种子初始化 using (var scope = app.Services.CreateScope()) { var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>(); context.SeedData(); } // 后续中间件配置 app.MapControllers(); app.Run();
3. 确保内存数据库名称完全一致
内存数据库通过名称标识实例,所有配置中必须使用完全相同的名称(如"InMemoryDB"),不能有拼写错误或大小写差异,否则会创建独立的数据库。
4. 保持DbContext的默认生命周期
AddDbContext默认注册为Scoped生命周期(每个请求一个实例),这是合理的。API请求时会创建新的DbContext实例,但会连接到同一个内存数据库,因此能读取到种子数据,无需修改为Singleton或Transient。
内容的提问来源于stack exchange,提问作者Srijani Ghosh
相关产品推荐
相关产品推荐

