diff --git a/demo/WPFDemo/WPFDemo.Api/CommandLines/Options.cs b/demo/WPFDemo/WPFDemo.Api/CommandLines/Options.cs
new file mode 100644
index 0000000..62494f4
--- /dev/null
+++ b/demo/WPFDemo/WPFDemo.Api/CommandLines/Options.cs
@@ -0,0 +1,13 @@
+using dotnetCampus.Cli;
+
+namespace WPFDemo.Api.CommandLines
+{
+ ///
+ /// 启动参数
+ ///
+ public class Options
+ {
+ [Option("Name")]
+ public string? Name { set; get; }
+ }
+}
diff --git a/demo/WPFDemo/WPFDemo.Api/Properties/AssemblyInfo.cs b/demo/WPFDemo/WPFDemo.Api/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..e44dfdc
--- /dev/null
+++ b/demo/WPFDemo/WPFDemo.Api/Properties/AssemblyInfo.cs
@@ -0,0 +1,6 @@
+using dotnetCampus.ApplicationStartupManager;
+using dotnetCampus.Telescope;
+
+using WPFDemo.Api.StartupTaskFramework;
+
+[assembly: MarkExport(typeof(StartupTask), typeof(StartupTaskAttribute))]
diff --git a/demo/WPFDemo/WPFDemo.Api/Startup/Foo1Startup.cs b/demo/WPFDemo/WPFDemo.Api/Startup/Foo1Startup.cs
new file mode 100644
index 0000000..9377dba
--- /dev/null
+++ b/demo/WPFDemo/WPFDemo.Api/Startup/Foo1Startup.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using dotnetCampus.ApplicationStartupManager;
+
+using WPFDemo.Api.StartupTaskFramework;
+
+namespace WPFDemo.Api.Startup
+{
+ [StartupTask(BeforeTasks = StartupNodes.CoreUI, AfterTasks = StartupNodes.Foundation)]
+ public class Foo1Startup : StartupTask
+ {
+ protected override Task RunAsync(StartupContext context)
+ {
+ context.Logger.LogInfo("Foo1 Startup");
+ return base.RunAsync(context);
+ }
+ }
+}
diff --git a/demo/WPFDemo/WPFDemo.Api/Startup/OptionStartup.cs b/demo/WPFDemo/WPFDemo.Api/Startup/OptionStartup.cs
new file mode 100644
index 0000000..22c95b0
--- /dev/null
+++ b/demo/WPFDemo/WPFDemo.Api/Startup/OptionStartup.cs
@@ -0,0 +1,16 @@
+using dotnetCampus.ApplicationStartupManager;
+using WPFDemo.Api.StartupTaskFramework;
+
+namespace WPFDemo.Api.Startup
+{
+ [StartupTask(BeforeTasks = StartupNodes.Foundation, AfterTasks = "LibStartup")]
+ class OptionStartup : StartupTask
+ {
+ protected override Task RunAsync(StartupContext context)
+ {
+ context.Logger.LogInfo("Command " + context.CommandLineOptions.Name);
+
+ return CompletedTask;
+ }
+ }
+}
diff --git a/demo/WPFDemo/WPFDemo.Api/StartupTaskFramework/AssemblyMetadataExporter.cs b/demo/WPFDemo/WPFDemo.Api/StartupTaskFramework/AssemblyMetadataExporter.cs
new file mode 100644
index 0000000..d5f3e99
--- /dev/null
+++ b/demo/WPFDemo/WPFDemo.Api/StartupTaskFramework/AssemblyMetadataExporter.cs
@@ -0,0 +1,34 @@
+using System.Reflection;
+using dotnetCampus.ApplicationStartupManager;
+using dotnetCampus.Telescope;
+
+namespace WPFDemo.Api.StartupTaskFramework
+{
+ public class AssemblyMetadataExporter
+ {
+ public AssemblyMetadataExporter(Assembly[] assemblies)
+ {
+ _assemblies = assemblies;
+ }
+
+ public IEnumerable ExportStartupTasks()
+ {
+ var collection = Export();
+ return collection.Select(x => new StartupTaskMetadata(x.RealType.Name.Replace("Startup", ""), x.CreateInstance)
+ {
+ Scheduler = x.Attribute.Scheduler,
+ BeforeTasks = x.Attribute.BeforeTasks,
+ AfterTasks = x.Attribute.AfterTasks,
+ //Categories = x.Attribute.Categories,
+ CriticalLevel = x.Attribute.CriticalLevel,
+ });
+ }
+
+ public IEnumerable> Export() where TAttribute : Attribute
+ {
+ return AttributedTypes.FromAssembly(_assemblies);
+ }
+
+ private readonly Assembly[] _assemblies;
+ }
+}
diff --git a/demo/WPFDemo/WPFDemo.Api/StartupTaskFramework/StartupContext.cs b/demo/WPFDemo/WPFDemo.Api/StartupTaskFramework/StartupContext.cs
new file mode 100644
index 0000000..3001cb5
--- /dev/null
+++ b/demo/WPFDemo/WPFDemo.Api/StartupTaskFramework/StartupContext.cs
@@ -0,0 +1,42 @@
+using dotnetCampus.ApplicationStartupManager;
+using dotnetCampus.Cli;
+using dotnetCampus.Configurations;
+using dotnetCampus.Configurations.Core;
+using WPFDemo.Api.CommandLines;
+
+namespace WPFDemo.Api.StartupTaskFramework
+{
+ public class StartupContext : IStartupContext
+ {
+ public StartupContext(IStartupContext startupContext, CommandLine commandLine, StartupLogger logger, FileConfigurationRepo configuration, IAppConfigurator configs)
+ {
+ _startupContext = startupContext;
+ Logger = logger;
+ Configuration = configuration;
+ Configs = configs;
+ CommandLine = commandLine;
+ CommandLineOptions = CommandLine.As();
+ }
+
+ public StartupLogger Logger { get; }
+
+ public CommandLine CommandLine { get; }
+
+ public Options CommandLineOptions { get; }
+
+ public FileConfigurationRepo Configuration { get; }
+
+ public IAppConfigurator Configs { get; }
+
+ public Task ReadCacheAsync(string key, string @default = "")
+ {
+ return Configuration.TryReadAsync(key, @default);
+ }
+
+ private readonly IStartupContext _startupContext;
+ public Task WaitStartupTaskAsync(string startupKey)
+ {
+ return _startupContext.WaitStartupTaskAsync(startupKey);
+ }
+ }
+}
diff --git a/demo/WPFDemo/WPFDemo.Api/StartupTaskFramework/StartupLogger.cs b/demo/WPFDemo/WPFDemo.Api/StartupTaskFramework/StartupLogger.cs
new file mode 100644
index 0000000..d5d8727
--- /dev/null
+++ b/demo/WPFDemo/WPFDemo.Api/StartupTaskFramework/StartupLogger.cs
@@ -0,0 +1,29 @@
+using System.Diagnostics;
+using System.Text;
+
+using dotnetCampus.ApplicationStartupManager;
+
+namespace WPFDemo.Api.StartupTaskFramework
+{
+ ///
+ /// 和项目关联的日志
+ ///
+ public class StartupLogger : StartupLoggerBase
+ {
+ public void LogInfo(string message)
+ {
+ Debug.WriteLine(message);
+ }
+
+ public override void ReportResult(IReadOnlyList wrappers)
+ {
+ var stringBuilder = new StringBuilder();
+ foreach (var keyValuePair in MilestoneDictionary)
+ {
+ stringBuilder.AppendLine($"{keyValuePair.Key} - [{keyValuePair.Value.threadName}] Start:{keyValuePair.Value.start} Elapsed:{keyValuePair.Value.elapsed}");
+ }
+
+ Debug.WriteLine(stringBuilder.ToString());
+ }
+ }
+}
diff --git a/demo/WPFDemo/WPFDemo.Api/StartupTaskFramework/StartupManager.cs b/demo/WPFDemo/WPFDemo.Api/StartupTaskFramework/StartupManager.cs
new file mode 100644
index 0000000..e5e67d7
--- /dev/null
+++ b/demo/WPFDemo/WPFDemo.Api/StartupTaskFramework/StartupManager.cs
@@ -0,0 +1,25 @@
+using dotnetCampus.ApplicationStartupManager;
+using dotnetCampus.Cli;
+using dotnetCampus.Configurations.Core;
+
+namespace WPFDemo.Api.StartupTaskFramework
+{
+ ///
+ /// 和项目关联的启动管理器,用来注入业务相关的逻辑
+ ///
+ public class StartupManager : StartupManagerBase
+ {
+ public StartupManager(CommandLine commandLine, FileConfigurationRepo configuration, Func fastFailAction, IMainThreadDispatcher mainThreadDispatcher) : base(new StartupLogger(), fastFailAction, mainThreadDispatcher)
+ {
+ var appConfigurator = configuration.CreateAppConfigurator();
+ Context = new StartupContext(StartupContext, commandLine, (StartupLogger) Logger, configuration, appConfigurator);
+ }
+
+ private StartupContext Context { get; }
+
+ protected override Task ExecuteStartupTaskAsync(StartupTaskBase startupTask, IStartupContext context, bool uiOnly)
+ {
+ return base.ExecuteStartupTaskAsync(startupTask, Context, uiOnly);
+ }
+ }
+}
diff --git a/demo/WPFDemo/WPFDemo.Api/StartupTaskFramework/StartupNodes.cs b/demo/WPFDemo/WPFDemo.Api/StartupTaskFramework/StartupNodes.cs
new file mode 100644
index 0000000..225a7a7
--- /dev/null
+++ b/demo/WPFDemo/WPFDemo.Api/StartupTaskFramework/StartupNodes.cs
@@ -0,0 +1,36 @@
+namespace WPFDemo.Api.StartupTaskFramework
+{
+ ///
+ /// 包含预设的启动节点。
+ ///
+ public class StartupNodes
+ {
+ ///
+ /// 基础服务(日志、异常处理、容器、生命周期管理等)请在此节点之前启动,其他业务请在此之后启动。
+ ///
+ public const string Foundation = "Foundation";
+
+ ///
+ /// 需要在任何一个 Window 创建之前启动的任务请在此节点之前。
+ /// 此节点之后将开始启动 UI。
+ ///
+ public const string CoreUI = "CoreUI";
+
+ ///
+ /// 需要在主 创建之后启动的任务请在此节点之后。
+ /// 此节点完成则代表主要 UI 已经初始化完毕(但不一定已显示)。
+ ///
+ public const string UI = "UI";
+
+ ///
+ /// 应用程序已完成启动。如果应该显示一个窗口,则此窗口已布局、渲染完毕,对用户完全可见,可开始交互。
+ /// 不被其他业务依赖的模块可在此节点之后启动。
+ ///
+ public const string AppReady = "AppReady";
+
+ ///
+ /// 任何不关心何时启动的启动任务应该设定为在此节点之前完成。
+ ///
+ public const string StartupCompleted = "StartupCompleted";
+ }
+}
diff --git a/demo/WPFDemo/WPFDemo.Api/StartupTaskFramework/StartupTask.cs b/demo/WPFDemo/WPFDemo.Api/StartupTaskFramework/StartupTask.cs
new file mode 100644
index 0000000..3e3d1c6
--- /dev/null
+++ b/demo/WPFDemo/WPFDemo.Api/StartupTaskFramework/StartupTask.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using dotnetCampus.ApplicationStartupManager;
+
+namespace WPFDemo.Api.StartupTaskFramework
+{
+ ///
+ /// 表示一个和当前业务强相关的启动任务
+ ///
+ public class StartupTask : StartupTaskBase
+ {
+ protected sealed override Task RunAsync(IStartupContext context)
+ {
+ return RunAsync((StartupContext) context);
+ }
+
+ protected virtual Task RunAsync(StartupContext context)
+ {
+ return CompletedTask;
+ }
+ }
+}
diff --git a/demo/WPFDemo/WPFDemo.Api/WPFDemo.Api.csproj b/demo/WPFDemo/WPFDemo.Api/WPFDemo.Api.csproj
new file mode 100644
index 0000000..8f375f9
--- /dev/null
+++ b/demo/WPFDemo/WPFDemo.Api/WPFDemo.Api.csproj
@@ -0,0 +1,20 @@
+
+
+
+ net6.0
+ enable
+ enable
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demo/WPFDemo/WPFDemo.App/App.xaml b/demo/WPFDemo/WPFDemo.App/App.xaml
new file mode 100644
index 0000000..97b0aec
--- /dev/null
+++ b/demo/WPFDemo/WPFDemo.App/App.xaml
@@ -0,0 +1,8 @@
+
+
+
+
+
diff --git a/demo/WPFDemo/WPFDemo.App/App.xaml.cs b/demo/WPFDemo/WPFDemo.App/App.xaml.cs
new file mode 100644
index 0000000..7ad2734
--- /dev/null
+++ b/demo/WPFDemo/WPFDemo.App/App.xaml.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Data;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows;
+
+namespace WPFDemo.App
+{
+ ///
+ /// Interaction logic for App.xaml
+ ///
+ public partial class App : Application
+ {
+ }
+}
diff --git a/demo/WPFDemo/WPFDemo.App/AssemblyInfo.cs b/demo/WPFDemo/WPFDemo.App/AssemblyInfo.cs
new file mode 100644
index 0000000..8b5504e
--- /dev/null
+++ b/demo/WPFDemo/WPFDemo.App/AssemblyInfo.cs
@@ -0,0 +1,10 @@
+using System.Windows;
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
diff --git a/demo/WPFDemo/WPFDemo.App/MainWindow.xaml b/demo/WPFDemo/WPFDemo.App/MainWindow.xaml
new file mode 100644
index 0000000..b71d7cc
--- /dev/null
+++ b/demo/WPFDemo/WPFDemo.App/MainWindow.xaml
@@ -0,0 +1,12 @@
+
+
+
+
+
diff --git a/demo/WPFDemo/WPFDemo.App/MainWindow.xaml.cs b/demo/WPFDemo/WPFDemo.App/MainWindow.xaml.cs
new file mode 100644
index 0000000..921bb55
--- /dev/null
+++ b/demo/WPFDemo/WPFDemo.App/MainWindow.xaml.cs
@@ -0,0 +1,26 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace WPFDemo.App
+{
+ ///
+ /// Interaction logic for MainWindow.xaml
+ ///
+ public partial class MainWindow : Window
+ {
+ public MainWindow()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/demo/WPFDemo/WPFDemo.App/Program.cs b/demo/WPFDemo/WPFDemo.App/Program.cs
new file mode 100644
index 0000000..ffcb547
--- /dev/null
+++ b/demo/WPFDemo/WPFDemo.App/Program.cs
@@ -0,0 +1,88 @@
+using System;
+using System.Diagnostics;
+using System.Reflection;
+using System.Threading.Tasks;
+
+using dotnetCampus.Cli;
+using dotnetCampus.Configurations.Core;
+
+using WPFDemo.Api.Startup;
+using WPFDemo.Api.StartupTaskFramework;
+using WPFDemo.App.StartupTaskFramework;
+using WPFDemo.Lib1.Startup;
+
+namespace WPFDemo.App
+{
+ class Program
+ {
+ [STAThread]
+ static void Main(string[] args)
+ {
+ var commandLine = CommandLine.Parse(args);
+
+ var app = new App();
+
+ //开始启动任务
+ StartStartupTasks(commandLine);
+
+ app.Run();
+ }
+
+ private static void StartStartupTasks(CommandLine commandLine)
+ {
+ Task.Run(() =>
+ {
+ // 获取应用配置文件逻辑
+ var configFilePath = "App.coin";
+ var repo = ConfigurationFactory.FromFile(configFilePath);
+
+ var assemblyMetadataExporter = new AssemblyMetadataExporter(BuildStartupAssemblies());
+
+ var startupManager = new StartupManager(commandLine, repo, HandleShutdownError, new MainThreadDispatcher())
+ .UseCriticalNodes
+ (
+ StartupNodes.Foundation,
+ StartupNodes.CoreUI,
+ StartupNodes.UI,
+ StartupNodes.AppReady,
+ StartupNodes.StartupCompleted
+ )
+ // 导出程序集的启动项
+ .AddStartupTaskMetadataCollector(() =>
+ assemblyMetadataExporter.ExportStartupTasks());
+ startupManager.Run();
+ });
+ }
+
+ private static Assembly[] BuildStartupAssemblies()
+ {
+ // 初始化预编译收集的所有模块。
+ return new Assembly[]
+ {
+ // WPFDemo.App
+ typeof(Program).Assembly,
+ // WPFDemo.Lib1
+ typeof(Foo2Startup).Assembly,
+ // WPFDemo.Api
+ typeof(Foo1Startup).Assembly,
+ };
+ }
+
+ private static Task HandleShutdownError(Exception ex)
+ {
+ // 这是启动过程的异常,需要进行退出
+
+#if DEBUG
+ Debug.WriteLine("========== [初始化过程中出现致命错误,详情请查看异常信息] ==========");
+ Debug.WriteLine(ex.ToString());
+
+ if (Debugger.IsAttached)
+ {
+ Debugger.Break();
+ }
+#endif
+
+ return Task.CompletedTask;
+ }
+ }
+}
diff --git a/demo/WPFDemo/WPFDemo.App/Properties/AssemblyInfo.cs b/demo/WPFDemo/WPFDemo.App/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..e44dfdc
--- /dev/null
+++ b/demo/WPFDemo/WPFDemo.App/Properties/AssemblyInfo.cs
@@ -0,0 +1,6 @@
+using dotnetCampus.ApplicationStartupManager;
+using dotnetCampus.Telescope;
+
+using WPFDemo.Api.StartupTaskFramework;
+
+[assembly: MarkExport(typeof(StartupTask), typeof(StartupTaskAttribute))]
diff --git a/demo/WPFDemo/WPFDemo.App/Properties/launchSettings.json b/demo/WPFDemo/WPFDemo.App/Properties/launchSettings.json
new file mode 100644
index 0000000..7ef3a56
--- /dev/null
+++ b/demo/WPFDemo/WPFDemo.App/Properties/launchSettings.json
@@ -0,0 +1,8 @@
+{
+ "profiles": {
+ "WPFDemo.App": {
+ "commandName": "Project",
+ "commandLineArgs": "-Name ApplicationStartupManager"
+ }
+ }
+}
\ No newline at end of file
diff --git a/demo/WPFDemo/WPFDemo.App/Startup/BusinessStartup.cs b/demo/WPFDemo/WPFDemo.App/Startup/BusinessStartup.cs
new file mode 100644
index 0000000..fad8408
--- /dev/null
+++ b/demo/WPFDemo/WPFDemo.App/Startup/BusinessStartup.cs
@@ -0,0 +1,28 @@
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using dotnetCampus.ApplicationStartupManager;
+using WPFDemo.Api.StartupTaskFramework;
+
+namespace WPFDemo.App.Startup
+{
+ [StartupTask(BeforeTasks = StartupNodes.AppReady, AfterTasks = "MainWindowStartup", Scheduler = StartupScheduler.UIOnly)]
+ internal class BusinessStartup : StartupTask
+ {
+ protected override Task RunAsync(StartupContext context)
+ {
+ if (Application.Current.MainWindow.Content is Grid grid)
+ {
+ grid.Children.Add(new Button()
+ {
+ HorizontalAlignment = HorizontalAlignment.Center,
+ VerticalAlignment = VerticalAlignment.Bottom,
+ Margin = new Thickness(10, 10, 10, 10),
+ Content = "Click"
+ });
+ }
+
+ return CompletedTask;
+ }
+ }
+}
diff --git a/demo/WPFDemo/WPFDemo.App/Startup/MainWindowStartup.cs b/demo/WPFDemo/WPFDemo.App/Startup/MainWindowStartup.cs
new file mode 100644
index 0000000..0981928
--- /dev/null
+++ b/demo/WPFDemo/WPFDemo.App/Startup/MainWindowStartup.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using dotnetCampus.ApplicationStartupManager;
+
+using WPFDemo.Api.StartupTaskFramework;
+
+namespace WPFDemo.App.Startup
+{
+ [StartupTask(BeforeTasks = StartupNodes.AppReady, AfterTasks = StartupNodes.UI, Scheduler = StartupScheduler.UIOnly)]
+ internal class MainWindowStartup : StartupTask
+ {
+ protected override Task RunAsync(StartupContext context)
+ {
+ var mainWindow = new MainWindow();
+ mainWindow.Show();
+
+ return CompletedTask;
+ }
+ }
+}
diff --git a/demo/WPFDemo/WPFDemo.App/StartupTaskFramework/MainThreadDispatcher.cs b/demo/WPFDemo/WPFDemo.App/StartupTaskFramework/MainThreadDispatcher.cs
new file mode 100644
index 0000000..13e731d
--- /dev/null
+++ b/demo/WPFDemo/WPFDemo.App/StartupTaskFramework/MainThreadDispatcher.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Threading.Tasks;
+using System.Windows;
+using dotnetCampus.ApplicationStartupManager;
+
+namespace WPFDemo.App.StartupTaskFramework
+{
+ // 因为没有在 WPFDemo.Api 引用 WPF 程序集,因此代码写在这里
+ class MainThreadDispatcher : IMainThreadDispatcher
+ {
+ public async Task InvokeAsync(Action action)
+ {
+ await Application.Current.Dispatcher.InvokeAsync(action);
+ }
+ }
+}
diff --git a/demo/WPFDemo/WPFDemo.App/WPFDemo.App.csproj b/demo/WPFDemo/WPFDemo.App/WPFDemo.App.csproj
new file mode 100644
index 0000000..6e0bd75
--- /dev/null
+++ b/demo/WPFDemo/WPFDemo.App/WPFDemo.App.csproj
@@ -0,0 +1,22 @@
+
+
+
+ WinExe
+ net6.0-windows
+ enable
+ true
+ WPFDemo.App.Program
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demo/WPFDemo/WPFDemo.Lib1/Properties/AssemblyInfo.cs b/demo/WPFDemo/WPFDemo.Lib1/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..e44dfdc
--- /dev/null
+++ b/demo/WPFDemo/WPFDemo.Lib1/Properties/AssemblyInfo.cs
@@ -0,0 +1,6 @@
+using dotnetCampus.ApplicationStartupManager;
+using dotnetCampus.Telescope;
+
+using WPFDemo.Api.StartupTaskFramework;
+
+[assembly: MarkExport(typeof(StartupTask), typeof(StartupTaskAttribute))]
diff --git a/demo/WPFDemo/WPFDemo.Lib1/Startup/Foo2Startup.cs b/demo/WPFDemo/WPFDemo.Lib1/Startup/Foo2Startup.cs
new file mode 100644
index 0000000..e60ad59
--- /dev/null
+++ b/demo/WPFDemo/WPFDemo.Lib1/Startup/Foo2Startup.cs
@@ -0,0 +1,16 @@
+using dotnetCampus.ApplicationStartupManager;
+
+using WPFDemo.Api.StartupTaskFramework;
+
+namespace WPFDemo.Lib1.Startup
+{
+ [StartupTask(BeforeTasks = StartupNodes.CoreUI, AfterTasks = StartupNodes.Foundation)]
+ public class Foo2Startup : StartupTask
+ {
+ protected override Task RunAsync(StartupContext context)
+ {
+ context.Logger.LogInfo("Foo2 Startup");
+ return base.RunAsync(context);
+ }
+ }
+}
diff --git a/demo/WPFDemo/WPFDemo.Lib1/Startup/Foo3Startup.cs b/demo/WPFDemo/WPFDemo.Lib1/Startup/Foo3Startup.cs
new file mode 100644
index 0000000..46f3822
--- /dev/null
+++ b/demo/WPFDemo/WPFDemo.Lib1/Startup/Foo3Startup.cs
@@ -0,0 +1,16 @@
+using dotnetCampus.ApplicationStartupManager;
+
+using WPFDemo.Api.StartupTaskFramework;
+
+namespace WPFDemo.Lib1.Startup
+{
+ [StartupTask(BeforeTasks = StartupNodes.CoreUI, AfterTaskList = new[] { nameof(WPFDemo.Lib1.Startup.Foo2Startup), "Foo1Startup" })]
+ public class Foo3Startup : StartupTask
+ {
+ protected override Task RunAsync(StartupContext context)
+ {
+ context.Logger.LogInfo("Foo3 Startup");
+ return base.RunAsync(context);
+ }
+ }
+}
diff --git a/demo/WPFDemo/WPFDemo.Lib1/Startup/LibStartup.cs b/demo/WPFDemo/WPFDemo.Lib1/Startup/LibStartup.cs
new file mode 100644
index 0000000..9dcf0db
--- /dev/null
+++ b/demo/WPFDemo/WPFDemo.Lib1/Startup/LibStartup.cs
@@ -0,0 +1,15 @@
+using dotnetCampus.ApplicationStartupManager;
+using WPFDemo.Api.StartupTaskFramework;
+
+namespace WPFDemo.Lib1.Startup
+{
+ [StartupTask(BeforeTasks = StartupNodes.Foundation)]
+ class LibStartup : StartupTask
+ {
+ protected override Task RunAsync(StartupContext context)
+ {
+ context.Logger.LogInfo("Lib Startup");
+ return base.RunAsync(context);
+ }
+ }
+}
diff --git a/demo/WPFDemo/WPFDemo.Lib1/WPFDemo.Lib1.csproj b/demo/WPFDemo/WPFDemo.Lib1/WPFDemo.Lib1.csproj
new file mode 100644
index 0000000..10bd6d9
--- /dev/null
+++ b/demo/WPFDemo/WPFDemo.Lib1/WPFDemo.Lib1.csproj
@@ -0,0 +1,17 @@
+
+
+
+ net6.0
+ enable
+ enable
+ false
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnetCampus.ApplicationStartupManager.sln b/dotnetCampus.ApplicationStartupManager.sln
index 163d9e4..7f14254 100644
--- a/dotnetCampus.ApplicationStartupManager.sln
+++ b/dotnetCampus.ApplicationStartupManager.sln
@@ -1,12 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.31605.320
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.32014.148
MinimumVisualStudioVersion = 15.0.26124.0
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{5D196596-756D-45C2-8A05-C8E4AB8A36E6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnetCampus.ApplicationStartupManager", "src\dotnetCampus.ApplicationStartupManager\dotnetCampus.ApplicationStartupManager.csproj", "{F7ED61F4-920C-49EB-8DC1-74B2BE6AF272}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "demo", "demo", "{A02845A0-C78A-407C-ACF2-529AE6600906}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WPFDemo.App", "demo\WPFDemo\WPFDemo.App\WPFDemo.App.csproj", "{32CDDF87-194D-4A6C-9DF5-B9D21A8F45AF}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WPFDemo.Api", "demo\WPFDemo\WPFDemo.Api\WPFDemo.Api.csproj", "{68AD8EB7-A9A1-4EA7-A419-9BA1F74ACA32}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WPFDemo.Lib1", "demo\WPFDemo\WPFDemo.Lib1\WPFDemo.Lib1.csproj", "{F4102A0A-E10A-462E-9AB1-0F80C83065D1}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -17,12 +25,27 @@ Global
{F7ED61F4-920C-49EB-8DC1-74B2BE6AF272}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F7ED61F4-920C-49EB-8DC1-74B2BE6AF272}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F7ED61F4-920C-49EB-8DC1-74B2BE6AF272}.Release|Any CPU.Build.0 = Release|Any CPU
+ {32CDDF87-194D-4A6C-9DF5-B9D21A8F45AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {32CDDF87-194D-4A6C-9DF5-B9D21A8F45AF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {32CDDF87-194D-4A6C-9DF5-B9D21A8F45AF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {32CDDF87-194D-4A6C-9DF5-B9D21A8F45AF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {68AD8EB7-A9A1-4EA7-A419-9BA1F74ACA32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {68AD8EB7-A9A1-4EA7-A419-9BA1F74ACA32}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {68AD8EB7-A9A1-4EA7-A419-9BA1F74ACA32}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {68AD8EB7-A9A1-4EA7-A419-9BA1F74ACA32}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F4102A0A-E10A-462E-9AB1-0F80C83065D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F4102A0A-E10A-462E-9AB1-0F80C83065D1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F4102A0A-E10A-462E-9AB1-0F80C83065D1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F4102A0A-E10A-462E-9AB1-0F80C83065D1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{F7ED61F4-920C-49EB-8DC1-74B2BE6AF272} = {5D196596-756D-45C2-8A05-C8E4AB8A36E6}
+ {32CDDF87-194D-4A6C-9DF5-B9D21A8F45AF} = {A02845A0-C78A-407C-ACF2-529AE6600906}
+ {68AD8EB7-A9A1-4EA7-A419-9BA1F74ACA32} = {A02845A0-C78A-407C-ACF2-529AE6600906}
+ {F4102A0A-E10A-462E-9AB1-0F80C83065D1} = {A02845A0-C78A-407C-ACF2-529AE6600906}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8AAD3A7E-EBB6-4125-9048-4CDE053D079B}
diff --git a/src/dotnetCampus.ApplicationStartupManager/StartupManagerBase.cs b/src/dotnetCampus.ApplicationStartupManager/StartupManagerBase.cs
index 9bf4996..82a00b2 100644
--- a/src/dotnetCampus.ApplicationStartupManager/StartupManagerBase.cs
+++ b/src/dotnetCampus.ApplicationStartupManager/StartupManagerBase.cs
@@ -444,9 +444,9 @@ namespace dotnetCampus.ApplicationStartupManager
private static string StartupTypeToKey(Type type)
=> type.Name.Remove(type.Name.Length - "startup".Length);
- internal virtual Task ExecuteStartupTaskAsync(StartupTaskBase startupTask, IStartupContext context, bool uiOnly)
+ protected internal virtual Task ExecuteStartupTaskAsync(StartupTaskBase startupTask, IStartupContext context, bool uiOnly)
{
return startupTask.JoinAsync(context, uiOnly);
}
}
-}
\ No newline at end of file
+}