using System.IO;
using System.Text;
using System.Windows;
using System.Windows.Threading;
using AxiOmron.PcbCheck.Options;
using AxiOmron.PcbCheck.Services.Implementations;
using AxiOmron.PcbCheck.Services.Interfaces;
using AxiOmron.PcbCheck.Utils;
using AxiOmron.PcbCheck.ViewModels;
using AxiOmron.PcbCheck.Views.Pages;
using AxiOmron.PcbCheck.Views.Windows;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using NLog.Extensions.Logging;
namespace AxiOmron.PcbCheck;
///
/// 表示 WPF 应用入口,负责 Host/DI、配置和日志初始化。
///
public partial class App : Application
{
private static readonly NLog.Logger FallbackLogger = NLog.LogManager.GetCurrentClassLogger();
private IHost? _host;
///
/// 获取当前应用服务容器。
///
public static IServiceProvider Services { get; private set; } = null!;
///
/// 应用启动入口。
///
/// 启动事件参数。
protected override async void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
RegisterGlobalExceptionHandlers();
try
{
Console.OutputEncoding = Encoding.UTF8;
}
catch (IOException)
{
// WinExe 在没有控制台句柄时忽略
}
try
{
_host = BuildHost();
await _host.StartAsync().ConfigureAwait(true);
Services = _host.Services;
var mainWindow = Services.GetRequiredService();
MainWindow = mainWindow;
mainWindow.Show();
}
catch (Exception ex)
{
LogGlobalException("应用启动失败", ex);
MessageBox.Show($"应用启动失败: {ex.Message}", "Axi Omron PCB Check", MessageBoxButton.OK, MessageBoxImage.Error);
Shutdown(-1);
}
}
///
/// 应用退出入口。
///
/// 退出事件参数。
protected override async void OnExit(ExitEventArgs e)
{
UnregisterGlobalExceptionHandlers();
if (_host is not null)
{
try
{
await ShutdownHelper.StopHostAsync(_host, TimeSpan.FromSeconds(2));
}
finally
{
_host.Dispose();
}
}
base.OnExit(e);
}
///
/// 构建应用 Host 与依赖注入容器。
///
/// 已构建的 Host 实例。
private static IHost BuildHost()
{
return Host.CreateDefaultBuilder()
.ConfigureAppConfiguration((context, configurationBuilder) =>
{
configurationBuilder.SetBasePath(AppContext.BaseDirectory);
configurationBuilder.AddJsonFile("appConfig.json", optional: true, reloadOnChange: false);
configurationBuilder.AddJsonFile($"appConfig.{context.HostingEnvironment.EnvironmentName}.json", optional: true, reloadOnChange: false);
})
.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.SetMinimumLevel(LogLevel.Information);
logging.AddNLog();
})
.ConfigureServices((context, services) =>
{
var appConfig = new AppConfig();
context.Configuration.Bind(appConfig);
services.AddSingleton(context.Configuration);
services.AddSingleton();
services.AddSingleton(appConfig);
services.AddSingleton();
services.AddSingleton(typeof(IAppLogger<>), typeof(AppLogger<>));
services.AddSingleton();
services.AddSingleton(TimeProvider.System);
services.AddHttpClient(nameof(AndonService));
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
services.AddSingleton(sp => sp.GetRequiredService());
services.AddHostedService(sp => sp.GetRequiredService());
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
services.AddTransient();
services.AddSingleton();
})
.Build();
}
///
/// 注册全局异常处理器,用于兜底记录 UI 线程、未观察任务和域级异常。
///
private void RegisterGlobalExceptionHandlers()
{
DispatcherUnhandledException += OnDispatcherUnhandledException;
AppDomain.CurrentDomain.UnhandledException += OnCurrentDomainUnhandledException;
TaskScheduler.UnobservedTaskException += OnTaskSchedulerUnobservedTaskException;
}
///
/// 注销全局异常处理器。
///
private void UnregisterGlobalExceptionHandlers()
{
DispatcherUnhandledException -= OnDispatcherUnhandledException;
AppDomain.CurrentDomain.UnhandledException -= OnCurrentDomainUnhandledException;
TaskScheduler.UnobservedTaskException -= OnTaskSchedulerUnobservedTaskException;
}
///
/// 处理 UI 线程未捕获异常,记录日志并阻止应用直接闪退。
///
/// 事件源。
/// 异常事件参数。
private void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
LogGlobalException("UI 线程未处理异常", e.Exception);
MessageBox.Show($"程序捕获到未处理异常,已写入日志:{e.Exception.Message}", "Axi Omron PCB Check", MessageBoxButton.OK, MessageBoxImage.Warning);
e.Handled = true;
}
///
/// 处理未观察任务异常,记录日志并标记为已观察。
///
/// 事件源。
/// 异常事件参数。
private void OnTaskSchedulerUnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs e)
{
LogGlobalException("未观察任务异常", e.Exception);
e.SetObserved();
}
///
/// 处理应用程序域未捕获异常,尽量在进程退出前补充日志。
///
/// 事件源。
/// 异常事件参数。
private void OnCurrentDomainUnhandledException(object? sender, UnhandledExceptionEventArgs e)
{
var exception = e.ExceptionObject as Exception ?? new Exception(e.ExceptionObject?.ToString() ?? "未知未处理异常");
LogGlobalException($"应用程序域未处理异常(IsTerminating={e.IsTerminating})", exception);
}
///
/// 统一记录全局异常日志,优先复用宿主日志器,失败时退回 NLog 直接写入。
///
/// 日志消息。
/// 异常对象。
private static void LogGlobalException(string message, Exception exception)
{
try
{
if (Services is not null)
{
var logger = Services.GetService>();
logger?.LogError(exception, message);
}
}
catch
{
// 忽略宿主日志失败,继续使用回退日志。
}
try
{
FallbackLogger.Error(exception, message);
}
catch
{
// 全局兜底日志不再向外抛出。
}
}
}