应用启动基座 `ApplicationBase`
6. 应用启动基座ApplicationBase
位置:Source/Extensions/H.Extensions.ApplicationBase/ApplicationBase.cs
ApplicationBase继承 WPF 的Application,是整个框架的发动机。它负责:
- 设置应用关闭模式。
- 注册应用路径服务。
- 初始化全局异常处理。
- 创建
ServiceCollection。 - 调用
ConfigureServices。 - 构建 IOC 容器。
- 加载多语言。
- 启动时调用
Configure。 - 创建主窗口。
- 加载主题。
- 显示启动页。
- 执行登录。
- 显示主窗口。
- 启动定时任务。
- 退出时记录日志并停止任务。
自定义应用通常继承它:
publicpartialclassApp:ApplicationBase{protectedoverrideWindowCreateMainWindow(StartupEventArgse){returnnewMainWindow();}protectedoverridevoidConfigureServices(IServiceCollectionservices){services.AddAdornerDialogMessage();services.AddSnackMessage();services.AddSetting();}protectedoverridevoidConfigure(IApplicationBuilderapp){app.UseStyleOptions();}}区别:
ConfigureServices:注册能力,例如 services.AddSetting() Configure:启用配置,例如 app.UseStyleOptions()ApplicationBases目录下的组合项目:
| 项目 | 作用 |
|---|---|
H.ApplicationBases.Default | 默认应用组合,一键注册消息、模块、主题、日志。 |
H.ApplicationBases.Modules | 默认模块集合。 |
H.ApplicationBases.Themes | 默认主题集合。 |
H.ApplicationBases.Messages | 默认消息集合。 |
H.ApplicationBases.Identify | 身份认证应用基座。 |
ApplicationBase 应用启动基座详解
一、什么是 ApplicationBase
ApplicationBase是 WPF-Control 框架的核心启动类,它继承自 WPF 的Application类,封装了应用程序的完整生命周期管理。
一句话概括:ApplicationBase 是应用的"发动机",负责启动、运行和关闭的全过程。
二、核心架构
2.1 继承关系
System.Windows.Application │ ▼ ApplicationBase (H.Extensions.ApplicationBase) │ ▼ DefaultApplicationBase (H.ApplicationBases.Default) │ ▼ YourApp (自定义应用)2.2 职责矩阵
| 阶段 | 职责 | 方法 |
|---|---|---|
| 构造阶段 | 设置关闭模式、注册路径服务、初始化异常处理 | 构造函数 |
| 服务注册 | 创建 ServiceCollection、调用 ConfigureServices | InitServiceCollection() |
| 启动阶段 | 配置应用、单例检查、加载主题、启动页、登录 | OnStartup() |
| 运行阶段 | 显示主窗口、启动定时任务 | OnStartup() |
| 退出阶段 | 停止定时任务、记录日志 | OnExit() |
三、启动流程详解
3.1 完整流程时序图
用户双击应用 │ ▼ ┌──────────────────────────────────────┐ │ 1. 构造函数执行 │ │ - 设置 ShutdownMode │ │ - 注册 AppPath 服务 │ │ - 初始化异常处理 │ │ - 创建 ServiceCollection │ │ - 调用 ConfigureServices │ │ - 构建 IOC 容器 │ │ - 加载多语言 │ └──────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────┐ │ 2. OnStartup 执行 │ │ - 调用 Configure │ │ - 单例检查 (OnSingleton) │ │ - 创建主窗口 │ │ - 加载主题 │ │ - 显示启动页 (OnSplashScreen) │ │ - 执行登录 (OnLogin) │ │ - 显示主窗口 │ │ - 启动定时任务 │ └──────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────┐ │ 3. 应用运行中 │ │ - 用户操作控件 │ │ - Command/Presenter/Service响应 │ └──────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────┐ │ 4. OnExit 执行 │ │ - 停止定时任务 │ │ - 记录退出日志 │ └──────────────────────────────────────┘3.2 核心代码剖析
第一步:构造函数初始化
publicabstractpartialclassApplicationBase:Application,IConfigureableApplication,ILoginableApplication{publicApplicationBase(){// 1. 设置关闭模式:主窗口关闭时退出应用this.ShutdownMode=ShutdownMode.OnMainWindowClose;// 2. 注册应用路径服务AppPaths.Register(this.CreateAppPathServce());// 3. 初始化全局异常处理this.InitExcetion();// 4. 创建服务容器并构建this.InitServiceCollection();}}第二步:服务容器初始化
protectedvoidInitServiceCollection(){// 创建服务集合ServiceCollectionsc=newServiceCollection();// 调用子类的服务注册方法this.ConfigureServices(sc);// 构建 IOC 容器Ioc.Build(sc);// 在显示页面前加载多语言Ioc.GetService<ILoadGlobalizationOptionsService>(false)?.Load(outstringmessage);}第三步:启动流程
protectedoverridevoidOnStartup(StartupEventArgse){// 1. 应用配置this.Configure();// 2. 单例检查(确保只有一个实例运行)this.OnSingleton(e);base.OnStartup(e);// 3. 创建主窗口Windowwindow=this.CreateMainWindow(e);// 4. 主窗口加载完成后的回调window.Loaded+=(s,e)=>{varloads=Ioc.GetAssignableFromServices<IMainWindowLoadedLoadable>().Distinct();foreach(variteminloads)item.Load(outstringmessage);};// 5. 显示启动页this.OnSplashScreen(e);// 6. 执行登录this.OnLogin();// 7. 加载主窗口状态Ioc<IMainWindowSavableService>.Instance?.Load(window);// 8. 显示主窗口this.MainWindow.Show();// 9. 记录启动日志this.ILogger?.Info("系统启动");// 10. 启动定时任务Ioc<IScheduledTaskService>.Instance?.Start();}四、自定义应用实现
4.1 最简应用示例
publicpartialclassApp:ApplicationBase{// 必须重写:创建主窗口protectedoverrideWindowCreateMainWindow(StartupEventArgse){returnnewMainWindow();}// 可选:注册服务protectedoverridevoidConfigureServices(IServiceCollectionservices){services.AddAdornerDialogMessage();// 注册消息服务services.AddSnackMessage();// 注册 Snack 消息services.AddSetting();// 注册设置服务}// 可选:应用配置protectedoverridevoidConfigure(IApplicationBuilderapp){app.UseStyleOptions();// 启用样式配置}}4.2 完整应用示例
publicpartialclassApp:ApplicationBase{protectedoverridevoidConfigureServices(IServiceCollectionservices){// 1. 注册应用基础服务services.AddApplicationServices();// 2. 注册项目服务services.AddProject<MyProjectService>(x=>x.UseOpenCurrentOnLoad=false);// 3. 注册模块services.AddHome<ProjectHomeViewPresenter>();// 4. 注册标签服务services.AddTag<ProjectTagService>(x=>{x.Tags.Add(newTag(){Name="重要",Background=Brushes.Red});x.Tags.Add(newTag(){Name="普通",Background=Brushes.Gray});});// 5. 注册数据库services.AddDbContextBySetting<MyDataContext>();services.AddSingleton<IRepository<MyEntity>,DbContextRepository<MyDataContext,MyEntity>>();}protectedoverridevoidConfigure(IApplicationBuilderapp){// 启用应用配置app.UseApplicationOptions();}protectedoverrideWindowCreateMainWindow(StartupEventArgse){returnnewMainWindow();}}五、ConfigureServices vs Configure
5.1 核心区别
| 方法 | 时机 | 作用 | 典型操作 |
|---|---|---|---|
| ConfigureServices | IOC 容器构建前 | 注册服务和能力 | services.AddXXX() |
| Configure | IOC 容器构建后 | 启用配置和中间件 | app.UseXXX() |
5.2 通俗理解
ConfigureServices:告诉框架"我有哪些能力" ├─ 注册服务:services.AddSetting() ├─ 注册模块:services.AddHome() └─ 注册数据库:services.AddDbContext() Configure:告诉框架"我要启用哪些能力" ├─ 启用设置:app.UseSettingOptions() ├─ 启用样式:app.UseStyleOptions() └─ 启用主题:app.UseThemeOptions()5.3 执行顺序
1. ConfigureServices(services) │ ├─→ services.AddSetting() ├─→ services.AddMessage() └─→ services.AddHome() │ ▼ 2. Ioc.Build() ←── 构建容器 │ ▼ 3. Configure(app) │ ├─→ app.UseSettingOptions() ├─→ app.UseMessageOptions() └─→ app.UseHomeOptions()六、ApplicationBases 组合项目
6.1 项目结构
ApplicationBases/ ├── H.ApplicationBases.Default/ # 默认应用组合 ├── H.ApplicationBases.Modules/ # 默认模块集合 ├── H.ApplicationBases.Themes/ # 默认主题集合 ├── H.ApplicationBases.Messages/ # 默认消息集合 └── H.ApplicationBases.Identify/ # 身份认证基座6.2 各项目作用
| 项目 | 作用 | 包含内容 |
|---|---|---|
| H.ApplicationBases.Default | 一键注册所有基础服务 | 消息、模块、主题、日志 |
| H.ApplicationBases.Modules | 默认功能模块 | 首页、设置、帮助、关于 |
| H.ApplicationBases.Themes | 默认主题样式 | Light、Dark、系统主题 |
| H.ApplicationBases.Messages | 默认消息组件 | Dialog、Snack、Notice |
| H.ApplicationBases.Identify | 身份认证支持 | 登录、权限验证 |
6.3 使用默认组合
publicpartialclassApp:DefaultApplicationBase{// 只需实现 CreateMainWindowprotectedoverrideWindowCreateMainWindow(StartupEventArgse){returnnewMainWindow();}// 可选:额外注册服务protectedoverridevoidConfigureServices(IServiceCollectionservices){base.ConfigureServices(services);// 调用基类注册默认服务// 添加自定义服务services.AddSingleton<IMyService,MyService>();}}6.4 默认服务注册流程
// AddApplicationServices 方法会自动注册:services.AddDefaultMessages();// 消息服务services.AddDefaultModuleServices();// 模块服务services.AddDefaultThemeServices();// 主题服务services.AddLog4net();// 日志服务七、异常处理机制
7.1 三种异常类型
protectedvirtualvoidInitExcetion(){// 1. UI 线程异常DispatcherUnhandledException+=App_DispatcherUnhandledException;// 2. 非 UI 线程异常AppDomain.CurrentDomain.UnhandledException+=CurrentDomain_UnhandledException;// 3. 异步任务异常TaskScheduler.UnobservedTaskException+=TaskScheduler_UnobservedTaskException;}7.2 异常处理示例
protectedvoidApp_DispatcherUnhandledException(objectsender,DispatcherUnhandledExceptionEventArgse){// 显示错误消息this.ShowMessage(e.Exception?.ToString(),"系统异常");// 标记异常已处理e.Handled=true;// 记录日志this.ILogger?.Error("系统异常");this.ILogger?.Error(e.Exception);}八、单例检查机制
8.1 实现原理
privateMutexmutex;publicvirtualvoidOnSingleton(StartupEventArgse){ProcessthisProc=Process.GetCurrentProcess();boolcreatedNew;// 创建命名互斥锁(以进程名作为锁名)mutex=newMutex(true,thisProc.ProcessName,outcreatedNew);// 如果锁已存在,说明已有实例在运行if(!createdNew){this.ShowMessage("应用程序已在运行中");this.Shutdown();}}8.2 使用场景
| 场景 | 说明 |
|---|---|
| 资源独占 | 避免多个实例访问同一硬件/文件 |
| 状态一致性 | 确保应用状态不被多个实例修改 |
| 内存优化 | 避免重复加载资源 |
九、最佳实践
9.1 应用组织规范
MyApp/ ├── App.xaml.cs # 继承 ApplicationBase ├── MainWindow.xaml # 主窗口 ├── ViewModels/ # 视图模型 ├── Services/ # 自定义服务 ├── Modules/ # 自定义模块 └── Resources/ # 资源文件9.2 服务注册顺序
protectedoverridevoidConfigureServices(IServiceCollectionservices){// 1. 先注册基础服务services.AddApplicationServices();// 2. 再注册业务服务services.AddDbContextBySetting<MyDataContext>();services.AddSingleton<IMyService,MyService>();// 3. 最后注册模块services.AddHome<MyHomePresenter>();}9.3 扩展方法命名约定
| 前缀 | 含义 | 示例 |
|---|---|---|
AddXXX | 注册服务 | AddSetting(),AddMessage() |
UseXXX | 启用配置 | UseSettingOptions(),UseStyleOptions() |
TryAddXXX | 安全注册(不覆盖) | TryAddSingleton() |
十、总结
ApplicationBase 为 WPF 应用提供了一站式启动解决方案:
- 生命周期管理:从启动到退出的完整流程
- 服务注册:通过 IOC 容器管理所有依赖
- 异常处理:全局捕获三种异常类型
- 单例保证:确保应用只运行一个实例
- 模块化组合:通过 ApplicationBases 快速构建应用
通过继承 ApplicationBase,开发者可以专注于业务逻辑,无需关心底层基础设施的搭建。
