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

WPF MVVM全局异常处理器如何注入ErrorLog上下文?

我来帮你搞定这个问题!你遇到的核心问题是App.xaml.cs的构造时机早于Prism容器的初始化,所以直接构造注入肯定拿不到实例。咱们一步步来解决:

解决方案步骤

1. 确保ErrorLog服务已正确注册到Prism容器

首先,更推荐为ErrorLog单独定义服务接口(避免和业务模型的IModel混淆,符合单一职责原则),然后在Prism容器中完成注册。

先定义IErrorLogService:

public interface IErrorLogService : IDisposable
{
    void CreateErrorLog(ErrorLog errorLog);
}

接着实现对应的服务类(基于你Code First生成的ErrorLog模型):

public class ErrorLogService : IErrorLogService
{
    private readonly YourDbContext _dbContext; // 替换成你实际的数据库上下文类

    public ErrorLogService(YourDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public void CreateErrorLog(ErrorLog errorLog)
    {
        _dbContext.ErrorLogs.Add(errorLog);
        _dbContext.SaveChanges();
    }

    public void Dispose()
    {
        _dbContext?.Dispose();
    }
}

然后在你的Prism Bootstrapper(比如UnityBootstrapper或DryIocBootstrapper)的RegisterTypes方法中注册服务:

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
    // 注册你的业务模型服务(保留你原有的代码)
    containerRegistry.Register<IModel, ModelService>();

    // 注册ErrorLog服务,用单例生命周期减少上下文实例开销
    containerRegistry.RegisterSingleton<IErrorLogService, ErrorLogService>();

    // 别忘了注册数据库上下文(如果之前没注册的话)
    containerRegistry.Register<YourDbContext>();
}

2. 在App.xaml.cs中延迟获取服务实例

因为App的构造函数会在Prism容器初始化前执行,所以不能直接通过构造注入拿到服务。我们需要在Prism初始化完成后,通过容器实例获取服务:

修改App.xaml.cs代码:

public partial class App : Application
{
    private IErrorLogService _errorLogService;
    private Bootstrapper _bootstrapper; // 替换成你实际的Bootstrapper类

    protected override void OnStartup(StartupEventArgs e)
    {
        // 先初始化Prism Bootstrapper,完成容器注册
        _bootstrapper = new Bootstrapper();
        _bootstrapper.Run();

        // 此时容器已就绪,获取ErrorLog服务实例
        _errorLogService = _bootstrapper.Container.Resolve<IErrorLogService>();
        // 也可以用ServiceLocator(如果你的Bootstrapper支持):
        // _errorLogService = ServiceLocator.Current.GetInstance<IErrorLogService>();

        base.OnStartup(e);
    }

    private void Application_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
    {
        // 构造ErrorLog实体
        var errorLog = new ErrorLog
        {
            ErrorMessage = e.Exception.Message,
            StackTrace = e.Exception.StackTrace,
            OccurredTime = DateTime.Now
            // 补充你模型中需要的其他字段
        };

        try
        {
            // 保存异常日志到数据库
            _errorLogService.CreateErrorLog(errorLog);
        }
        catch (Exception ex)
        {
            // 容错处理:如果数据库保存失败,写入本地文件避免丢失日志
            File.AppendAllText(
                "FallbackErrorLog.txt",
                $"[{DateTime.Now}] 日志保存失败:{ex.Message}\r\n原始异常:{e.Exception.Message}\r\nStackTrace:{e.Exception.StackTrace}\r\n---\r\n"
            );
        }

        // 标记异常已处理(可选,根据你的需求决定是否让程序继续运行)
        e.Handled = true;
    }

    protected override void OnExit(ExitEventArgs e)
    {
        // 退出时释放服务资源
        _errorLogService?.Dispose();
        _bootstrapper?.Dispose();
        base.OnExit(e);
    }
}

3. 关键注意点

  • 禁止在App构造函数中注入:App构造函数执行时,Prism容器还未完成初始化,注入操作必然失败,必须在OnStartup中等待Bootstrapper运行完成后再获取服务。
  • 日志保存的容错性:保存异常日志的代码本身可能出错(比如数据库断开),一定要加try-catch做降级处理,避免日志保存失败导致程序二次崩溃。
  • 生命周期管理:使用RegisterSingleton确保ErrorLog服务仅创建一次,减少数据库上下文的资源开销,同时在App退出时记得释放资源。

如果你坚持要复用现有的IModel接口,只需在注册时添加命名标识,获取时指定名称即可:

// Bootstrapper中注册
containerRegistry.Register<IModel, ErrorLogService>("ErrorLogService");

// App中获取
_errorLogService = _bootstrapper.Container.Resolve<IModel>("ErrorLogService") as ErrorLogService;

不过还是推荐单独定义日志服务接口,代码会更清晰易维护。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:37:47