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("应用程序已退出");
}
}
}