diff --git a/src/dotnetCampus.ApplicationStartupManager/IStartupContext.cs b/src/dotnetCampus.ApplicationStartupManager/IStartupContext.cs index 60978b3..71e79e6 100644 --- a/src/dotnetCampus.ApplicationStartupManager/IStartupContext.cs +++ b/src/dotnetCampus.ApplicationStartupManager/IStartupContext.cs @@ -1,12 +1,18 @@ using System.Threading.Tasks; -//using dotnetCampus.Configurations; namespace dotnetCampus.ApplicationStartupManager { + /// + /// 表示启动任务的上下文接口 + /// public interface IStartupContext { - //IAppConfigurator Configs { get; } - //Task ReadCacheAsync(string key, string @default = ""); + /// + /// 等待某个启动任务完成 + /// + /// + /// + /// 这是框架层需要支持的能力,因此也就放在此 Task WaitStartupTaskAsync(string startupKey); } } diff --git a/src/dotnetCampus.ApplicationStartupManager/IStartupLogger.cs b/src/dotnetCampus.ApplicationStartupManager/IStartupLogger.cs index cb1ef2d..e06d317 100644 --- a/src/dotnetCampus.ApplicationStartupManager/IStartupLogger.cs +++ b/src/dotnetCampus.ApplicationStartupManager/IStartupLogger.cs @@ -4,10 +4,27 @@ using System.Threading.Tasks; namespace dotnetCampus.ApplicationStartupManager { + /// + /// 启动模块的日志 + /// public interface IStartupLogger { + /// + /// 打点某个里程碑,将会自动与上个里程碑记录时间差 + /// + /// void RecordTime(string milestoneName); + /// + /// 记录某个任务的耗时情况 + /// + /// + /// + /// Task RecordDuration(string taskName, Func> task); + /// + /// 上报启动结果 + /// + /// void ReportResult(IReadOnlyList wrappers); } } diff --git a/src/dotnetCampus.ApplicationStartupManager/IStartupManager.cs b/src/dotnetCampus.ApplicationStartupManager/IStartupManager.cs index d6e4c09..8f92364 100644 --- a/src/dotnetCampus.ApplicationStartupManager/IStartupManager.cs +++ b/src/dotnetCampus.ApplicationStartupManager/IStartupManager.cs @@ -2,10 +2,24 @@ namespace dotnetCampus.ApplicationStartupManager { + /// + /// 启动流程管理器 + /// public interface IStartupManager { + /// + /// 等待某个启动项的完成 + /// + /// + /// Task WaitStartupTaskAsync(string startupTaskKey); + /// + /// 获取指定类型的启动项 + /// + /// + /// + /// 理论上相同的类型的启动项不会被重复加入,基本都是一个启动项一个类型 StartupTaskBase GetStartupTask() where T : StartupTaskBase; } } diff --git a/src/dotnetCampus.ApplicationStartupManager/IStartupTaskWrapper.cs b/src/dotnetCampus.ApplicationStartupManager/IStartupTaskWrapper.cs index 36d68a4..56f9e10 100644 --- a/src/dotnetCampus.ApplicationStartupManager/IStartupTaskWrapper.cs +++ b/src/dotnetCampus.ApplicationStartupManager/IStartupTaskWrapper.cs @@ -2,11 +2,26 @@ namespace dotnetCampus.ApplicationStartupManager { + /// + /// 启动项在启动框架的信息 + /// public interface IStartupTaskWrapper { + /// + /// 跟随等待着当前启动项的其他启动项 + /// HashSet FollowTasks { get; } + /// + /// 当前启动项所依赖的其他启动项 + /// HashSet Dependencies { get; } + /// + /// 当前启动项的标识 + /// string StartupTaskKey { get; } + /// + /// 表示当前启动项是否只能在 UI 线程启动 + /// bool UIOnly { get; } } } diff --git a/src/dotnetCampus.ApplicationStartupManager/IStartupValueProvider.cs b/src/dotnetCampus.ApplicationStartupManager/IStartupValueProvider.cs index 920c2f4..a59c7f2 100644 --- a/src/dotnetCampus.ApplicationStartupManager/IStartupValueProvider.cs +++ b/src/dotnetCampus.ApplicationStartupManager/IStartupValueProvider.cs @@ -1,7 +1,15 @@ namespace dotnetCampus.ApplicationStartupManager { + /// + /// 用于启动项里的值提供器,用于多个启动项之间传递参数 + /// + /// public interface IStartupValueProvider { + /// + /// 获取启动项提供的值 + /// + /// T ProvideValue(); } } diff --git a/src/dotnetCampus.ApplicationStartupManager/NullObjectStartup.cs b/src/dotnetCampus.ApplicationStartupManager/NullObjectStartup.cs index f9d4409..70ec3c2 100644 --- a/src/dotnetCampus.ApplicationStartupManager/NullObjectStartup.cs +++ b/src/dotnetCampus.ApplicationStartupManager/NullObjectStartup.cs @@ -1,5 +1,8 @@ namespace dotnetCampus.ApplicationStartupManager { + /// + /// 一个表示空白的启动项 + /// internal sealed class NullObjectStartup : StartupTaskBase { diff --git a/src/dotnetCampus.ApplicationStartupManager/StartupContext.cs b/src/dotnetCampus.ApplicationStartupManager/StartupContext.cs index 50da798..1faea1f 100644 --- a/src/dotnetCampus.ApplicationStartupManager/StartupContext.cs +++ b/src/dotnetCampus.ApplicationStartupManager/StartupContext.cs @@ -1,36 +1,26 @@ using System; using System.Threading.Tasks; -//using dotnetCampus.Configurations; -//using dotnetCampus.Configurations.Core; namespace dotnetCampus.ApplicationStartupManager { + /// + /// 启动项的上下文信息,业务方可以自己再定义而不需要使用此类型 + /// internal class StartupContext : IStartupContext { public IStartupLogger Logger { get; } - //public FileConfigurationRepo Configuration { get; } - - //public IAppConfigurator Configs { get; } - public Func FastFail { get; } private readonly Func _waitStartupTaskAsync; - //public Task ReadCacheAsync(string key, string @default = "") - //{ - // return Configuration.TryReadAsync(key, @default); - //} - Task IStartupContext.WaitStartupTaskAsync(string startupKey) => _waitStartupTaskAsync(startupKey); public StartupContext(IStartupLogger logger, /*FileConfigurationRepo configuration,*/ Func fastFailAction, Func waitStartupAsync) { Logger = logger; - //Configuration = configuration; _waitStartupTaskAsync = waitStartupAsync; - //Configs = configuration.CreateAppConfigurator(); FastFail = fastFailAction ?? (exception => StartupTaskBase.CompletedTask); } } diff --git a/src/dotnetCampus.ApplicationStartupManager/StartupLogger.cs b/src/dotnetCampus.ApplicationStartupManager/StartupLogger.cs index 5ca1d36..8c69d2c 100644 --- a/src/dotnetCampus.ApplicationStartupManager/StartupLogger.cs +++ b/src/dotnetCampus.ApplicationStartupManager/StartupLogger.cs @@ -9,20 +9,36 @@ using System.Threading.Tasks; namespace dotnetCampus.ApplicationStartupManager { + /// + /// 表示启动任务的基础日志,推荐业务方提供更贴合业务的日志,和日志记录的方法 + /// public class StartupLoggerBase : IStartupLogger { private readonly Stopwatch _mainWatch; + /// + /// 各个启动的里程碑的信息,包括里程碑的所运行的线程名,启动时间和执行时间 + /// + /// Key: 启动的里程碑名 + /// + /// + /// Value: 启动的信息,包括里程碑的所运行的线程名,启动时间和执行时间。时间都是从 获取 + /// + /// protected ConcurrentDictionary MilestoneDictionary { get; } = new ConcurrentDictionary(); + /// + /// 创建启动任务的基础日志,此日志的核心功能就是监控启动项的启动时间 + /// public StartupLoggerBase() { _mainWatch = new Stopwatch(); _mainWatch.Start(); } + /// public void RecordTime(string milestoneName) { var start = MilestoneDictionary.Count > 0 @@ -34,6 +50,7 @@ namespace dotnetCampus.ApplicationStartupManager start, end - start); } + /// public async Task RecordDuration(string taskName, Func> task) { var threadName = "null"; @@ -51,8 +68,10 @@ namespace dotnetCampus.ApplicationStartupManager } } + /// public virtual void ReportResult(IReadOnlyList wrappers) { + // 没有实际的可以记录的地方,需要业务方自己实现记录到哪 } } } diff --git a/src/dotnetCampus.ApplicationStartupManager/StartupManagerBase.cs b/src/dotnetCampus.ApplicationStartupManager/StartupManagerBase.cs index 1b40517..70c4043 100644 --- a/src/dotnetCampus.ApplicationStartupManager/StartupManagerBase.cs +++ b/src/dotnetCampus.ApplicationStartupManager/StartupManagerBase.cs @@ -9,15 +9,16 @@ using System.Threading.Tasks; namespace dotnetCampus.ApplicationStartupManager { + /// + /// 启动任务管理器,这是此框架的入口 + /// + /// 期望业务方自己再基于此类型继续实现自己的业务逻辑,例如注入业务方需要的日志模块,以及构建启动任务上下文 + /// + /// public class StartupManagerBase : IStartupManager { private readonly IMainThreadDispatcher _dispatcher; - ///// - ///// Builder 模式所需状态:包含当前剩余需要管理的启动任务程序集。 - ///// - //private readonly List _assembliesToBeManaged = new List(); - /// /// Builder 模式所需状态:包含当前所有的关键启动任务。 /// @@ -42,10 +43,25 @@ namespace dotnetCampus.ApplicationStartupManager private List? Graph { get; set; } private StartupContext Context { get; } + + /// + /// 获取启动任务上下文信息 + /// protected IStartupContext StartupContext => Context; + /// + /// 获取启动任务日志 + /// protected IStartupLogger Logger => Context.Logger; + /// + /// 创建启动任务管理器 + /// + /// 启动项的日志记录器 + /// 启动过程存在失败时需要执行的逻辑,也就是说此委托被框架执行时,将应该记录失败然后退出应用 + /// 传入线程调度器,需要业务方自己实现 + /// 是否需要在进入启动框架时,让框架设置线程池的线程数 + /// public StartupManagerBase(IStartupLogger logger, /*FileConfigurationRepo configurationRepo,*/ Func fastFailAction, IMainThreadDispatcher dispatcher, bool shouldSetThreadPool = true) { @@ -213,12 +229,20 @@ namespace dotnetCampus.ApplicationStartupManager // return this; //} + /// + /// 加入构建预设启动项 + /// + /// + /// public StartupManagerBase ForStartupTasksOfCategory(Action taskBuilder) { _additionalBuilders.Add(taskBuilder); return this; } + /// + /// 启动框架,开始执行应用程序的启动流程 + /// public async void Run() { if (Graph == null) @@ -352,6 +376,10 @@ namespace dotnetCampus.ApplicationStartupManager } } + /// + /// 导出所有的启动任务项,可以给子类继承,用于让子类定制获取启动任务项的方法 + /// + /// protected virtual IEnumerable ExportStartupTasks() { foreach (var func in _startupTaskMetadataCollectorList) @@ -444,6 +472,7 @@ namespace dotnetCampus.ApplicationStartupManager throw new InvalidOperationException($"{startupTaskKey}既无法添加至字典,也无法从字典获取对应值"); } + /// public Task WaitStartupTaskAsync(string startupTaskKey) => GetStartupTaskWrapper(startupTaskKey).TaskBase.TaskResult; @@ -453,6 +482,13 @@ namespace dotnetCampus.ApplicationStartupManager private static string StartupTypeToKey(Type type) => type.Name.Remove(type.Name.Length - "startup".Length); + /// + /// 实际执行某个具体的启动任务项的函数,可以给子类继承,用来控制具体的启动任务项执行逻辑 + /// + /// + /// + /// + /// protected internal virtual Task ExecuteStartupTaskAsync(StartupTaskBase startupTask, IStartupContext context, bool uiOnly) { return startupTask.JoinAsync(context, uiOnly); diff --git a/src/dotnetCampus.ApplicationStartupManager/StartupTaskAttribute.cs b/src/dotnetCampus.ApplicationStartupManager/StartupTaskAttribute.cs index cd17dac..3c61633 100644 --- a/src/dotnetCampus.ApplicationStartupManager/StartupTaskAttribute.cs +++ b/src/dotnetCampus.ApplicationStartupManager/StartupTaskAttribute.cs @@ -1,8 +1,10 @@ using System; -using System.Diagnostics.CodeAnalysis; namespace dotnetCampus.ApplicationStartupManager { + /// + /// 启动任务的特性,可以让业务方用来对接,如对接预编译框架,从而收集启动任务项 + /// [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] public sealed class StartupTaskAttribute : Attribute { diff --git a/src/dotnetCampus.ApplicationStartupManager/StartupTaskBase.cs b/src/dotnetCampus.ApplicationStartupManager/StartupTaskBase.cs index bb642e7..923a9d4 100644 --- a/src/dotnetCampus.ApplicationStartupManager/StartupTaskBase.cs +++ b/src/dotnetCampus.ApplicationStartupManager/StartupTaskBase.cs @@ -4,10 +4,22 @@ using System.Threading.Tasks; namespace dotnetCampus.ApplicationStartupManager { + /// + /// 启动任务项的基类型 + /// public abstract class StartupTaskBase { - // 由于我们都在编译期间收集 Attribute 了,当然也能收集使用方到底重写了哪个 Run。 - // 这里传入的 isUIOnly 就是编译期间收集的那个属性。 + /// + /// 将当前启动任务项加入执行 + /// + /// + /// 此函数由启动框架调用 + /// + /// + /// + /// + /// 由于我们都在编译期间收集 Attribute 了,当然也能收集使用方到底重写了哪个 Run。 + /// 这里传入的 isUIOnly 就是编译期间收集的那个属性。 public async Task JoinAsync(IStartupContext context, bool isUIOnly) { // 决定执行 Run 还是 RunAsync。 @@ -44,11 +56,19 @@ namespace dotnetCampus.ApplicationStartupManager } } + /// + /// 启动任务项的实际执行逻辑,由子类继承,实现启动任务项业务逻辑 + /// + /// + /// protected virtual Task RunAsync(IStartupContext context) { return CompletedTask; } + /// + /// 一个表示执行完成的任务,可以在 作为返回值 + /// protected internal static Task CompletedTask => #if NETFRAMEWORK CompletedCommonTask; @@ -59,6 +79,9 @@ namespace dotnetCampus.ApplicationStartupManager Task.CompletedTask; #endif + /// + /// 获取当前启动任务项可等待任务 + /// public Task TaskResult => CompletedSource.Task; private TaskCompletionSource CompletedSource { get; } = new TaskCompletionSource(); @@ -67,6 +90,12 @@ namespace dotnetCampus.ApplicationStartupManager // 框架注入,一定不为空 = null!; + /// + /// 获取某个指定传入的启动任务项的提供的参数 + /// + /// 提供参数的启动任务项 + /// 参数 + /// protected TValue FetchValue() where TStartup : StartupTaskBase, IStartupValueProvider { var task = Manager.GetStartupTask(); diff --git a/src/dotnetCampus.ApplicationStartupManager/StartupTaskBuilder.cs b/src/dotnetCampus.ApplicationStartupManager/StartupTaskBuilder.cs index 7262535..91f25be 100644 --- a/src/dotnetCampus.ApplicationStartupManager/StartupTaskBuilder.cs +++ b/src/dotnetCampus.ApplicationStartupManager/StartupTaskBuilder.cs @@ -2,6 +2,9 @@ namespace dotnetCampus.ApplicationStartupManager { + /// + /// 启动流程任务创建器 + /// public class StartupTaskBuilder { private readonly StartupTaskWrapper _wrapper; @@ -17,18 +20,31 @@ namespace dotnetCampus.ApplicationStartupManager _addFollowTasksAction = addFollowTasksAction; } + /// + /// 设置或获取启动流程的分类 + /// public StartupCategory Categories { get => _wrapper.Categories; set => _wrapper.Categories = value; } + /// + /// 加上依赖的启动任务项 + /// + /// + /// public StartupTaskBuilder AddDependencies(string afterTasks) { _addDependenciesAction(_wrapper, afterTasks); return this; } + /// + /// 加上跟随当前启动任务项的启动任务项 + /// + /// + /// public StartupTaskBuilder AddFollowTasks(string beforeTasks) { _addFollowTasksAction(_wrapper, beforeTasks); diff --git a/src/dotnetCampus.ApplicationStartupManager/dotnetCampus.ApplicationStartupManager.csproj b/src/dotnetCampus.ApplicationStartupManager/dotnetCampus.ApplicationStartupManager.csproj index d579113..52be5d1 100644 --- a/src/dotnetCampus.ApplicationStartupManager/dotnetCampus.ApplicationStartupManager.csproj +++ b/src/dotnetCampus.ApplicationStartupManager/dotnetCampus.ApplicationStartupManager.csproj @@ -1,10 +1,10 @@ - + - netcoreapp3.1;netstandard2.0;net45;net5.0 + netcoreapp3.1;netstandard2.0;net45;net5.0;net6.0 true - + true enable