You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF Core应用使用Caliburn.Micro时如何按请求注入AppDbContext

问题根因
  • 重复注册同类型服务:同时调用_container.Instance(_db)和_container.PerRequest<AppDbContext, AppDbContext>()时,会为AppDbContext类型注册两个无key服务条目。SimpleContainer解析无key服务时默认仅匹配单个注册条目,存在多条时就会抛出Sequence contains more than one element异常。
  • 依赖缺失导致实例化失败:单独使用PerRequest<AppDbContext, AppDbContext>()注册时空引用,是因为AppDbContext的构造函数需要DbContextOptions<AppDbContext>类型参数,但该依赖未注册到容器,SimpleContainer无法完成构造注入,导致实例创建失败。
  • 预生成全局DbContext实例的逻辑本身不符合需求:单例DbContext会存在缓存脏读、并发冲突等问题,和「每个请求独立DbContext实例」的目标完全冲突,不需要保留提前创建的_db实例。
修复步骤
  1. 移除Bootstrapper中预构造AppDbContext的私有字段_db及相关实例化逻辑,不需要提前创建DbContext实例。
  2. 将DbContextOptions<AppDbContext>数据库配置作为单例注册到容器,该配置线程安全,可被所有DbContext实例复用。
  3. 删除_container.Instance(_db)这行重复注册代码,仅保留PerRequest生命周期的AppDbContext注册。
  4. 修正原连接字符串中数据库路径的多余空格,避免数据库连接失败。
修正后的Bootstrapper代码
public class Bootstrapper : BootstrapperBase
{
    private SimpleContainer _container = new SimpleContainer();
    public Bootstrapper()
    {
        Initialize();

        ConventionManager.AddElementConvention<PasswordBox>(
        PasswordBoxHelper.BoundPasswordProperty,
        "Password",
        "PasswordChanged");
    }

    protected override void Configure()
    {
        _container.Instance(_container);

        // 注册DbContext配置,单例生命周期
        var options = new DbContextOptionsBuilder<AppDbContext>()
                 .UseJet(@"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=F:\AccessDatabase\TestDatabase1.accdb;")
             .Options;
        _container.Instance(options);

        _container.Singleton<IWindowManager, WindowManager>();
        _container.Singleton<IEventAggregator, EventAggregator>();
        _container.PerRequest<DataAccess, DataAccess>();
        // 仅保留按请求生命周期的AppDbContext注册,不需要额外注册预生成实例
        _container.PerRequest<AppDbContext, AppDbContext>();


        GetType().Assembly.GetTypes()
            .Where(type => type.IsClass)
            .Where(type => type.Name.EndsWith("ViewModel"))
            .ToList()
            .ForEach(viewModelType => _container.RegisterPerRequest(
                viewModelType, viewModelType.ToString(), viewModelType));
    }

    protected override async void OnStartup(object sender, StartupEventArgs e)
    {
        await DisplayRootViewForAsync<ShellViewModel>();
    }

    protected override object GetInstance(Type service, string key)
    {
        return _container.GetInstance(service, key);
    }

    protected override IEnumerable<object> GetAllInstances(Type service)
    {
        return _container.GetAllInstances(service);
    }

    protected override void BuildUp(object instance)
    {
        _container.BuildUp(instance);
    }
}
注意事项
  • SimpleContainer不会自动释放PerRequest生命周期的服务,AppDbContext作为占用数据库连接的非托管类型,使用完后需要手动调用Dispose()释放:如果是在ViewModel中长期注入持有,可在ViewModel的关闭/失活逻辑中释放;如果是临时使用,建议用using语句包裹解析逻辑,自动释放资源。
  • 所有依赖AppDbContext的服务(含DataAccess、ViewModel)必须通过容器解析,不要手动调用构造函数new实例,否则容器无法完成依赖注入,依然会出现空引用问题。

内容的提问来源于stack exchange,提问作者Kiarash Kanani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 12:42:06