using FluentValidation; using Mapster; using Microsoft.Extensions.Configuration; using NewLife; using System.Configuration; using System.IO; using System.Text; using System.Windows; using System.Windows.Threading; using YY.Admin.Core; using YY.Admin.EventBus; using YY.Admin.Filter; using YY.Admin.Module; using YY.Admin.Properties; using YY.Admin.Services.Service.Print; using YY.Admin.Setup; using YY.Admin.ViewModels; using YY.Admin.Views; using YY.Admin.Core.Util; namespace YY.Admin { /// /// Interaction logic for App.xaml /// public partial class App : PrismApplication { private IConfiguration? _configuration; private ILoggerService? _logger; private readonly SyncModule _syncModule = new(); public App() { DispatcherUnhandledException += OnDispatcherUnhandledException; AppDomain.CurrentDomain.UnhandledException += OnUnhandledDomainException; } private static void TryWriteCrashLog(string headline, Exception ex) { try { var dir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "YY.Admin", "logs"); Directory.CreateDirectory(dir); var file = Path.Combine(dir, $"crash-{DateTime.Now:yyyyMMdd-HHmmss}.txt"); var sb = new StringBuilder(); sb.AppendLine(headline); sb.AppendLine(ex.ToString()); File.WriteAllText(file, sb.ToString(), Encoding.UTF8); MessageBox.Show($"程序异常已写入日志:\n{file}\n\n{ex.Message}", "智能制造MES工控", MessageBoxButton.OK, MessageBoxImage.Error); } catch { MessageBox.Show($"{headline}\n{ex}", "智能制造MES工控", MessageBoxButton.OK, MessageBoxImage.Error); } } private void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) { TryWriteCrashLog("UI 线程未处理异常", e.Exception); e.Handled = true; Shutdown(1); } private void OnUnhandledDomainException(object? sender, UnhandledExceptionEventArgs e) { if (e.ExceptionObject is Exception ex) { TryWriteCrashLog("域未处理异常", ex); } if (e.IsTerminating) { Environment.Exit(1); } } /// /// 写入用户级 AppSettings(user.config)。若文件损坏(如缺少 configSections),删除后重试一次。 /// private static void PersistSkinTypeUserSettingSafe() { for (var attempt = 0; attempt < 2; attempt++) { try { AppSettings.Default.SkinType = AppSettingsViewModel.GetSkinType().ToInt(); AppSettings.Default.Save(); return; } catch (ConfigurationErrorsException ex) { if (attempt == 0) { var path = ex.Filename; if (string.IsNullOrWhiteSpace(path) && ex.InnerException is ConfigurationErrorsException inner) path = inner.Filename; try { if (!string.IsNullOrWhiteSpace(path) && File.Exists(path)) File.Delete(path); AppSettings.Default.Reload(); } catch { // 删除/Reload 失败则向上抛出原异常 } continue; } throw; } } } protected override Window CreateShell() { return Container.Resolve(); } protected override void OnStartup(StartupEventArgs e) { try { var baseDirectory = AppDomain.CurrentDomain.BaseDirectory; var cfgPath = Path.Combine(baseDirectory, "Configuration", "appsettings.json"); if (!File.Exists(cfgPath)) { var msg = $"未找到配置文件(请确认与 YY.Admin.exe 同目录存在 Configuration\\appsettings.json):\n{cfgPath}"; TryWriteStartupFailure(msg); Shutdown(1); return; } var userCfgPath = Path.Combine( AppWritablePaths.EnsureDirectoryExists(AppWritablePaths.ConfigurationDirectory), "appsettings.json"); // 构建配置:安装目录默认 + 用户目录覆盖(JeecgIntegration 等可由服务器设置写入) _configuration = new ConfigurationBuilder() .SetBasePath(baseDirectory) .AddJsonFile(Path.Combine("Configuration", "appsettings.json"), optional: false, reloadOnChange: true) .AddJsonFile(userCfgPath, optional: true, reloadOnChange: true) .Build(); // 全局配置 TypeAdapterConfig.GlobalSettings.Default .IgnoreNullValues(true) .NameMatchingStrategy(NameMatchingStrategy.IgnoreCase); // FluentValidation 全局规则级别配置 ValidatorOptions.Global.DefaultRuleLevelCascadeMode = CascadeMode.Stop; // Mapster 全局配置 #if DEBUG //TypeAdapterConfig.GlobalSettings.RequireExplicitMapping = true; #endif base.OnStartup(e); } catch (Exception ex) { TryWriteCrashLog("启动阶段异常(配置/框架初始化失败)", ex); Shutdown(1); } } private static void TryWriteStartupFailure(string message) { try { var dir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "YY.Admin", "logs"); Directory.CreateDirectory(dir); var file = Path.Combine(dir, $"startup-{DateTime.Now:yyyyMMdd-HHmmss}.txt"); File.WriteAllText(file, message, Encoding.UTF8); MessageBox.Show($"{message}\n\n已记录:{file}", "智能制造MES工控", MessageBoxButton.OK, MessageBoxImage.Error); } catch { MessageBox.Show(message, "智能制造MES工控", MessageBoxButton.OK, MessageBoxImage.Error); } } //注册 protected override void RegisterTypes(IContainerRegistry containerRegistry) { //后续调整为配置依赖注入(Prism Module) // 注册错误处理 containerRegistry.RegisterSingleton(); //全局错误处理 containerRegistry.RegisterSingleton(); // 注册事件聚合器(Prism自带) containerRegistry.RegisterSingleton(); //项目配置选项 containerRegistry.AddProjectOptions(_configuration!); // 注册原始配置,供业务服务读取第三方对接参数 containerRegistry.RegisterInstance(_configuration!); // 注册缓存服务 containerRegistry.AddNewLifeCache(_configuration!); //注册数据库服务 containerRegistry.AddDbContext(_configuration!); //注册通知事件服务 containerRegistry.AddNotificationEventBus(); // 服务注册 containerRegistry.AddService(_configuration!); // 注册HttpClient连接池 containerRegistry.AddHttpClient(); // 注册断联续传同步模块 _syncModule.RegisterTypes(containerRegistry); // 注册所有需要导航的视图 containerRegistry.AddNavigation(); } protected override void OnInitialized() { base.OnInitialized(); // 获取日志服务 _logger = Container.Resolve(); // 初始化全局异常处理(通过解析触发构造函数注册) Container.Resolve(); // 保存默认主题(用户级 user.config;损坏时自动删文件并重载) PersistSkinTypeUserSettingSafe(); _logger.Information("应用程序已启动"); // 加载 PrintDot 本地设置(使 PrintDotService 在任何页面调用前已有配置) PrintDotSettings.Load(); // 启动断联续传同步模块 _syncModule.OnInitialized(Container); } protected override void OnExit(ExitEventArgs e) { BaseViewModel.StopTokenCheckTimer(); base.OnExit(e); _logger?.Information("应用程序已退出"); } } }