@elf-express/admin-net-mcp 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/dist/index.js +83 -88
  2. package/knowledge/Furion_Teaching_Manual/04-1-/351/205/215/347/275/256.md +442 -0
  3. package/knowledge/Furion_Teaching_Manual/04-2-/351/201/270/351/240/205.md +363 -0
  4. package/knowledge/Furion_Teaching_Manual/05-1-/345/213/225/346/205/213WebAPI.md +825 -0
  5. package/knowledge/Furion_Teaching_Manual/05-2-HttpContext.md +217 -0
  6. package/knowledge/Furion_Teaching_Manual/05-3-/347/257/251/351/201/270/345/231/250/346/224/224/346/210/252/345/231/250AOP.md +581 -0
  7. package/knowledge/Furion_Teaching_Manual/05-4-/350/253/213/346/261/202/347/250/275/346/240/270/346/227/245/350/252/214.md +129 -0
  8. package/knowledge/Furion_Teaching_Manual/05-5-/344/270/255/344/273/213/350/273/237/351/253/224Middleware.md +328 -0
  9. package/knowledge/Furion_Teaching_Manual/05-6-Vue-React-Angular/344/273/213/351/235/242/344/273/243/347/220/206.md +317 -0
  10. package/knowledge/Furion_Teaching_Manual/06-1/350/246/217/347/257/204/345/214/226/346/216/245/345/217/243.md +1458 -0
  11. package/knowledge/Furion_Teaching_Manual/06-2/347/254/254/344/270/211/346/226/271API_Scalar.md +91 -0
  12. package/knowledge/Furion_Teaching_Manual/07-/345/217/213/345/245/275/344/276/213/345/244/226/350/231/225/347/220/206.md +511 -0
  13. package/knowledge/Furion_Teaching_Manual/08-1-/350/263/207/346/226/231/351/251/227/350/255/211/345/237/272/347/244/216/344/275/277/347/224/250.md +587 -0
  14. package/knowledge/Furion_Teaching_Manual/10-1-SqlSugar/346/225/264/345/220/210.md +336 -0
  15. package/knowledge/Furion_Teaching_Manual/11-SaaS /345/244/232/347/247/237/346/210/266/347/255/206/350/250/230.md" +271 -0
  16. package/knowledge/Furion_Teaching_Manual/12-furion-dependency-injection.md +408 -0
  17. package/knowledge/Furion_Teaching_Manual/13-/347/211/251/344/273/266/350/263/207/346/226/231/346/230/240/345/260/204/357/274/210Mapster/357/274/211.md +162 -0
  18. package/knowledge/Furion_Teaching_Manual/14-/345/210/206/345/270/203/345/274/217/347/274/223/345/255/230.md +311 -0
  19. package/knowledge/Furion_Teaching_Manual/15-/345/256/211/345/205/250/351/211/264/346/235/203.md +832 -0
  20. package/knowledge/Furion_Teaching_Manual/17-/346/252/242/350/246/226/347/257/204/346/234/254/345/274/225/346/223/216.md +327 -0
  21. package/knowledge/Furion_Teaching_Manual/18-/346/227/245/350/252/214/350/250/230/351/214/204.md +639 -0
  22. package/knowledge/Furion_Teaching_Manual/19-1-HTTP/351/201/240/347/253/257/350/253/213/346/261/202/345/237/272/347/244/216/344/275/277/347/224/250.md +621 -0
  23. package/knowledge/Furion_Teaching_Manual/19-2-HTTP/351/201/240/347/253/257/350/253/213/346/261/202/351/200/262/351/232/216/346/214/207/345/215/227.md +928 -0
  24. package/knowledge/Furion_Teaching_Manual/19-3-HTTP/351/201/240/347/253/257/350/253/213/346/261/202/345/270/270/350/246/213/345/225/217/351/241/214.md +362 -0
  25. package/knowledge/Furion_Teaching_Manual/20-/350/263/207/346/226/231/345/212/240/350/247/243/345/257/206.md +286 -0
  26. package/knowledge/Furion_Teaching_Manual/20-/351/231/204/351/214/204-KSort/350/263/207/346/226/231/347/260/275/345/220/215/345/256/214/346/225/264/345/216/237/345/247/213/347/242/274.md +305 -0
  27. package/knowledge/Furion_Teaching_Manual/21-/345/205/250/347/220/203/345/214/226/345/222/214/346/234/254/345/234/260/345/214/226.md +342 -0
  28. package/knowledge/Furion_Teaching_Manual/22-/344/272/213/344/273/266/345/214/257/346/265/201/346/216/222EventBus.md +448 -0
  29. package/knowledge/Furion_Teaching_Manual/23-JSON/345/272/217/345/210/227/345/214/226.md +340 -0
  30. package/knowledge/Furion_Teaching_Manual/24-/345/215/263/346/231/202/351/200/232/350/250/212SignalR.md +247 -0
  31. package/knowledge/Furion_Teaching_Manual/25-/350/274/224/345/212/251/350/247/222/350/211/262/346/234/215/345/213/231WorkerService.md +295 -0
  32. package/knowledge/Furion_Teaching_Manual/26-1-/346/216/222/347/250/213/344/275/234/346/245/255/345/256/232/346/231/202/344/273/273/345/213/231.md +631 -0
  33. package/knowledge/Furion_Teaching_Manual/26-2-Cron/350/241/250/351/201/224/345/274/217.md +203 -0
  34. package/knowledge/Furion_Teaching_Manual/26-3-/344/273/273/345/213/231/344/275/207/345/210/227TaskQueue.md +215 -0
  35. package/knowledge/Furion_Teaching_Manual/27-/345/210/206/346/225/243/345/274/217ID/347/224/237/346/210/220.md +86 -0
  36. package/knowledge/Furion_Teaching_Manual/28-/346/250/241/347/265/204/345/214/226/351/226/213/347/231/274.md +68 -0
  37. package/knowledge/Furion_Teaching_Manual/29-/346/265/201/350/256/212/347/211/251/344/273/266Clay.md +313 -0
  38. package/knowledge/Furion_Teaching_Manual/30-/350/204/253/346/225/217/350/231/225/347/220/206/357/274/210Sensitive Detection).md" +168 -0
  39. package/knowledge/Furion_Teaching_Manual/32-/346/234/203/350/251/261/345/222/214/347/213/200/346/205/213/347/256/241/347/220/206.md +147 -0
  40. package/knowledge/Furion_Teaching_Manual/33-IPC/347/250/213/345/272/217/351/200/232/350/250/212.md +98 -0
  41. package/knowledge/Furion_Teaching_Manual/34-2-Docker/351/203/250/347/275/262.md +313 -0
  42. package/knowledge/Furion_Teaching_Manual/34-3-Nginx/351/203/250/347/275/262.md +157 -0
  43. package/knowledge/Furion_Teaching_Manual/34-8-WindowsService/351/203/250/347/275/262.md +112 -0
  44. package/knowledge/Furion_Teaching_Manual/35-1-Docker/347/222/260/345/242/203/346/214/201/347/272/214/351/203/250/347/275/262Jenkins.md +169 -0
  45. package/knowledge/Furion_Teaching_Manual/36-1-/345/226/256/345/205/203/346/270/254/350/251/246/346/225/264/345/220/210/346/270/254/350/251/246.md +275 -0
  46. package/knowledge/Furion_Teaching_Manual/36-3-/345/237/272/346/272/226/346/270/254/350/251/246Benchmarking.md +80 -0
  47. package/knowledge/attributes.md +153 -0
  48. package/knowledge/config.md +147 -0
  49. package/knowledge/entity.md +115 -0
  50. package/knowledge/event.md +124 -0
  51. package/knowledge/plugin.md +136 -0
  52. package/knowledge/service.md +146 -0
  53. package/knowledge/sqlsugar.md +172 -0
  54. package/knowledge/vue-typescript.md +338 -0
  55. package/package.json +3 -2
@@ -0,0 +1,203 @@
1
+ # 26.2 Cron 表達式
2
+
3
+ > **版本說明**:Furion 4.8.0+ 採用 TimeCrontab 作為 Cron 表達式解析。非 Furion 框架可安裝 `TimeCrontab` 套件。
4
+
5
+ ---
6
+
7
+ ## 26.2.1 概述
8
+
9
+ Cron 表達式是由 5~7 個域組成的字串,每個域代表一個時間單位,是定時任務排程的核心基礎。
10
+
11
+ ---
12
+
13
+ ## 26.2.2 快速入門
14
+
15
+ ### 四種格式
16
+
17
+ ```csharp
18
+ // 常規:分 時 天 月 周
19
+ var crontab = Crontab.Parse("* * * * *");
20
+
21
+ // 含年份:分 時 天 月 周 年
22
+ var crontab = Crontab.Parse("* * * * * *", CronStringFormat.WithYears);
23
+
24
+ // 含秒數:秒 分 時 天 月 周
25
+ var crontab = Crontab.Parse("* * * * * *", CronStringFormat.WithSeconds);
26
+
27
+ // 含秒和年:秒 分 時 天 月 周 年
28
+ var crontab = Crontab.Parse("* * * * * * *", CronStringFormat.WithSecondsAndYears);
29
+
30
+ // 取得下一個/上一個發生時間
31
+ var next = crontab.GetNextOccurrence(DateTime.Now);
32
+ var prev = crontab.GetPreviousOccurrence(DateTime.Now); // 4.9.7.6+
33
+ ```
34
+
35
+ ### Macro 標識符與靜態屬性
36
+
37
+ ```csharp
38
+ // 字串方式
39
+ var secondly = Crontab.Parse("@secondly"); // 每秒
40
+ var minutely = Crontab.Parse("@minutely"); // 每分鐘
41
+ var hourly = Crontab.Parse("@hourly"); // 每小時
42
+ var daily = Crontab.Parse("@daily"); // 每天 00:00:00
43
+ var monthly = Crontab.Parse("@monthly"); // 每月 1 號
44
+ var weekly = Crontab.Parse("@weekly"); // 每週日
45
+ var yearly = Crontab.Parse("@yearly"); // 每年 1/1
46
+ var workday = Crontab.Parse("@workday"); // 週一至週五
47
+
48
+ // 靜態屬性方式
49
+ var secondly = Crontab.Secondly;
50
+ var minutely = Crontab.Minutely;
51
+ // ... 同上
52
+ ```
53
+
54
+ ### Macro At 標識符
55
+
56
+ ```csharp
57
+ Crontab.SecondlyAt(3, 5, 6); // 每第 3、5、6 秒
58
+ Crontab.MinutelyAt(3); // 每分鐘第 3 秒
59
+ Crontab.HourlyAt(3, 5, 6); // 每小時第 3、5、6 分鐘
60
+ Crontab.DailyAt(3); // 每天第 3 小時
61
+ Crontab.MonthlyAt(3, 5, 6); // 每月第 3、5、6 天
62
+ Crontab.WeeklyAt(3, "FRI", 6); // 每週星期 3、五、6(支援混合)
63
+ Crontab.YearlyAt(3, "MAY", 6); // 每年第 3、五、6 月
64
+ ```
65
+
66
+ > 星期縮寫:`SUN`、`MON`、`TUE`、`WED`、`THU`、`FRI`、`SAT`
67
+ > 月份縮寫:`JAN`~`DEC`
68
+
69
+ ### R 隨機時刻(4.9.6.17+)
70
+
71
+ ```csharp
72
+ // 每天 00:00 的隨機秒數觸發
73
+ var crontab = Crontab.Parse("R 0 0 * * ? *", CronStringFormat.WithSecondsAndYears);
74
+ ```
75
+
76
+ ---
77
+
78
+ ## 26.2.3 各欄位說明
79
+
80
+ | 欄位 | 允許值 | 特殊符號 | 格式化要求 |
81
+ |------|--------|----------|-----------|
82
+ | 秒 | 0-59 | `*` `,` `-` `/` `R` | WithSeconds / WithSecondsAndYears |
83
+ | 分鐘 | 0-59 | `*` `,` `-` `/` `R` | ALL |
84
+ | 小時 | 0-23 | `*` `,` `-` `/` `R` | ALL |
85
+ | 天 | 1-31 | `*` `,` `-` `/` `?` `L` `W` | ALL |
86
+ | 月份 | 1-12 / JAN-DEC | `*` `,` `-` `/` | ALL |
87
+ | 星期 | 0-6 / SUN-SAT | `*` `,` `-` `/` `?` `L` `#` | ALL |
88
+ | 年份 | 0001-9999 | `*` `,` `-` `/` | WithYears / WithSecondsAndYears |
89
+
90
+ ### 特殊符號說明
91
+
92
+ | 符號 | 說明 |
93
+ |------|------|
94
+ | `*` | 匹配任意值 |
95
+ | `?` | 僅用於「天」和「星期」,避免兩者衝突 |
96
+ | `-` | 範圍,如 `5-20` 表示 5 到 20 |
97
+ | `/` | 步進,如 `5/20` 表示從 5 開始每隔 20 |
98
+ | `,` | 列舉,如 `5,20` |
99
+ | `L` | 最後,如星期域 `5L` = 最後一個星期四 |
100
+ | `W` | 最近工作日,如 `5W` = 離 5 號最近的工作日 |
101
+ | `LW` | 某月最後一個工作日 |
102
+ | `#` | 第幾個星期幾,如 `2#3` = 第三個星期二 |
103
+ | `R` | 隨機時刻(4.9.6.17+) |
104
+
105
+ ---
106
+
107
+ ## 26.2.4 CronStringFormat 格式化
108
+
109
+ | 格式 | 書寫順序 |
110
+ |------|---------|
111
+ | `Default` | 分 時 天 月 周 |
112
+ | `WithYears` | 分 時 天 月 周 年 |
113
+ | `WithSeconds` | 秒 分 時 天 月 周 |
114
+ | `WithSecondsAndYears` | 秒 分 時 天 月 周 年 |
115
+
116
+ ---
117
+
118
+ ## 26.2.6 實現簡單定時任務
119
+
120
+ ### while + Task 方式
121
+
122
+ ```csharp
123
+ var crontab = Crontab.Parse("* * * * * *", CronStringFormat.WithSeconds);
124
+
125
+ // 無阻塞方式
126
+ Task.Factory.StartNew(async () =>
127
+ {
128
+ while (true)
129
+ {
130
+ await Task.Delay(crontab.GetSleepTimeSpan(DateTime.Now));
131
+ Console.WriteLine(DateTime.Now.ToString("G"));
132
+ }
133
+ }, TaskCreationOptions.LongRunning);
134
+ ```
135
+
136
+ ### BackgroundService 方式
137
+
138
+ ```csharp
139
+ public class Worker : BackgroundService
140
+ {
141
+ private readonly Crontab _crontab;
142
+
143
+ public Worker(ILogger<Worker> logger)
144
+ {
145
+ _crontab = Crontab.Parse("* * * * * *", CronStringFormat.WithSeconds);
146
+ }
147
+
148
+ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
149
+ {
150
+ while (!stoppingToken.IsCancellationRequested)
151
+ {
152
+ var taskFactory = new TaskFactory(TaskScheduler.Current);
153
+ await taskFactory.StartNew(async () =>
154
+ {
155
+ // 業務程式碼
156
+ await Task.CompletedTask;
157
+ }, stoppingToken);
158
+
159
+ await Task.Delay(_crontab.GetSleepTimeSpan(DateTime.Now), stoppingToken);
160
+ }
161
+ }
162
+ }
163
+ ```
164
+
165
+ > 建議使用 **26.1 排程作業** 實現強大的分散式定時任務。
166
+
167
+ ---
168
+
169
+ ## 26.2.7 Crontab 物件 API 速查
170
+
171
+ ### 實例方法
172
+
173
+ | 方法 | 說明 |
174
+ |------|------|
175
+ | `GetNextOccurrence(startTime)` | 下一個執行時間 |
176
+ | `GetNextOccurrence(startTime, endTime)` | 指定範圍內下一個時間 |
177
+ | `GetNextOccurrences(startTime, endTime)` | 指定範圍內所有執行時間 |
178
+ | `GetPreviousOccurrence(startTime)` | 上一個執行時間(4.9.7.6+) |
179
+ | `GetPreviousOccurrences(startTime, endTime)` | 指定範圍內所有過去時間(4.9.7.6+) |
180
+ | `GetSleepMilliseconds(baseTime)` | 距下次觸發的毫秒數 |
181
+ | `GetSleepTimeSpan(baseTime)` | 距下次觸發的 TimeSpan(4.8.4.10+) |
182
+ | `ToString()` | 轉換為 Cron 表達式字串 |
183
+
184
+ ### 靜態方法
185
+
186
+ | 方法 | 說明 |
187
+ |------|------|
188
+ | `Parse(expr, format)` | 解析表達式 |
189
+ | `TryParse(expr, format)` | 嘗試解析(不拋例外) |
190
+ | `ParseAt(macro, params)` | 建立 Macro At 物件 |
191
+ | `IsValid(expr, format)` | 判斷是否有效(4.8.7.17+) |
192
+ | `SecondlyAt(...)` / `MinutelyAt(...)` / `HourlyAt(...)` | 秒/分/時 At |
193
+ | `DailyAt(...)` / `MonthlyAt(...)` / `WeeklyAt(...)` / `YearlyAt(...)` | 天/月/週/年 At |
194
+
195
+ ### 靜態屬性
196
+
197
+ `Secondly` / `Minutely` / `Hourly` / `Daily` / `Monthly` / `Weekly` / `Yearly` / `Workday`
198
+
199
+ ---
200
+
201
+ ## 線上工具
202
+
203
+ 推薦使用線上 Cron 表達式生成器:https://cron.qqe2.com/
@@ -0,0 +1,215 @@
1
+ # 26.3 任務佇列(TaskQueue)
2
+
3
+ > **版本說明**:僅適用於 Furion 4.8.3+ 版本。可取代舊版 `SpareTime.DoIt()` 和 `SpareTime.DoOnce`。
4
+
5
+ ---
6
+
7
+ ## 26.3.1 概述
8
+
9
+ 任務佇列用於管理背景工作,不會阻塞主執行緒。基於 `Channel + Task + ThreadPool` 實作,入隊/出隊速度極快,吞吐量極高。
10
+
11
+ **應用場景**:發送郵件、發送簡訊等可能長時間執行或不需要即時回饋的任務。
12
+
13
+ **與事件匯流排的區別**:事件匯流排基於訊息通訊(無序,需匹配 Id);任務佇列按入隊順序依次出隊執行。
14
+
15
+ ---
16
+
17
+ ## 26.3.3 快速入門
18
+
19
+ ### 註冊服務
20
+
21
+ ```csharp
22
+ services.AddTaskQueue();
23
+ ```
24
+
25
+ ### 使用 ITaskQueue
26
+
27
+ ```csharp
28
+ public class YourService : IYourService
29
+ {
30
+ private readonly ITaskQueue _taskQueue;
31
+ public YourService(ITaskQueue taskQueue) => _taskQueue = taskQueue;
32
+
33
+ // 同步入隊
34
+ public void SyncTask()
35
+ {
36
+ _taskQueue.Enqueue(provider => Console.WriteLine("同步任務"));
37
+ }
38
+
39
+ // 同步入隊,延遲 3 秒
40
+ public void SyncTaskDelay()
41
+ {
42
+ _taskQueue.Enqueue(_ => Console.WriteLine("延遲 3 秒"),
43
+ task => task.WithDelay(3000));
44
+ }
45
+
46
+ // 非同步入隊
47
+ public async Task AsyncTask()
48
+ {
49
+ await _taskQueue.EnqueueAsync(async (provider, token) =>
50
+ {
51
+ Console.WriteLine("非同步任務");
52
+ await ValueTask.CompletedTask;
53
+ });
54
+ }
55
+
56
+ // 非同步入隊,延遲 3 秒
57
+ public async Task AsyncTaskDelay()
58
+ {
59
+ await _taskQueue.EnqueueAsync(async (_, _) =>
60
+ {
61
+ Console.WriteLine("延遲 3 秒");
62
+ await ValueTask.CompletedTask;
63
+ }, task => task.WithDelay(3000));
64
+ }
65
+
66
+ // Cron 表達式延遲
67
+ public void CronTask()
68
+ {
69
+ _taskQueue.Enqueue(_ => Console.WriteLine("Cron"),
70
+ task => task.WithDelay("* * * * *"));
71
+ }
72
+
73
+ // 延遲 + 立即執行一次(4.9.1.56+)
74
+ public void DelayWithRunOnce()
75
+ {
76
+ _taskQueue.Enqueue(_ => Console.WriteLine("延遲但先執行一次"),
77
+ task => task.WithDelay(3000).WithRunOnceIfDelaySet(true));
78
+ }
79
+ }
80
+ ```
81
+
82
+ ### TaskQueued 靜態類
83
+
84
+ ```csharp
85
+ TaskQueued.Enqueue(provider => { });
86
+ await TaskQueued.EnqueueAsync(async (provider, token) => { });
87
+ ```
88
+
89
+ ---
90
+
91
+ ## 26.3.5 在處理程式中使用服務
92
+
93
+ ```csharp
94
+ _taskQueue.Enqueue(provider =>
95
+ {
96
+ // 範圍/瞬時服務需建立作用域
97
+ using var scoped = provider.CreateScope();
98
+ var repository = scoped.ServiceProvider.GetService<IRepository<User>>();
99
+
100
+ // 單例服務可直接使用外部注入的實例
101
+ _logger.LogInformation("OK");
102
+ });
103
+ ```
104
+
105
+ ---
106
+
107
+ ## 26.3.6 訂閱未察覺異常
108
+
109
+ ```csharp
110
+ services.AddTaskQueue(builder =>
111
+ {
112
+ builder.UnobservedTaskExceptionHandler = (obj, args) => { };
113
+ });
114
+ ```
115
+
116
+ ---
117
+
118
+ ## 26.3.7 並行與串行(4.9.1.22+)
119
+
120
+ ```csharp
121
+ // 全域設定
122
+ services.AddTaskQueue(builder =>
123
+ {
124
+ builder.Concurrent = false; // 串行(預設並行)
125
+ });
126
+
127
+ // 局部設定(4.9.1.38+)
128
+ await _taskQueue.EnqueueAsync(async (_, _) => { },
129
+ task => task.WithDelay(3000).WithConcurrent(false)); // 串行
130
+ ```
131
+
132
+ ---
133
+
134
+ ## 26.3.8 任務標識 TaskId(4.9.1.28+)
135
+
136
+ ```csharp
137
+ // 自動產生 TaskId
138
+ var taskId = await _taskQueue.EnqueueAsync(async (_, _) => { });
139
+
140
+ // 自訂 TaskId(4.9.1.38+)
141
+ var taskId = await _taskQueue.EnqueueAsync(async (_, _) => { },
142
+ task => task.WithTaskId("唯一 id"));
143
+ ```
144
+
145
+ ---
146
+
147
+ ## 26.3.9 任務管道 Channel(4.9.1.28+)
148
+
149
+ ```csharp
150
+ var taskId = await _taskQueue.EnqueueAsync(async (_, _) => { },
151
+ task => task.WithChannel("批次1"));
152
+ ```
153
+
154
+ 可根據 Channel 進行任務執行結果訂閱。
155
+
156
+ ---
157
+
158
+ ## 26.3.10 異常重試設定(4.9.1.24+)
159
+
160
+ ```csharp
161
+ services.AddTaskQueue(builder =>
162
+ {
163
+ builder.NumRetries = 3; // 預設重試 3 次
164
+ builder.RetryTimeout = 1000; // 每次間隔 1000ms
165
+ });
166
+ ```
167
+
168
+ ---
169
+
170
+ ## 26.3.11 任務執行結果訂閱(4.9.1.28+)
171
+
172
+ ```csharp
173
+ _taskQueue.OnExecuted += (sender, args) =>
174
+ {
175
+ Console.WriteLine($"任務 {args.TaskId} 管道 {args.Channel},狀態:{args.Status},異常:{args.Exception}");
176
+ };
177
+ ```
178
+
179
+ ### 重複訂閱問題
180
+
181
+ `ITaskQueue` 為單例,非單例服務中訂閱後需在 `Dispose` 中移除:
182
+
183
+ ```csharp
184
+ public class SomeService : ISomeService, IScoped, IDisposable
185
+ {
186
+ private readonly ITaskQueue _taskQueue;
187
+
188
+ public SomeService(ITaskQueue taskQueue)
189
+ {
190
+ _taskQueue = taskQueue;
191
+ _taskQueue.OnExecuted += Subscribe;
192
+ }
193
+
194
+ void Subscribe(object sender, TaskHandlerEventArgs args) { }
195
+
196
+ public void Dispose() => _taskQueue.OnExecuted -= Subscribe;
197
+ }
198
+ ```
199
+
200
+ ### 最佳推薦
201
+
202
+ 在 `Startup.cs` 的 `Configure` 中或**單例服務**中訂閱,避免重複多播。
203
+
204
+ ---
205
+
206
+ ## 任務設定方法速查
207
+
208
+ | 方法 | 說明 |
209
+ |------|------|
210
+ | `.WithDelay(ms)` | 延遲毫秒數 |
211
+ | `.WithDelay(cronExpr, format)` | Cron 表達式延遲 |
212
+ | `.WithRunOnceIfDelaySet(true)` | 延遲佇列先立即執行一次(4.9.1.56+) |
213
+ | `.WithConcurrent(bool)` | 局部並行/串行(4.9.1.38+) |
214
+ | `.WithTaskId(object)` | 自訂任務 Id(4.9.1.38+) |
215
+ | `.WithChannel(string)` | 設定管道/批次(4.9.1.28+) |
@@ -0,0 +1,86 @@
1
+ # 27. 分散式 ID 生成
2
+
3
+ ---
4
+
5
+ ## 27.1 為什麼需要分散式 ID
6
+
7
+ - **全域唯一性**:不能出現重複的 ID,這是最基本的要求。
8
+ - **趨勢遞增**:MySQL InnoDB 使用聚集索引,B-tree 資料結構下應盡量使用有序主鍵以保證寫入效能。
9
+ - **單調遞增**:保證下一個 ID 一定大於上一個 ID,適用於交易版本號、IM 增量訊息、排序等場景。
10
+ - **資訊安全**:連續 ID 容易被惡意爬取或讓競爭對手推算訂單量,某些場景下需要 ID 無規則。
11
+
12
+ ---
13
+
14
+ ## 27.2 分散式 ID 種類
15
+
16
+ | 類型 | 說明 |
17
+ |------|------|
18
+ | 連續 GUID | 基於時間戳的有序 GUID |
19
+ | 短 ID | 適用於低並發內部系統(任務 ID、Issue 編號等) |
20
+ | 雪花演算法 ID | 2.1+ 版本已移除,建議自行整合 |
21
+
22
+ ---
23
+
24
+ ## 27.3 如何使用
25
+
26
+ ### 27.3.1 連續 GUID
27
+
28
+ **靜態 `IDGen` 方式:**
29
+
30
+ ```csharp
31
+ var guid = IDGen.NextID();
32
+
33
+ // 更多參數
34
+ var guid2 = IDGen.NextID(new SequentialGuidSettings { LittleEndianBinary16Format = true });
35
+ ```
36
+
37
+ > ⚠️ 在迴圈中使用 `IDGen` 靜態類效能最差(底層不斷解析服務)。非迴圈中效能等同於以下兩種方式。
38
+
39
+ **`IDistributedIDGenerator` 注入方式(推薦):**
40
+
41
+ ```csharp
42
+ private readonly IDistributedIDGenerator _idGenerator;
43
+
44
+ public AppServices(IDistributedIDGenerator idGenerator)
45
+ {
46
+ _idGenerator = idGenerator;
47
+ var guidObject = _idGenerator.Create();
48
+ }
49
+ ```
50
+
51
+ **`SequentialGuidIDGenerator` 方式:**
52
+
53
+ ```csharp
54
+ var idGen = new SequentialGuidIDGenerator();
55
+ var guid = idGen.Create();
56
+
57
+ // 更多參數
58
+ var guid2 = idGen.Create(new SequentialGuidSettings { LittleEndianBinary16Format = true });
59
+ ```
60
+
61
+ ### 27.3.2 短 ID
62
+
63
+ ```csharp
64
+ var shortid = ShortIDGen.NextID(); // 包含數字、字母,不含特殊符號,8 位
65
+
66
+ // 更多設定
67
+ var shortid = ShortIDGen.NextID(new GenerationOptions
68
+ {
69
+ UseNumbers = false, // 不包含數字
70
+ UseSpecialCharacters = true, // 包含特殊符號
71
+ Length = 8 // 設定長度(不設定則為隨機長度)
72
+ });
73
+
74
+ // 自訂參與運算的字元
75
+ ShortIDGen.SetCharacters("ⒶⒷⒸⒹⒺⒻⒼⒽⒾⒿⓀⓁⓂⓃⓄⓅⓆⓇⓈⓉⓊⓋⓌⓍⓎⓏ...");
76
+
77
+ // 自訂隨機數步長
78
+ ShortIDGen.SetSeed(1939048828);
79
+
80
+ // 重置所有自訂設定
81
+ ShortIDGen.Reset();
82
+ ```
83
+
84
+ ### 27.3.3 雪花演算法 ID
85
+
86
+ Furion 2.1+ 版本已移除雪花演算法 ID 功能,因使用頻率不高且實作方式各異,建議採用擴充或自行整合的方式。
@@ -0,0 +1,68 @@
1
+ # 28. 模組化開發
2
+
3
+ ---
4
+
5
+ ## 28.1 概述
6
+
7
+ 模組化是將不同功能組裝在一起的程式碼組織方式,像樂高積木一樣,各模組形狀功能不同,互相依賴支撐,最終組成完整專案。
8
+
9
+ ### 模組分類
10
+
11
+ | 類型 | 說明 |
12
+ |------|------|
13
+ | **應用程式模組** | 完整的應用程式,可獨立執行,有自己的實體、服務、API 及 UI |
14
+ | **框架級模組** | 解決特定業務功能的模組,如上傳檔案、分散式快取、資料驗證等 |
15
+
16
+ ---
17
+
18
+ ## 28.3 啟用模組化支援
19
+
20
+ > ⚠️ 以下設定**必須**在 `appsettings.json` 中設定才有效(啟動時自訂設定檔尚未載入)。
21
+
22
+ ```json
23
+ {
24
+ "AppSettings": {
25
+ "EnabledReferenceAssemblyScan": true,
26
+ "SupportPackageNamePrefixs": ["Module1", "Module2"],
27
+ "ExternalAssemblies": ["plugins/Module1.dll", "plugins/Module2.dll"]
28
+ }
29
+ }
30
+ ```
31
+
32
+ ### 四種新增模組方式
33
+
34
+ | 方式 | 設定 | 說明 |
35
+ |------|------|------|
36
+ | **專案引用** | 無需設定 | 直接新增專案參考或編輯 `.csproj`,Furion 自動載入 |
37
+ | **DLL 引用** | `EnabledReferenceAssemblyScan: true` | 新增 `.dll` 參考方式 |
38
+ | **NuGet 安裝** | `SupportPackageNamePrefixs: [...]` | 設定 NuGet 套件名稱前綴 |
39
+ | **動態載入 DLL** | `ExternalAssemblies: [...]` | 放入 plugins 資料夾,無需新增參考(4.9.2.14+ 支援目錄掃描) |
40
+
41
+ ### 動態載入 DLL 發佈設定
42
+
43
+ 預設插件/模組資料夾不會輸出到發佈目錄,需編輯 `.csproj`:
44
+
45
+ ```xml
46
+ <ItemGroup>
47
+ <None Update="plugins\**\**">
48
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
49
+ </None>
50
+ </ItemGroup>
51
+ ```
52
+
53
+ ---
54
+
55
+ ## 28.4 注意事項
56
+
57
+ - 每個模組應有獨立的路由格式:`/模組名稱/路由位址`,避免衝突
58
+ - 若包含 UI 元素(檢視、HTML/CSS/JS),應採用**嵌入式資源**方式
59
+ - 模組需新增第三方服務時,應設定在 `AppStartup` 的衍生類別中
60
+ - 模組的註解檔 `.xml` 需放在與 `.dll` 同級目錄
61
+
62
+ ---
63
+
64
+ ## 28.5 關於熱插拔機制
65
+
66
+ Furion v2.4.0+ 已移除執行階段熱載入/熱卸載模組功能,因為微軟的 `AssemblyLoadContext` + 資料夾監控機制尚未成熟。
67
+
68
+ 目前框架僅支援**啟動時載入模組**,不在執行階段進行任何處理。