using AIK.Common.Interface; using AIK.Models.GuageModels; using AIK.Service.Extensions; using AIK.Service.IService; using AIK.Service.Service; using AIK.ViewModels; using AIK.ViewModels.ChipWriteStart; using AIK.ViewModels.CloudData; using AIK.ViewModels.CommonViewModel; using AIK.ViewModels.HomePage; using AIK.ViewModels.Integral; using AIK.ViewModels.Membership; using AIK.ViewModels.RemoteControlDetector; using AIK.ViewModels.RemoteCopy; using AIK.ViewModels.RemoteGeneration; using AIK.ViewModels.TirePressure; using AIK.ViewModels.UpdateCenter; using AIK.ViewModels.UserKeyRecord; using AIK.Views.AccountPages; using AIK.Views.MenuPages; using AIK.Views.MenuPages.ChipGeneration; using AIK.Views.MenuPages.ChipWriteStart; using AIK.Views.MenuPages.CloudData; using AIK.Views.MenuPages.CommonPage; using AIK.Views.MenuPages.Home; using AIK.Views.MenuPages.Integral; using AIK.Views.MenuPages.RemoteControlDetector; using AIK.Views.MenuPages.RemoteCopy; using AIK.Views.MenuPages.RemoteGeneration; using AIK.Views.MenuPages.TirePressure; using AIK.Views.MenuPages.UpdateCenter; using AIK.Views.UIServices; using AIK.Views.UpdatePages; using AIKKey.Infrastructure; using AutoUpdaterDotNET; using CommunityToolkit.Mvvm.DependencyInjection; using CommunityToolkit.Mvvm.Messaging; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using NLog; using NLog.Extensions.Hosting; using NLog.Extensions.Logging; using System; using System.Configuration; using System.Data; using System.Diagnostics; using System.Net; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Navigation; namespace AIKKey { /// /// Interaction logic for App.xaml /// public partial class App : Application { private static IHost? _host; private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private UpdateWindow _updateWindow; public static IHost Host => _host ??= CreateHostBuilder(Environment.GetCommandLineArgs()).Build(); private static Mutex _mutex; public static IServiceProvider Services => Host.Services; private IServiceProvider? _serviceProvider; public static IHostBuilder CreateHostBuilder(string[] args) => Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(args) .ConfigureAppConfiguration((context, config) => { config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); config.AddEnvironmentVariables(); }) .ConfigureLogging((context, logging) => { logging.ClearProviders(); logging.AddNLog(context.Configuration); }) .UseNLog() .ConfigureServices(ConfigureServices); private static void ConfigureServices(HostBuilderContext context, IServiceCollection services) { // 注册视图模型 services.AddSingleton(); services.AddTransient(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); #region 注册服务 // 基础服务 services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); //更新服务 services.AddSingleton(); //工厂(文件操作obd/bin) services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(sp => new FileServiceFactory( sp.GetRequiredService(), sp.GetRequiredService(), sp.GetRequiredService() )); //文件基础服务(复制、解压) services.AddSingleton(); //窗体弹窗 services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); //二维码 services.AddSingleton(); //业务服务 services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); //Hid通信 services.AddSingleton(); // 文件选择 services.AddSingleton(); #endregion //注册模型 services.AddSingleton(); // 单例模式,整个应用共享一个实例 // 注册 Messenger(单例) services.AddSingleton(provider => WeakReferenceMessenger.Default); // 注册窗口 services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddTransient(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddTransient(); services.AddTransient(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); // 注册 HttpClientFactory services.AddHttpClient(); } private void RegisterWindowMappings() { var windowService = Services.GetRequiredService(); // 注册功能窗口映射 windowService.RegisterWindow(WindowKey.VideoPopup, typeof(VideoPopupWindow), typeof(VideoPlayerViewModel)); } protected override async void OnStartup(StartupEventArgs e) { try { string appName = "AIKKeyWin7_Mutex"; // 替换为你的应用名 #if CN appName = "AIKKeyWin7_Mutex"; #elif TEST appName = "AIKKeyTESTWin7_Mutex"; #else appName = "AIKKeyGlobalWin7_Mutex"; #endif _mutex = new Mutex(true, appName, out bool createdNew); if (!createdNew) { MessageBox.Show("应用已在运行!"); Current.Shutdown(); return; } // 系统级操作(Win7 硬件重扫 CM_ReScan_DevNode 等)需要管理员权限: // 记录权限授予是否生效,便于排查"重扫未生效/权限未开启"问题。 //Logger.Info(UsbRescanHelper.IsAdministrator() // ? "权限授予成功:当前进程已以管理员权限运行(硬件重扫等系统操作可用)" // : "权限未授予:当前进程非管理员权限,硬件重扫(CM_ReScan_DevNode)等系统操作将无法执行"); // Win7 下 .NET Framework 默认仅协商 TLS 1.0,而服务器(key.aik518.com)只接受 TLS 1.2+, // 必须显式启用 TLS 1.2,否则所有 HTTPS/wss 请求(扫码登录、业务接口、图片下载)都会握手失败。 // 放在 base.OnStartup 之前:StartupUri 创建 MainWindow 时会立即发起扫码登录连接。 ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls; //// 系统级兜底:写入 SchUseStrongCrypto + SChannel TLS 1.2 注册表(需要管理员权限, //// 首次管理员运行一次后重启生效;无权限时只记日志,不阻塞启动)。 //if (TlsRegistryHelper.IsWindows7) //{ // TlsRegistryHelper.EnsureTls12Enabled(out bool changed, out string error); // if (changed) // { // Logger.Info("已写入 TLS 1.2 注册表配置(SchUseStrongCrypto + SChannel),需要重启系统后生效。"); // } // else if (!string.IsNullOrEmpty(error)) // { // Logger.Warn("TLS 1.2 注册表配置未写入: {Error}", error); // } // // 无论是否本次写入,都记录当前注册表实际状态,便于定位"配置了但未生效"的问题 // Logger.Info("TLS 1.2 注册表当前状态: {Status}", TlsRegistryHelper.GetRegistryStatus()); //} //// Win7 启动自检:用 SslStream 直接探测 TLS 1.2 握手,区分"网络不通"与"系统 SChannel 未启用 TLS 1.2" //_ = RunTls12StartupProbeAsync(); // 初始化全局异常处理 base.OnStartup(e); SetupExceptionHandling(); await Host.StartAsync(); Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); // 配置 CommunityToolkit.Mvvm 的 Ioc Ioc.Default.ConfigureServices(Services); IUpdateService updateService= Services.GetRequiredService(); //await updateService.StartUpdateProcess(); await updateService.CheckForUpdate(); RegisterWindowMappings(); // 后台预加热 WebView2 环境,加速 AI 客服窗口首次打开 _ = PreWarmWebView2Async(); } catch (Exception ex) { Logger.Fatal(ex, "应用程序启动失败"); MessageBox.Show($"应用程序启动失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error); Shutdown(); } } /// /// 后台预创建 WebView2 环境,避免 AI 客服窗口打开时实时初始化。 /// WebView2 运行时内部会缓存已创建的环境,后续 EnsureCoreWebView2Async 直接复用。 /// private static async Task PreWarmWebView2Async() { try { await Task.Run(() => Microsoft.Web.WebView2.Core.CoreWebView2Environment.CreateAsync()); } catch { // 预热失败不影响主流程,窗口打开时还会再尝试 EnsureCoreWebView2Async } } /// /// Win7 启动自检:对业务 API 服务器做一次 TLS 1.2 握手探测并记入日志。 /// 用于区分"网络不通"与"系统 SChannel 未启用 TLS 1.2"(后者在 Win7 上只能通过 /// 打补丁 + 写注册表 + 重启系统解决,代码层 ServicePointManager/SslProtocols 无法绕过)。 /// private static async Task RunTls12StartupProbeAsync() { try { string host; int port = 443; try { var configService = Services.GetRequiredService(); var baseUrl = configService.ApiSettings.BaseUrl; var uri = new Uri(baseUrl.Contains("://") ? baseUrl : "https://" + baseUrl); host = uri.Host; port = uri.Port > 0 ? uri.Port : 443; } catch { host = "key.aikkey.cn"; // 兜底,与日志中实际访问的服务器一致 } var result = await TlsRegistryHelper.ProbeTls12HandshakeAsync(host, port); Logger.Info("TLS 1.2 启动自检: {Result}", result); } catch (Exception ex) { Logger.Error(ex, "TLS 1.2 启动自检失败"); } } protected override async void OnExit(ExitEventArgs e) { _mutex?.ReleaseMutex(); base.OnExit(e); using (Host) { await Host.StopAsync(TimeSpan.FromSeconds(5)); } } private void SetupExceptionHandling() { // UI线程异常 DispatcherUnhandledException += (s, e) => { Logger.Fatal(e.Exception, "UI线程未处理异常"); e.Handled = true; ShowErrorDialog("应用程序错误", e.Exception); }; // 非UI线程异常 AppDomain.CurrentDomain.UnhandledException += (s, e) => { if (e.ExceptionObject is Exception ex) { Logger.Fatal(ex, "非UI线程未处理异常"); } }; // Task异常 TaskScheduler.UnobservedTaskException += (s, e) => { Logger.Error(e.Exception, "Task未观察异常"); e.SetObserved(); }; } private void ShowErrorDialog(string title, Exception ex) { // 使用ModernWPF或自定义对话框 MessageBox.Show($"{title}\n\n{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error); } public static void ConfigureServices(IServiceCollection services) { // 这个方法可以用于外部配置 ConfigureServices(null!, services); } } }