@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,340 @@
1
+ # 23. JSON 序列化
2
+
3
+ ---
4
+
5
+ ## 23.1 概述
6
+
7
+ JSON 是一種輕量級的資料交換格式,在前後端資料互動中廣泛應用。
8
+
9
+ ---
10
+
11
+ ## 23.2 序列化庫
12
+
13
+ | 庫 | 說明 |
14
+ |---|------|
15
+ | `System.Text.Json` | .NET Core 內建,Furion 框架**預設實作** |
16
+ | `Newtonsoft.Json` | 使用人數最多,需安裝 `Microsoft.AspNetCore.Mvc.NewtonsoftJson`(Furion 4.6.5+ 已內建) |
17
+
18
+ Furion 抽象出 `IJsonSerializerProvider` 介面,統一不同序列化工具的設定與用法差異。
19
+
20
+ ---
21
+
22
+ ## 23.3 IJsonSerializerProvider 介面
23
+
24
+ ```csharp
25
+ public interface IJsonSerializerProvider
26
+ {
27
+ string Serialize(object value, object jsonSerializerOptions = default);
28
+ T Deserialize<T>(string json, object jsonSerializerOptions = default);
29
+ object Deserialize(string json, Type returnType, object jsonSerializerOptions = default);
30
+ object GetSerializerOptions();
31
+ }
32
+ ```
33
+
34
+ 預設實作:`SystemTextJsonSerializerProvider`(啟動時自動註冊)。
35
+
36
+ ---
37
+
38
+ ## 23.4 基本使用
39
+
40
+ ```csharp
41
+ // 取得實例
42
+ private readonly IJsonSerializerProvider _json;
43
+ public MyService(IJsonSerializerProvider json) => _json = json;
44
+ // 或靜態方式
45
+ var json = JSON.GetJsonSerializer();
46
+
47
+ // 序列化
48
+ var str = _json.Serialize(new { Id = 1, Name = "Furion" });
49
+
50
+ // 反序列化
51
+ var obj = _json.Deserialize<MyModel>(jsonString);
52
+
53
+ // 自訂選項
54
+ var str = _json.Serialize(obj, new JsonSerializerOptions { WriteIndented = true });
55
+ ```
56
+
57
+ > ⚠️ `System.Text.Json` 預設反序列化**大小寫敏感**,需設定 `PropertyNameCaseInsensitive = true`。
58
+
59
+ ---
60
+
61
+ ## 23.5 常見設定速查
62
+
63
+ 以下同時列出 `System.Text.Json`(STJ)和 `Newtonsoft.Json`(NJ)的設定方式。
64
+
65
+ ### 23.5.1 替換為 Newtonsoft.Json
66
+
67
+ ```csharp
68
+ services.AddControllersWithViews().AddNewtonsoftJson();
69
+ ```
70
+
71
+ 建立 `NewtonsoftJsonSerializerProvider`(實作 `IJsonSerializerProvider, ISingleton`):
72
+
73
+ ```csharp
74
+ public class NewtonsoftJsonSerializerProvider : IJsonSerializerProvider, ISingleton
75
+ {
76
+ public string Serialize(object value, object opts = null)
77
+ => JsonConvert.SerializeObject(value, (opts ?? GetSerializerOptions()) as JsonSerializerSettings);
78
+
79
+ public T Deserialize<T>(string json, object opts = null)
80
+ => JsonConvert.DeserializeObject<T>(json, (opts ?? GetSerializerOptions()) as JsonSerializerSettings);
81
+
82
+ public object Deserialize(string json, Type type, object opts = null)
83
+ => JsonConvert.DeserializeObject(json, type, (opts ?? GetSerializerOptions()) as JsonSerializerSettings);
84
+
85
+ public object GetSerializerOptions()
86
+ => App.GetOptions<MvcNewtonsoftJsonOptions>()?.SerializerSettings;
87
+ }
88
+ ```
89
+
90
+ ### 23.5.2 屬性名原樣輸出(大寫開頭)
91
+
92
+ ```csharp
93
+ // STJ
94
+ options.JsonSerializerOptions.PropertyNamingPolicy = null;
95
+
96
+ // NJ
97
+ options.SerializerSettings.ContractResolver = new DefaultContractResolver();
98
+ ```
99
+
100
+ ### 23.5.3 時間格式化(時間戳轉時間)
101
+
102
+ ```csharp
103
+ // STJ(4.6.5+,4.9.1.31+ 預設值為 yyyy-MM-dd HH:mm:ss)
104
+ options.JsonSerializerOptions.Converters.AddDateTimeTypeConverters("yyyy-MM-dd HH:mm:ss");
105
+ // UTC 自動轉本地:AddDateTimeTypeConverters("yyyy-MM-dd HH:mm:ss", true)
106
+
107
+ // NJ(4.9.1.3+)
108
+ options.SerializerSettings.Converters.AddDateTimeTypeConverters("yyyy-MM-dd HH:mm:ss");
109
+ ```
110
+
111
+ > 4.9.1.3+ 還支援自動將 13/10 位時間戳轉換為 `DateTime` / `DateTimeOffset` 型別。
112
+
113
+ ### 23.5.4 忽略循環參考
114
+
115
+ ```csharp
116
+ // STJ(.NET 6+)
117
+ options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
118
+
119
+ // NJ
120
+ options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
121
+ ```
122
+
123
+ ### 23.5.5~23.5.7 其他 STJ 設定
124
+
125
+ ```csharp
126
+ options.JsonSerializerOptions.IncludeFields = true; // 包含成員欄位
127
+ options.JsonSerializerOptions.AllowTrailingCommas = true; // 允許尾隨逗號
128
+ options.JsonSerializerOptions.ReadCommentHandling = JsonCommentHandling.Skip; // 允許註解
129
+ ```
130
+
131
+ ### 23.5.8 處理中文亂碼
132
+
133
+ ```csharp
134
+ // STJ
135
+ options.JsonSerializerOptions.Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping;
136
+
137
+ // NJ:無需設定
138
+ ```
139
+
140
+ ### 23.5.9 不區分大小寫
141
+
142
+ ```csharp
143
+ // STJ
144
+ options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
145
+
146
+ // NJ:無需設定
147
+ ```
148
+
149
+ ### 23.5.10 忽略特定屬性
150
+
151
+ ```csharp
152
+ [System.Text.Json.Serialization.JsonIgnore] // STJ
153
+ [Newtonsoft.Json.JsonIgnore] // NJ
154
+ public string PropertyName { get; set; }
155
+ ```
156
+
157
+ ### 23.5.11 動態物件屬性名大寫問題
158
+
159
+ ```csharp
160
+ // NJ
161
+ options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
162
+ ```
163
+
164
+ ### 23.5.12 忽略所有 null 屬性
165
+
166
+ ```csharp
167
+ // STJ
168
+ options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
169
+
170
+ // NJ
171
+ options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
172
+ ```
173
+
174
+ ### 23.5.13 忽略所有預設值屬性
175
+
176
+ ```csharp
177
+ // STJ
178
+ options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault;
179
+
180
+ // NJ
181
+ options.SerializerSettings.DefaultValueHandling = DefaultValueHandling.Ignore;
182
+ ```
183
+
184
+ ### 23.5.14 控制屬性序列化順序
185
+
186
+ ```csharp
187
+ [System.Text.Json.Serialization.JsonPropertyOrder(0)] // STJ
188
+ [Newtonsoft.Json.JsonProperty(Order = 0)] // NJ
189
+ ```
190
+
191
+ ### 23.5.15 重新命名序列化名稱
192
+
193
+ ```csharp
194
+ [System.Text.Json.Serialization.JsonPropertyName("newName")] // STJ
195
+ [Newtonsoft.Json.JsonProperty("newName")] // NJ
196
+ ```
197
+
198
+ ### 23.5.16 JSON 字串縮排
199
+
200
+ ```csharp
201
+ // STJ
202
+ options.JsonSerializerOptions.WriteIndented = true;
203
+
204
+ // NJ
205
+ options.SerializerSettings.Formatting = Formatting.Indented;
206
+ ```
207
+
208
+ ### 23.5.17 long 轉 string(防止 JS 精度溢位)
209
+
210
+ ```csharp
211
+ // STJ
212
+ options.JsonSerializerOptions.Converters.AddLongTypeConverters();
213
+ // 4.9.1.23+ 可設定超過 17 位才轉換
214
+ // options.JsonSerializerOptions.Converters.AddLongTypeConverters(overMaxLengthOf17: true);
215
+
216
+ // NJ
217
+ options.SerializerSettings.Converters.AddLongTypeConverters();
218
+ ```
219
+
220
+ > `Dictionary<,>` 含 `long` 的情況 STJ 不支援,需改用 NJ。
221
+
222
+ ### 23.5.18 String 轉 Number
223
+
224
+ ```csharp
225
+ // STJ
226
+ options.JsonSerializerOptions.NumberHandling = JsonNumberHandling.AllowReadingFromString;
227
+
228
+ // NJ:無需設定
229
+ ```
230
+
231
+ ### 23.5.19 Number / Boolean 轉 String(4.9.7.29+)
232
+
233
+ ```csharp
234
+ // STJ
235
+ options.JsonSerializerOptions.Converters.Add(new StringJsonConverter());
236
+ ```
237
+
238
+ ### 23.5.20 DateOnly / TimeOnly 支援(4.7.9+)
239
+
240
+ ```csharp
241
+ // STJ
242
+ options.JsonSerializerOptions.Converters.AddDateOnlyConverters();
243
+ options.JsonSerializerOptions.Converters.AddTimeOnlyConverters();
244
+
245
+ // NJ
246
+ options.SerializerSettings.Converters.AddDateOnlyConverters();
247
+ options.SerializerSettings.Converters.AddTimeOnlyConverters();
248
+ ```
249
+
250
+ ### 23.5.21 Clay 流變物件序列化
251
+
252
+ ```csharp
253
+ // STJ
254
+ options.JsonSerializerOptions.Converters.AddClayConverters();
255
+
256
+ // NJ
257
+ options.SerializerSettings.Converters.AddClayConverters();
258
+ ```
259
+
260
+ ### 23.5.22 DateTimeOffset 反序列化異常(NJ)
261
+
262
+ ```csharp
263
+ // NJ(處理 0001-01-01 00:00:00 報錯)
264
+ options.SerializerSettings.MetadataPropertyHandling = MetadataPropertyHandling.Ignore;
265
+ options.SerializerSettings.DateParseHandling = DateParseHandling.None;
266
+ options.SerializerSettings.Converters.Add(new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal });
267
+ ```
268
+
269
+ ### 23.5.23 繼承/衍生類別序列化
270
+
271
+ ```csharp
272
+ // .NET 7 之前 STJ 需手動處理
273
+ var json = JsonSerializer.Serialize<object>(value);
274
+ var json = JsonSerializer.Serialize(value, value.GetType());
275
+ ```
276
+
277
+ ### 23.5.24 列舉與字串互轉
278
+
279
+ ```csharp
280
+ // STJ 局部
281
+ [JsonConverter(typeof(JsonStringEnumConverter))]
282
+ public Gender Gender { get; set; }
283
+
284
+ // STJ 全域
285
+ options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
286
+
287
+ // NJ 局部
288
+ [JsonConverter(typeof(StringEnumConverter))]
289
+ public Gender Gender { get; set; }
290
+
291
+ // NJ 全域
292
+ options.SerializerSettings.Converters.Add(new StringEnumConverter());
293
+ ```
294
+
295
+ ### 23.5.25 檢查 JSON 有效性
296
+
297
+ ```csharp
298
+ // 原生方式
299
+ try { using var doc = JsonDocument.Parse(jsonString); }
300
+ catch (JsonException) { /* 無效 */ }
301
+
302
+ // Furion 靜態類(4.9.1.8+)
303
+ bool isValid = JSON.IsValid(jsonString);
304
+ ```
305
+
306
+ ### 23.5.26 自訂型別序列化轉換器
307
+
308
+ ```csharp
309
+ // STJ
310
+ public class LongToStringJsonConverter : JsonConverter<long>
311
+ {
312
+ public override long Read(ref Utf8JsonReader reader, Type type, JsonSerializerOptions options)
313
+ => reader.GetInt64();
314
+ public override void Write(Utf8JsonWriter writer, long value, JsonSerializerOptions options)
315
+ => writer.WriteStringValue(value.ToString());
316
+ }
317
+
318
+ // NJ
319
+ public class LongToStringJsonConverter : JsonConverter<long>
320
+ {
321
+ public override long ReadJson(JsonReader reader, Type type, long existingValue, bool hasExisting, JsonSerializer serializer)
322
+ => JValue.ReadFrom(reader).Value<long>();
323
+ public override void WriteJson(JsonWriter writer, long value, JsonSerializer serializer)
324
+ => writer.WriteValue(value.ToString());
325
+ }
326
+ ```
327
+
328
+ > 可空型別(如 `long?`)需建立獨立的轉換器。
329
+
330
+ ---
331
+
332
+ ## 23.6 DataTable / DataSet / Tuple / JArray / JObject / JToken
333
+
334
+ `System.Text.Json` 不支援這些複雜型別,需替換為 `Newtonsoft.Json`(見 23.5.1)。
335
+
336
+ ---
337
+
338
+ ## 23.7 STJ vs NJ 完整差異對比
339
+
340
+ 請參閱微軟官方文件:[從 Newtonsoft.Json 遷移到 System.Text.Json](https://docs.microsoft.com/zh-tw/dotnet/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to)
@@ -0,0 +1,247 @@
1
+ # 24. 即時通訊(SignalR)
2
+
3
+ ---
4
+
5
+ ## 24.1 概述
6
+
7
+ 即時通訊(IM)是指在網路上進行即時傳遞文字、文件、語音與視訊的系統。應用場景包括:聊天工具、網遊、直播、訂單推送、協同辦公等。
8
+
9
+ Furion 框架整合了微軟 **SignalR** 庫來簡化即時通訊開發。SignalR 已內建於 .NET SDK 中,支援 Web、App、Console、Desktop 等多平台。
10
+
11
+ ---
12
+
13
+ ## 24.4 註冊 SignalR 服務
14
+
15
+ ```csharp
16
+ // .NET 6+
17
+ var builder = WebApplication.CreateBuilder(args).Inject();
18
+ builder.Services.AddSignalR();
19
+
20
+ var app = builder.Build();
21
+ app.MapHubs(); // 註冊集線器
22
+ app.MapControllers();
23
+ app.Run();
24
+ ```
25
+
26
+ ```csharp
27
+ // .NET 5 Startup 模式
28
+ services.AddSignalR();
29
+
30
+ app.UseEndpoints(endpoints =>
31
+ {
32
+ endpoints.MapHubs();
33
+ endpoints.MapControllerRoute(name: "default", pattern: "{controller=Home}/{action=Index}/{id?}");
34
+ });
35
+ ```
36
+
37
+ ---
38
+
39
+ ## 24.6 集線器 Hub 定義
40
+
41
+ ### Hub 方式
42
+
43
+ ```csharp
44
+ [MapHub("/hubs/chathub")]
45
+ public class ChatHub : Hub
46
+ {
47
+ public Task SendMessage(string user, string message)
48
+ => Clients.All.SendAsync("ReceiveMessage", user, message);
49
+ }
50
+ ```
51
+
52
+ ### Hub\<T\> 強型別方式
53
+
54
+ ```csharp
55
+ public interface IChatClient
56
+ {
57
+ Task ReceiveMessage(string user, string message);
58
+ }
59
+
60
+ [MapHub("/hubs/chathub")]
61
+ public class StronglyTypedChatHub : Hub<IChatClient>
62
+ {
63
+ public async Task SendMessage(string user, string message)
64
+ => await Clients.All.ReceiveMessage(user, message);
65
+ }
66
+ ```
67
+
68
+ > 使用 `Hub<IChatClient>` 可獲得編譯期檢查,避免魔法字串。
69
+
70
+ ### [MapHub] 設定連線位址
71
+
72
+ ```csharp
73
+ [MapHub("/hubs/chathub")]
74
+ public class ChatHub : Hub { }
75
+ ```
76
+
77
+ ### Hub 進階設定
78
+
79
+ ```csharp
80
+ [MapHub("/hubs/chathub")]
81
+ public class ChatHub : Hub
82
+ {
83
+ public static void HttpConnectionDispatcherOptionsSettings(HttpConnectionDispatcherOptions options) { }
84
+ public static void HubEndpointConventionBuilderSettings(HubEndpointConventionBuilder builder) { }
85
+ }
86
+ ```
87
+
88
+ ---
89
+
90
+ ## 24.7 取得 Hub 實例
91
+
92
+ ```csharp
93
+ // 建構子注入(單例,可在任何地方使用)
94
+ public HomeController(IHubContext<NotificationHub> hubContext) { }
95
+
96
+ // 強型別
97
+ public ChatController(IHubContext<ChatHub, IChatClient> chatHubContext) { }
98
+
99
+ // HttpContext 解析
100
+ var hubContext = context.RequestServices.GetRequiredService<IHubContext<ChatHub>>();
101
+
102
+ // IHost 中解析
103
+ var hubContext = host.Services.GetService(typeof(IHubContext<ChatHub>));
104
+
105
+ // 泛型轉換(反射場景)
106
+ await CommonHubContextMethod((IHubContext)myHubContext);
107
+ ```
108
+
109
+ ---
110
+
111
+ ## 24.8 服務端與客戶端雙工通訊
112
+
113
+ | 方法 | 說明 |
114
+ |------|------|
115
+ | `Clients.All.方法(參數)` | 觸發所有客戶端 |
116
+ | `Clients.Caller.方法(參數)` | 觸發呼叫者客戶端 |
117
+ | `Clients.Others.方法(參數)` | 觸發呼叫者以外的客戶端 |
118
+ | `Clients.User("userId").方法(參數)` | 觸發特定使用者 |
119
+ | `Clients.Users("u1","u2").方法(參數)` | 觸發多個使用者 |
120
+ | `Clients.Group("group").方法(參數)` | 觸發分組內客戶端 |
121
+ | `Clients.Groups("g1","g2").方法(參數)` | 觸發多個分組 |
122
+ | `Clients.GroupExcept("group").方法(參數)` | 觸發分組外的客戶端 |
123
+
124
+ ---
125
+
126
+ ## 24.9 自訂使用者唯一標識
127
+
128
+ ```csharp
129
+ public class YourUserIdProvider : IUserIdProvider
130
+ {
131
+ public virtual string GetUserId(HubConnectionContext connection)
132
+ {
133
+ // 透過 connection.User 取得 JWT 授權的使用者
134
+ return connection.User?.FindFirst(ClaimTypes.NameIdentifier)?.Value;
135
+ }
136
+ }
137
+
138
+ // 註冊
139
+ builder.Services.AddSingleton<IUserIdProvider, YourUserIdProvider>();
140
+
141
+ // 使用
142
+ Clients.User(userId).方法(參數);
143
+ ```
144
+
145
+ ---
146
+
147
+ ## 24.11 各客戶端連線 API
148
+
149
+ ### 24.11.1 JavaScript 客戶端
150
+
151
+ ```bash
152
+ npm install @microsoft/signalr
153
+ ```
154
+
155
+ ```javascript
156
+ const connection = new signalR.HubConnectionBuilder()
157
+ .withUrl("/chathub")
158
+ .configureLogging(signalR.LogLevel.Information)
159
+ .build();
160
+
161
+ async function start() {
162
+ try {
163
+ await connection.start();
164
+ console.log("SignalR Connected.");
165
+ } catch (err) {
166
+ console.log(err);
167
+ setTimeout(start, 5000);
168
+ }
169
+ }
170
+
171
+ connection.onclose(async () => await start());
172
+ start();
173
+ ```
174
+
175
+ 或透過 CDN 引入:
176
+
177
+ ```html
178
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/6.0.1/signalr.js"></script>
179
+ ```
180
+
181
+ ### 24.11.2 TypeScript 客戶端(Vue 3.2+)
182
+
183
+ ```bash
184
+ npm i @microsoft/signalr @types/node
185
+ ```
186
+
187
+ ```typescript
188
+ import { HubConnectionBuilder } from "@microsoft/signalr";
189
+ import { ref } from "vue";
190
+
191
+ const messages = ref("");
192
+
193
+ const connection = new HubConnectionBuilder()
194
+ .withUrl("https://localhost:7260/chatHub")
195
+ .build();
196
+
197
+ connection.start().then(() => connection.send("SendMessage", "Hello"));
198
+
199
+ connection.on("ReciveMessage", (msg: string) => {
200
+ console.log("msg", msg);
201
+ });
202
+
203
+ const sendMsg = async () => {
204
+ await connection.send("SendMessage", messages.value);
205
+ };
206
+ ```
207
+
208
+ ### 24.11.3 .NET 客戶端
209
+
210
+ ```bash
211
+ Install-Package Microsoft.AspNetCore.SignalR.Client
212
+ ```
213
+
214
+ ```csharp
215
+ var connection = new HubConnectionBuilder()
216
+ .WithUrl("http://localhost:53353/ChatHub")
217
+ .Build();
218
+
219
+ connection.Closed += async (error) =>
220
+ {
221
+ await Task.Delay(new Random().Next(0, 5) * 1000);
222
+ await connection.StartAsync();
223
+ };
224
+
225
+ connection.On<string, string>("ReceiveMessage", (user, message) =>
226
+ {
227
+ Dispatcher.Invoke(() => messagesList.Items.Add($"{user}: {message}"));
228
+ });
229
+
230
+ await connection.StartAsync();
231
+ await connection.InvokeAsync("SendMessage", user, message);
232
+ ```
233
+
234
+ ### 24.11.4 Java 客戶端
235
+
236
+ ```groovy
237
+ // Gradle
238
+ implementation 'com.microsoft.signalr:signalr:7.0.0'
239
+ ```
240
+
241
+ ```java
242
+ HubConnection hubConnection = HubConnectionBuilder.create(url).build();
243
+ hubConnection.send("Send", input);
244
+ hubConnection.on("Send", (message) -> {
245
+ System.out.println("New Message: " + message);
246
+ }, String.class);
247
+ ```