Files
XplorePlane/XP.Hardware.PLC.Sentry/App.xaml.cs
T

206 lines
9.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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;
}
}
}