WPF .NET6项目中DbContextFactory调用CreateDbContext()空异常排查
问题分析与修复方案
核心问题:_contextFactory未被依赖注入赋值
你在MainWindow中声明了_contextFactory字段,但没有通过依赖注入获取实例。因为你注册了MainWindow为瞬态服务,但使用的是无参构造函数,DI容器无法自动注入IDbContextFactory<MyDbContext>,导致_contextFactory始终为null,调用CreateDbContext()时触发空引用异常。
次要问题:MyDbContext.OnConfiguring代码冗余/错误
当optionsBuilder未配置时,你新建了DbContextOptionsBuilder实例但未将配置应用到传入的optionsBuilder上,属于无效代码。
MVVM架构优化建议
当前在Window中创建DbContext再传递给ViewModel的方式不符合职责分离原则,应将IDbContextFactory<MyDbContext>直接注入到ViewModel中,由ViewModel自行管理DbContext生命周期。
修复步骤
1. 修复MainWindow的依赖注入
修改MainWindow构造函数,通过构造函数注入IDbContextFactory<MyDbContext>:
public partial class MainWindow : Window { private readonly IDbContextFactory<MyDbContext> _contextFactory; private SomeViewModel _someViewModel; // 通过构造函数注入工厂实例 public MainWindow(IDbContextFactory<MyDbContext> contextFactory) { InitializeComponent(); _contextFactory = contextFactory; // 直接将工厂传入ViewModel(更符合MVVM) _someViewModel = new SomeViewModel(contextFactory); DataContext = _someViewModel; } }
2. 修正MyDbContext的OnConfiguring方法
删除冗余的DbContextOptionsBuilder创建逻辑,直接修改传入的optionsBuilder:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { if (!optionsBuilder.IsConfigured) { string defaultConnection = Settings.Default.DefaultConnection; // 直接使用传入的optionsBuilder配置数据库连接 optionsBuilder.UseMySql(defaultConnection, ServerVersion.AutoDetect(defaultConnection)); } optionsBuilder.UseLazyLoadingProxies(); optionsBuilder.LogTo(Console.WriteLine, LogLevel.Information); optionsBuilder.EnableSensitiveDataLogging(); optionsBuilder.EnableDetailedErrors(); }
3. 优化ViewModel的DbContext使用
将IDbContextFactory<MyDbContext>注入到ViewModel,由ViewModel自行创建DbContext:
public class SomeViewModel { private readonly IDbContextFactory<MyDbContext> _contextFactory; public SomeViewModel(IDbContextFactory<MyDbContext> contextFactory) { _contextFactory = contextFactory; } // 示例:使用工厂创建DbContext并执行数据操作 public async Task LoadDataAsync() { using var context = _contextFactory.CreateDbContext(); // 执行数据查询/操作,例如: // var dataList = await context.YourDbSet.ToListAsync(); } }
4. 确保服务提供者正确构建并启动应用
在App.xaml.cs中,必须从DI容器中获取MainWindow实例启动,而非直接new:
public partial class App : Application { private IServiceProvider _serviceProvider; protected override void OnStartup(StartupEventArgs e) { var services = new ServiceCollection(); ConfigureServices(services); _serviceProvider = services.BuildServiceProvider(); // 从容器中获取MainWindow实例,触发依赖注入 var mainWindow = _serviceProvider.GetRequiredService<MainWindow>(); mainWindow.Show(); } private void ConfigureServices(IServiceCollection services) { string defaultConnection = Settings.Default.DefaultConnection; services.AddDbContextFactory<MyDbContext>(options => options.UseMySql(defaultConnection, ServerVersion.AutoDetect(defaultConnection))); services.AddTransient<MainWindow>(); // 注册ViewModel到DI容器 services.AddTransient<SomeViewModel>(); } }
内容的提问来源于stack exchange,提问作者Donatas
相关产品推荐
相关产品推荐

