@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,408 @@
1
+ # Furion 依賴注入 / 控制反轉(DI / IoC)筆記
2
+
3
+ ---
4
+
5
+ ## 1. 核心概念
6
+
7
+ | 概念 | 簡稱 | 說明 |
8
+ |------|------|------|
9
+ | 依賴注入 | DI | 不在程式碼中手動 `new`,由外部容器自動注入所需物件 |
10
+ | 控制反轉 | IoC | 將建立物件實例的控制權,從程式碼交給 IoC 容器管理 |
11
+
12
+ **優點**:解耦、易擴展、易單元測試
13
+ **缺點**:採用反射實現,有一定效能損耗
14
+
15
+ ---
16
+
17
+ ## 2. 三種注入方式
18
+
19
+ ### 2.1 建構子注入(推薦)
20
+
21
+ ```csharp
22
+ public class FurionService
23
+ {
24
+ private readonly IRepository _repository;
25
+
26
+ public FurionService(IRepository repository)
27
+ {
28
+ _repository = repository;
29
+ }
30
+ }
31
+ ```
32
+
33
+ ✅ 依賴關係清晰,物件初始化後狀態正確
34
+ ❌ 參數可能過多;有些類(如 MVC Controller)不適合
35
+
36
+ ---
37
+
38
+ ### 2.2 屬性注入
39
+
40
+ ```csharp
41
+ public class FurionService
42
+ {
43
+ [FromServices] // .NET 8+ 也支援 [FromKeyedServices]
44
+ public IRepository Repository { get; set; }
45
+ }
46
+ ```
47
+
48
+ ✅ 靈活,可隨時替換依賴
49
+ ❌ 僅限 Controller / 動態 WebAPI;狀態不一致風險
50
+
51
+ ---
52
+
53
+ ### 2.3 方法參數注入
54
+
55
+ ```csharp
56
+ public class FurionService
57
+ {
58
+ public Person GetById([FromServices] IRepository repository, int id)
59
+ {
60
+ return repository.Find(id);
61
+ }
62
+ }
63
+ ```
64
+
65
+ ✅ 靈活
66
+ ❌ 僅限 Controller / 動態 WebAPI;新增依賴會破壞方法簽章
67
+
68
+ ---
69
+
70
+ ## 3. 生命週期
71
+
72
+ | 介面 | 生命週期 | 說明 |
73
+ |------|----------|------|
74
+ | `ITransient` | 暫時(Transient) | 每次請求都建立新實例,適合輕量無狀態服務 |
75
+ | `IScoped` | 範圍(Scoped) | 每個 HTTP 請求建立一次,請求結束後釋放 |
76
+ | `ISingleton` | 單例(Singleton) | 首次請求後全程共用同一實例 |
77
+
78
+ > ⚠️ 以上介面只能由**實例類**實現,靜態類、抽象類、介面不可實現。
79
+
80
+ ---
81
+
82
+ ## 4. 常見用法
83
+
84
+ ### 4.1 基本用法(介面 + 實作)
85
+
86
+ ```csharp
87
+ // Service 層
88
+ public interface IBusinessService { Person Get(int id); }
89
+
90
+ public class BusinessService : IBusinessService, ITransient
91
+ {
92
+ private readonly IRepository<Person> _personRepository;
93
+
94
+ public BusinessService(IRepository<Person> personRepository)
95
+ {
96
+ _personRepository = personRepository;
97
+ }
98
+
99
+ public Person Get(int id) => _personRepository.Find(id);
100
+ }
101
+
102
+ // Controller 層
103
+ public class PersonController : ControllerBase
104
+ {
105
+ private readonly IBusinessService _businessService;
106
+
107
+ public PersonController(IBusinessService businessService)
108
+ {
109
+ _businessService = businessService;
110
+ }
111
+ }
112
+ ```
113
+
114
+ ---
115
+
116
+ ### 4.2 泛型注入
117
+
118
+ ```csharp
119
+ public class BusinessService<T> : IBusinessService<T>, ITransient { ... }
120
+
121
+ // 注入
122
+ public PersonController(IBusinessService<int> businessService) { ... }
123
+ ```
124
+
125
+ ---
126
+
127
+ ### 4.3 一個介面多個實作
128
+
129
+ **推薦:`INamedServiceProvider`(Furion 3.8.6+)**
130
+
131
+ ```csharp
132
+ public class BusinessService : IBusinessService, ITransient { ... }
133
+ public class OtherBusinessService : IBusinessService, ITransient { ... }
134
+
135
+ // 注入並解析
136
+ public class MyApi : IDynamicApiController
137
+ {
138
+ private readonly INamedServiceProvider<IBusinessService> _provider;
139
+
140
+ public MyApi(INamedServiceProvider<IBusinessService> provider)
141
+ {
142
+ _provider = provider;
143
+ }
144
+
145
+ public string GetName()
146
+ {
147
+ // 方法一:透過反射(有效能損耗)
148
+ var s1 = _provider.GetService(nameof(BusinessService));
149
+
150
+ // 方法二:指定生命週期(無反射,推薦)
151
+ var s2 = _provider.GetService<ITransient>(nameof(OtherBusinessService));
152
+
153
+ return s1.GetName() + s2.GetName();
154
+ }
155
+ }
156
+ ```
157
+
158
+ **自訂解析名稱:`[Injection(Named = "...")]`**
159
+
160
+ ```csharp
161
+ [Injection(Named = "BusName1")]
162
+ public class BusinessService : IBusinessService, ITransient { ... }
163
+
164
+ [Injection(Named = "BusName2")]
165
+ public class OtherBusinessService : IBusinessService, ITransient { ... }
166
+ ```
167
+
168
+ ---
169
+
170
+ ### 4.4 無介面注入(直接注入實作類)
171
+
172
+ ```csharp
173
+ public class SelfService : ITransient
174
+ {
175
+ // ...
176
+ }
177
+
178
+ // Controller 直接注入實作類
179
+ public ValueController(SelfService selfService) { ... }
180
+ ```
181
+
182
+ ---
183
+
184
+ ## 5. `[Injection]` 特性配置
185
+
186
+ | 屬性 | 類型 | 說明 |
187
+ |------|------|------|
188
+ | `Action` | `InjectionActions` | `Add`(預設,允許多實作)/ `TryAdd`(已存在則跳過) |
189
+ | `Pattern` | `InjectionPatterns` | `Self` / `FirstInterface` / `SelfWithFirstInterface` / `ImplementedInterfaces` / `All`(預設) |
190
+ | `Named` | `string` | 別名,預設為類名 |
191
+ | `Order` | `int` | 注冊排序,數字越大越晚注冊 |
192
+ | `Proxy` | `Type` | AOP 代理類型 |
193
+ | `ExceptInterfaces` | `Type[]` | 排除不注冊的介面 |
194
+
195
+ ---
196
+
197
+ ## 6. appsettings.json 動態注冊
198
+
199
+ 可不修改程式碼,直接透過設定檔實現熱插拔:
200
+
201
+ ```json
202
+ {
203
+ "DependencyInjectionSettings": {
204
+ "Definitions": [
205
+ {
206
+ "Interface": "Furion.Application;Furion.Application.ITestService",
207
+ "Service": "Furion.Application;Furion.Application.TestService",
208
+ "RegisterType": "Transient",
209
+ "Action": "Add",
210
+ "Pattern": "SelfWithFirstInterface",
211
+ "Named": "TestService",
212
+ "Order": 1,
213
+ "Proxy": "Furion.Application;Furion.Application.LogDispatchProxy"
214
+ }
215
+ ]
216
+ }
217
+ }
218
+ ```
219
+
220
+ > 💡 格式:`程式集名稱;完整類別名稱`
221
+ > 💡 外部程式集需先在 `AppSettings.ExternalAssemblies` 中註冊
222
+
223
+ **注冊優先級**:`appsettings.json` > `[Injection]` > 預設掃描
224
+
225
+ ---
226
+
227
+ ## 7. AOP 攔截
228
+
229
+ > ⚠️ 僅支援**介面注入**,不支援直接注入類。動態 API 請改用 Filter 方式。
230
+
231
+ ### 7.1 建立代理類
232
+
233
+ ```csharp
234
+ public class LogDispatchProxy : AspectDispatchProxy, IDispatchProxy
235
+ {
236
+ public object Target { get; set; }
237
+ public IServiceProvider Services { get; set; }
238
+
239
+ // 同步攔截
240
+ public override object Invoke(MethodInfo method, object[] args)
241
+ {
242
+ Console.WriteLine("方法被呼叫");
243
+ var result = method.Invoke(Target, args);
244
+ Console.WriteLine("返回值:" + result);
245
+ return result;
246
+ }
247
+
248
+ // 非同步無回傳值
249
+ public async override Task InvokeAsync(MethodInfo method, object[] args)
250
+ {
251
+ Console.WriteLine("方法被呼叫");
252
+ await (method.Invoke(Target, args) as Task);
253
+ }
254
+
255
+ // 非同步有回傳值
256
+ public async override Task<T> InvokeAsyncT<T>(MethodInfo method, object[] args)
257
+ {
258
+ var result = await (method.Invoke(Target, args) as Task<T>);
259
+ return result;
260
+ }
261
+ }
262
+ ```
263
+
264
+ > 💡 取得方法特性:`method.GetActualCustomAttribute<TAttribute>()`
265
+
266
+ ### 7.2 套用代理
267
+
268
+ ```csharp
269
+ [Injection(Proxy = typeof(LogDispatchProxy))]
270
+ public class TestService : ITestService, ITransient { ... }
271
+ ```
272
+
273
+ ### 7.3 全域攔截
274
+
275
+ ```csharp
276
+ // IDispatchProxy 改為 IGlobalDispatchProxy
277
+ public class LogDispatchProxy : AspectDispatchProxy, IGlobalDispatchProxy { ... }
278
+
279
+ // 排除特定類
280
+ [SuppressProxy]
281
+ public class SkipService : ISkipService, ITransient { ... }
282
+ ```
283
+
284
+ **攔截優先級**:`[SuppressProxy]` > `[Injection(Proxy)]` > 全域攔截
285
+
286
+ ### 7.4 在 AOP 中解析服務
287
+
288
+ ```csharp
289
+ var someService = Services.GetService<ISomeService>(); // 推薦
290
+ // 或
291
+ var someService = App.GetService<ISomeService>();
292
+ ```
293
+
294
+ ---
295
+
296
+ ## 8. 非 Web / 多執行緒中解析服務
297
+
298
+ Web 請求外框架不會自動管理作用域,需手動建立:
299
+
300
+ ```csharp
301
+ // 方式一:IServiceProvider
302
+ using var scope = serviceProvider.CreateScope();
303
+ var services = scope.ServiceProvider;
304
+ var repo = Db.GetRepository<Person>(services);
305
+ var other = services.GetService<XXX>();
306
+
307
+ // 方式二:IServiceScopeFactory
308
+ using var scope = serviceScopeFactory.CreateScope();
309
+ var services = scope.ServiceProvider;
310
+
311
+ // 方式三:Scoped 靜態類(Furion 提供)
312
+ Scoped.Create((factory, scope) => {
313
+ var services = scope.ServiceProvider;
314
+ });
315
+ ```
316
+
317
+ ---
318
+
319
+ ## 9. 在單例中解析非單例服務
320
+
321
+ 透過 `IServiceScopeFactory` 建立範圍再解析:
322
+
323
+ ```csharp
324
+ public class SomeService : ISomeService, ISingleton
325
+ {
326
+ private readonly IServiceScopeFactory _scopeFactory;
327
+
328
+ public SomeService(IServiceScopeFactory scopeFactory)
329
+ {
330
+ _scopeFactory = scopeFactory;
331
+ }
332
+
333
+ public async Task Method()
334
+ {
335
+ using var scope = _scopeFactory.CreateScope();
336
+ var repo = scope.ServiceProvider.GetService<IRepository<User>>();
337
+ }
338
+ }
339
+ ```
340
+
341
+ ---
342
+
343
+ ## 10. WinForm / WPF 支援(Furion 4.8.7.23+)
344
+
345
+ 將所有 `new Form()` / `new Window()` 替換為 `Native.CreateInstance<T>()`。
346
+
347
+ ### WinForm
348
+
349
+ ```csharp
350
+ // Program.cs
351
+ static void Main()
352
+ {
353
+ Serve.RunNative();
354
+ ApplicationConfiguration.Initialize();
355
+ Application.Run(Native.CreateInstance<Form1>()); // ← 替換 new Form1()
356
+ }
357
+
358
+ // 開啟新視窗(支援傳入其他參數)
359
+ Native.CreateInstance<Form2>("我是參數").ShowDialog();
360
+
361
+ // 取得已開啟視窗實例
362
+ var form1 = Application.OpenForms.OfType<Form>().FirstOrDefault(f => f is Form1);
363
+ ```
364
+
365
+ ### WPF
366
+
367
+ ```csharp
368
+ // App.xaml.cs(移除 StartupUri)
369
+ public partial class App : Application
370
+ {
371
+ public App() { Serve.RunNative(); }
372
+
373
+ protected override void OnStartup(StartupEventArgs e)
374
+ {
375
+ Native.CreateInstance<MainWindow>().Show();
376
+ base.OnStartup(e);
377
+ }
378
+ }
379
+
380
+ // 開啟新視窗
381
+ Native.CreateInstance<Window1>("我是參數").Show();
382
+
383
+ // 取得已開啟視窗實例
384
+ var w = Application.Current.Windows.OfType<Window>().FirstOrDefault(w => w is MainWindow);
385
+ ```
386
+
387
+ > 💡 透過 `Native.CreateInstance<T>()` 建立的視窗支援建構子注入。
388
+
389
+ ---
390
+
391
+ ## 11. 自訂掃描注冊(Scrutor)
392
+
393
+ ```csharp
394
+ services.Scan(scan => scan
395
+ .FromAssemblyOf<ITransientService>()
396
+ .AddClasses(c => c.AssignableTo<ITransientService>())
397
+ .AsImplementedInterfaces()
398
+ .WithTransientLifetime()
399
+ .AddClasses(c => c.AssignableTo<IScopedService>())
400
+ .As<IScopedService>()
401
+ .WithScopedLifetime()
402
+ // 泛型注冊
403
+ .AddClasses(c => c.AssignableTo(typeof(IOpenGeneric<>)))
404
+ .AsImplementedInterfaces()
405
+ );
406
+ ```
407
+
408
+ > 📖 詳見 [Scrutor GitHub](https://github.com/khellang/Scrutor)
@@ -0,0 +1,162 @@
1
+ # Furion 物件資料映射(Mapster)筆記
2
+
3
+ ---
4
+
5
+ ## 1. 概念說明
6
+
7
+ 將一個物件的資料,依照特定規則批量映射到另一個物件,減少手工賦值操作與人為出錯率。常見場景:`DTO ↔ Entity` 互轉。
8
+
9
+ > 💡 Furion 推薦使用 **Mapster**(高效能、易使用)。若需使用 AutoMapper,無需安裝 Furion 的 Mapster 擴展包。
10
+
11
+ ---
12
+
13
+ ## 2. 安裝
14
+
15
+ 在 `Furion.Core` 層安裝擴展包,Furion 會自動載入,無需手動呼叫:
16
+
17
+ ```
18
+ Furion.Extras.ObjectMapper.Mapster
19
+ ```
20
+
21
+ ---
22
+
23
+ ## 3. 基本用法
24
+
25
+ ### 3.1 傳統手動賦值(舊寫法)
26
+
27
+ ```csharp
28
+ var entity = repository.Find(1);
29
+
30
+ var dto = new Dto();
31
+ dto.Id = entity.Id;
32
+ dto.Name = entity.Name;
33
+ dto.Age = entity.Age;
34
+ dto.FullName = entity.FirstName + entity.LastName;
35
+ dto.IdCard = entity.IdCard.Replace("1234", "****");
36
+ ```
37
+
38
+ ### 3.2 使用 Mapster(新寫法)
39
+
40
+ ```csharp
41
+ var entity = repository.Find(1);
42
+ var dto = entity.Adapt<Dto>(); // 一行搞定
43
+ ```
44
+
45
+ ---
46
+
47
+ ## 4. 自訂映射規則
48
+
49
+ 對於需要特殊處理的欄位(如組合欄位、資料遮罩),建立映射規則類:
50
+
51
+ ```csharp
52
+ using Mapster;
53
+
54
+ public class Mapper : IRegister
55
+ {
56
+ public void Register(TypeAdapterConfig config)
57
+ {
58
+ config.ForType<Entity, Dto>()
59
+ .Map(dest => dest.FullName, src => src.FirstName + src.LastName)
60
+ .Map(dest => dest.IdCard, src => src.IdCard.Replace("1234", "****"));
61
+ }
62
+ }
63
+ ```
64
+
65
+ > 💡 `Mapper.cs` 可放在任意專案或資料夾,Furion 啟動時會自動掃描並注入設定。
66
+
67
+ ---
68
+
69
+ ## 5. 依賴注入方式
70
+
71
+ ```csharp
72
+ public class PersonService
73
+ {
74
+ private readonly IMapper _mapper;
75
+
76
+ public PersonService(IMapper mapper)
77
+ {
78
+ _mapper = mapper;
79
+ }
80
+
81
+ public Dto GetDto(Entity entity)
82
+ {
83
+ return _mapper.Map<Dto>(entity);
84
+ }
85
+ }
86
+ ```
87
+
88
+ ---
89
+
90
+ ## 6. 搭配 EF Core(ProjectToType)
91
+
92
+ 避免手動 `Select` 逐欄位對應:
93
+
94
+ ```csharp
95
+ // 傳統寫法
96
+ var list = context.Sources
97
+ .Select(p => new Destination
98
+ {
99
+ Id = p.Id,
100
+ Name = p.Name,
101
+ // ...
102
+ }).ToList();
103
+
104
+ // Mapster 寫法
105
+ var list = context.Sources
106
+ .ProjectToType<Destination>()
107
+ .ToList();
108
+ ```
109
+
110
+ ---
111
+
112
+ ## 7. 全域預設設定
113
+
114
+ 在 `Startup` 中統一設定全域映射行為:
115
+
116
+ ```csharp
117
+ TypeAdapterConfig.GlobalSettings.Default
118
+ .PreserveReference(true);
119
+ ```
120
+
121
+ ---
122
+
123
+ ## 8. Dictionary Key 變小寫問題
124
+
125
+ Mapster 映射後 `Dictionary` 的 Key 預設會變小寫,有兩種解決方式:
126
+
127
+ ### 方式一:全域設定(推薦)
128
+
129
+ ```csharp
130
+ TypeAdapterConfig.GlobalSettings.Default
131
+ .NameMatchingStrategy(NameMatchingStrategy.Exact);
132
+ ```
133
+
134
+ ### 方式二:單獨設定該映射
135
+
136
+ ```csharp
137
+ public class TestMapper : IRegister
138
+ {
139
+ public void Register(TypeAdapterConfig config)
140
+ {
141
+ config.ForType<TestDemo, TestDemo2>()
142
+ .AfterMapping(dest =>
143
+ {
144
+ dest.Dic = new Dictionary<string, string>(
145
+ dest.Dic,
146
+ StringComparer.OrdinalIgnoreCase);
147
+ });
148
+ }
149
+ }
150
+ ```
151
+
152
+ ---
153
+
154
+ ## 快速速查
155
+
156
+ | 方法 | 說明 |
157
+ |------|------|
158
+ | `entity.Adapt<Dto>()` | 物件轉換(最常用) |
159
+ | `_mapper.Map<Dto>(entity)` | DI 注入方式轉換 |
160
+ | `query.ProjectToType<Dto>()` | EF Core Linq 投影轉換 |
161
+ | `IRegister` | 自訂映射規則介面 |
162
+ | `TypeAdapterConfig.GlobalSettings.Default` | 全域設定入口 |