using Prism.Ioc; using Prism.Modularity; using Prism.Unity; using Serilog; using System; using System.Resources; using System.Windows; using XP.Common.Configs; using XP.Common.Localization; using XP.Common.Localization.Interfaces; using XP.Common.Logging; using XP.Common.Logging.Implementations; using XP.Common.Logging.Interfaces; using XP.Hardware.Plc.Abstractions; using XP.Hardware.Plc.Core; using XP.Hardware.Plc.Services; using XP.Hardware.PLC.Configs; using XP.Hardware.PLC.Helpers; using XP.Hardware.PLC.Services; using XP.Hardware.PLC.Sentry.Views; using XP.Hardware.PLC.Views; namespace XP.Hardware.PLC.Sentry { /// /// PLC Sentry Monitor 应用程序入口 | PLC Sentry Monitor application entry point /// public partial class App : PrismApplication { /// /// 应用程序日志实例(带模块上下文)| Application logger instance (with module context) /// private ILogger _logger => Log.ForContext("SourceContext", "XP.Hardware.PLC.Sentry"); /// /// 创建主窗口 | Create main shell window /// protected override Window CreateShell() { return Container.Resolve(); } /// /// 注册类型到依赖注入容器 | Register types to DI container /// protected override void RegisterTypes(IContainerRegistry containerRegistry) { // === 注册 XP.Common 基础服务 | Register XP.Common base services === containerRegistry.RegisterSingleton(); // === 注册 PLC 核心服务(复用 PLCModule 的注册模式)| Register PLC core services (reuse PLCModule registration pattern) === // IPlcClient 瞬态注册,每次 Resolve 创建独立实例,避免并发竞争 // IPlcClient registered as transient, each Resolve creates independent instance to avoid contention containerRegistry.Register(); // PlcService 单例(依赖:IPlcClient, ILoggerService, XmlSignalParser) // PlcService singleton (deps: IPlcClient, ILoggerService, XmlSignalParser) containerRegistry.RegisterSingleton(); // IPlcService 接口映射到同一个 PlcService 单例 | IPlcService interface maps to same PlcService singleton containerRegistry.Register(c => c.Resolve()); // 配置加载器(瞬态)| Configuration loader (transient) containerRegistry.Register(); // XML 信号解析器(瞬态)| XML signal parser (transient) containerRegistry.Register(); // PLC 写入队列单例(依赖:IPlcClient, ILoggerService)| PLC write queue singleton containerRegistry.RegisterSingleton(); // 信号数据交互服务单例(依赖:PlcService, PlcWriteQueue, IPlcClient, ILoggerService) // Signal data service singleton containerRegistry.RegisterSingleton(); // === 注册 PLC 已有窗口 | Register existing PLC windows === containerRegistry.Register(); containerRegistry.Register(); // === 注册 Sentry 视图和 ViewModel | Register Sentry views and ViewModels === containerRegistry.Register(); containerRegistry.Register(); } /// /// 配置模块目录 | Configure module catalog /// protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog) { // 注册通用模块(提供本地化、Dump 等基础服务)| Register common module (provides localization, dump, etc.) moduleCatalog.AddModule(); base.ConfigureModuleCatalog(moduleCatalog); } /// /// 应用程序启动 | Application startup /// protected override void OnStartup(StartupEventArgs e) { // 尽早注册非托管异常捕获 | Register unmanaged exception handler early AppDomain.CurrentDomain.UnhandledException += (s, args) => { var ex = args.ExceptionObject as Exception; try { _logger.Fatal(ex, "检测到未处理异常(IsTerminating={IsTerminating})| Unhandled exception detected (IsTerminating={IsTerminating})", args.IsTerminating); Log.CloseAndFlush(); // 向用户显示友好的错误提示 | Show friendly error message to user MessageBox.Show( $"应用发生严重错误,即将退出。请查看日志获取详细信息。\n\n{ex?.Message}\n\nA critical error occurred. The application will exit. Please check logs for details.", "致命错误 | Fatal Error", MessageBoxButton.OK, MessageBoxImage.Error); } catch { /* 最后的防线 | Last resort */ } }; // 加载并初始化 Serilog | Load and initialize Serilog SerilogConfig serilogConfig = XP.Common.Helpers.ConfigLoader.LoadSerilogConfig(); SerilogInitializer.Initialize(serilogConfig); _logger.Information("PLC Sentry Monitor 启动开始 | PLC Sentry Monitor startup started"); base.OnStartup(e); } /// /// 应用程序初始化完成 | Application initialization completed /// protected override void OnInitialized() { base.OnInitialized(); // 注册模块级多语言资源到 Fallback Chain | Register module-level localization resources to Fallback Chain try { var localizationService = Container.Resolve(); // 注册 PLC 模块的多语言资源(PlcAddrConfigEditorWindow 等窗口依赖) // Register PLC module localization resources (required by PlcAddrConfigEditorWindow, etc.) var plcResourceManager = new ResourceManager( "XP.Hardware.PLC.Resources.Resources", typeof(XP.Hardware.PLC.PLCModule).Assembly); localizationService.RegisterResourceSource("XP.Hardware.PLC", plcResourceManager); // 注册 Sentry 模块的多语言资源 | Register Sentry module localization resources var resourceManager = new ResourceManager( "XP.Hardware.PLC.Sentry.Resources.Resources", typeof(App).Assembly); localizationService.RegisterResourceSource("XP.Hardware.PLC.Sentry", resourceManager); // 初始化 LocalizationHelper | Initialize LocalizationHelper LocalizationHelper.Initialize(localizationService); } catch (Exception ex) { _logger.Warning(ex, "Sentry 多语言资源注册失败 | Sentry localization resource registration failed"); } // 注册写入组件到 PlcService | Register write components to PlcService var plcService = Container.Resolve(); var writeQueue = Container.Resolve(); var signalDataService = Container.Resolve() as SignalDataService; plcService.RegisterWriteComponents(writeQueue, signalDataService?.DirectWriteChannel); _logger.Information("PLC Sentry Monitor 初始化完成 | PLC Sentry Monitor initialization completed"); } /// /// 应用程序退出 | Application exit /// protected override void OnExit(ExitEventArgs e) { _logger.Information("PLC Sentry Monitor 退出 | PLC Sentry Monitor exiting"); Log.CloseAndFlush(); base.OnExit(e); } /// /// 捕获 UI 线程未处理异常 | Capture UI thread unhandled exceptions /// private void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) { _logger.Fatal(e.Exception, "应用发生未处理异常 | Application encountered unhandled exception"); try { // 尝试刷新日志确保异常信息被持久化 | Flush logs to ensure exception info is persisted Log.CloseAndFlush(); } catch { /* 日志刷新失败不影响异常处理 | Log flush failure should not affect exception handling */ } MessageBox.Show( $"应用发生未处理异常,请查看日志获取详细信息。\n\n{e.Exception.Message}\n\nApplication encountered an unhandled exception. Please check logs for details.", "错误 | Error", MessageBoxButton.OK, MessageBoxImage.Error); // 标记异常已处理,防止应用崩溃 | Mark exception as handled to prevent app crash e.Handled = true; } } }