206 lines
9.4 KiB
C#
206 lines
9.4 KiB
C#
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
|
||
{
|
||
/// <summary>
|
||
/// PLC Sentry Monitor 应用程序入口 | PLC Sentry Monitor application entry point
|
||
/// </summary>
|
||
public partial class App : PrismApplication
|
||
{
|
||
/// <summary>
|
||
/// 应用程序日志实例(带模块上下文)| Application logger instance (with module context)
|
||
/// </summary>
|
||
private ILogger _logger => Log.ForContext("SourceContext", "XP.Hardware.PLC.Sentry");
|
||
|
||
/// <summary>
|
||
/// 创建主窗口 | Create main shell window
|
||
/// </summary>
|
||
protected override Window CreateShell()
|
||
{
|
||
return Container.Resolve<SentryMainWindow>();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 注册类型到依赖注入容器 | Register types to DI container
|
||
/// </summary>
|
||
protected override void RegisterTypes(IContainerRegistry containerRegistry)
|
||
{
|
||
// === 注册 XP.Common 基础服务 | Register XP.Common base services ===
|
||
containerRegistry.RegisterSingleton<ILoggerService, SerilogLoggerService>();
|
||
|
||
// === 注册 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<IPlcClient, S7PlcClient>();
|
||
|
||
// PlcService 单例(依赖:IPlcClient, ILoggerService, XmlSignalParser)
|
||
// PlcService singleton (deps: IPlcClient, ILoggerService, XmlSignalParser)
|
||
containerRegistry.RegisterSingleton<PlcService>();
|
||
|
||
// IPlcService 接口映射到同一个 PlcService 单例 | IPlcService interface maps to same PlcService singleton
|
||
containerRegistry.Register<IPlcService>(c => c.Resolve<PlcService>());
|
||
|
||
// 配置加载器(瞬态)| Configuration loader (transient)
|
||
containerRegistry.Register<PLC.Configs.ConfigLoader>();
|
||
|
||
// XML 信号解析器(瞬态)| XML signal parser (transient)
|
||
containerRegistry.Register<XmlSignalParser>();
|
||
|
||
// PLC 写入队列单例(依赖:IPlcClient, ILoggerService)| PLC write queue singleton
|
||
containerRegistry.RegisterSingleton<PlcWriteQueue>();
|
||
|
||
// 信号数据交互服务单例(依赖:PlcService, PlcWriteQueue, IPlcClient, ILoggerService)
|
||
// Signal data service singleton
|
||
containerRegistry.RegisterSingleton<ISignalDataService, SignalDataService>();
|
||
|
||
// === 注册 PLC 已有窗口 | Register existing PLC windows ===
|
||
containerRegistry.Register<PlcAddrConfigEditorWindow>();
|
||
containerRegistry.Register<PLC.ViewModels.PlcAddrConfigEditorViewModel>();
|
||
|
||
// === 注册 Sentry 视图和 ViewModel | Register Sentry views and ViewModels ===
|
||
containerRegistry.Register<SentryMainWindow>();
|
||
containerRegistry.Register<Sentry.ViewModels.SentryMainViewModel>();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 配置模块目录 | Configure module catalog
|
||
/// </summary>
|
||
protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
|
||
{
|
||
// 注册通用模块(提供本地化、Dump 等基础服务)| Register common module (provides localization, dump, etc.)
|
||
moduleCatalog.AddModule<XP.Common.Module.CommonModule>();
|
||
|
||
base.ConfigureModuleCatalog(moduleCatalog);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 应用程序启动 | Application startup
|
||
/// </summary>
|
||
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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 应用程序初始化完成 | Application initialization completed
|
||
/// </summary>
|
||
protected override void OnInitialized()
|
||
{
|
||
base.OnInitialized();
|
||
|
||
// 注册模块级多语言资源到 Fallback Chain | Register module-level localization resources to Fallback Chain
|
||
try
|
||
{
|
||
var localizationService = Container.Resolve<ILocalizationService>();
|
||
|
||
// 注册 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<PlcService>();
|
||
var writeQueue = Container.Resolve<PlcWriteQueue>();
|
||
var signalDataService = Container.Resolve<ISignalDataService>() as SignalDataService;
|
||
plcService.RegisterWriteComponents(writeQueue, signalDataService?.DirectWriteChannel);
|
||
|
||
_logger.Information("PLC Sentry Monitor 初始化完成 | PLC Sentry Monitor initialization completed");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 应用程序退出 | Application exit
|
||
/// </summary>
|
||
protected override void OnExit(ExitEventArgs e)
|
||
{
|
||
_logger.Information("PLC Sentry Monitor 退出 | PLC Sentry Monitor exiting");
|
||
Log.CloseAndFlush();
|
||
base.OnExit(e);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 捕获 UI 线程未处理异常 | Capture UI thread unhandled exceptions
|
||
/// </summary>
|
||
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;
|
||
}
|
||
}
|
||
}
|