@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,169 @@
1
+ # 35.1 Docker 環境持續部署(Jenkins)
2
+
3
+ ---
4
+
5
+ ## 35.1.1 概述
6
+
7
+ 利用包含 .NET 環境的 Jenkins Docker 映像檔,實現持續化部署。
8
+
9
+ ---
10
+
11
+ ## 35.1.2 安裝 Docker 版 Jenkins
12
+
13
+ 標準 `jenkins:lts` 映像檔無法執行 `dotnet` 命令,需自行建置包含 .NET SDK 的映像檔。
14
+
15
+ ### Dockerfile
16
+
17
+ ```dockerfile
18
+ FROM jenkins/jenkins:lts
19
+ USER root
20
+ WORKDIR /dotnet
21
+ RUN apt-get update && apt-get install -y wget && rm -rf /var/lib/apt/lists/*
22
+ RUN wget -O dotnet.tar.gz https://download.visualstudio.microsoft.com/download/pr/.../dotnet-sdk-5.0.100-linux-x64.tar.gz
23
+ RUN tar zxf dotnet.tar.gz -C ./ && rm -rf dotnet.tar.gz
24
+ ENV PATH="${PATH}:/dotnet:/var/jenkins_home/.dotnet/tools"
25
+ ENV DOTNET_ROOT="/dotnet"
26
+ RUN apt update -y && apt install icu-devtools vim zip unzip -y
27
+ RUN usermod -a -G root jenkins
28
+ USER jenkins
29
+ ```
30
+
31
+ > SDK 下載連結請至微軟官網取得對應版本:https://dotnet.microsoft.com/download
32
+
33
+ ### 建置與執行
34
+
35
+ ```bash
36
+ # 建置映像檔
37
+ docker build -t jenkins:dotnet .
38
+
39
+ # 執行容器
40
+ docker run -d -p 8080:8080 -p 50000:50000 --name mjenkins \
41
+ --privileged=true --restart always -u root \
42
+ -e TZ="Asia/Shanghai" \
43
+ -v /mudata/jenkins:/var/jenkins_home \
44
+ -v /usr/bin/docker:/usr/bin/docker \
45
+ -v /var/run/docker.sock:/var/run/docker.sock \
46
+ -v /mudata/webroot/:/mudata/webroot \
47
+ jenkins:dotnet
48
+ ```
49
+
50
+ ---
51
+
52
+ ## 35.1.3 自動化部署(本地)
53
+
54
+ ### Shell 腳本
55
+
56
+ ```bash
57
+ #!/bin/bash
58
+ # Jenkins 建置腳本(測試服)
59
+
60
+ solutionName=YourProject.Web.Entry
61
+ containerName=yourcontainer
62
+ port=9994
63
+ csprojDir=${solutionName}/${solutionName}.csproj
64
+ webDir=/mudata/webroot/jenkins/publish/webapp
65
+
66
+ dotnet restore
67
+
68
+ # 清空並發佈
69
+ rm -rf ${webDir}/${JOB_NAME}/*
70
+ dotnet publish ${JENKINS_HOME}/workspace/${JOB_NAME}/${csprojDir} \
71
+ -c Release -o ${webDir}/${JOB_NAME} /p:Version=1.0.${BUILD_NUMBER}
72
+
73
+ # 停止並移除舊容器
74
+ CID=$(docker ps -a | grep "${containerName}" | awk '{print $1}')
75
+ if [ "$CID" != "" ]; then
76
+ docker stop ${containerName}
77
+ docker rm ${containerName}
78
+ docker rmi ${containerName}
79
+ fi
80
+
81
+ # 重新建置並執行
82
+ docker build -t ${containerName} ${webDir}/${JOB_NAME}/.
83
+ docker run --name ${containerName} --restart=always -d \
84
+ -p ${port}:${port} -v /etc/localtime:/etc/localtime:ro ${containerName}
85
+
86
+ echo "success!"
87
+ ```
88
+
89
+ > 流程:拉取原始碼 → `dotnet publish` → `docker build` → `docker run`。可設定分支合併後自動觸發建置。
90
+
91
+ ---
92
+
93
+ ## 35.1.4 自動化遠端部署
94
+
95
+ ### 前置條件
96
+
97
+ 安裝 Jenkins 外掛:**Publish Over SSH**,並在「系統管理 → Publish over SSH」設定 SSH 伺服器。
98
+
99
+ ### 建置腳本(Jenkins 端)
100
+
101
+ ```bash
102
+ #!/bin/bash
103
+ # 發佈並打包
104
+
105
+ solutionName=YourProject.Web.Entry
106
+ csprojDir=/${solutionName}/${solutionName}.csproj
107
+ webDir=/mudata/webroot/jenkins/publish/webapp
108
+
109
+ dotnet restore
110
+
111
+ rm -rf ${webDir}/${JOB_NAME}/*
112
+ dotnet publish ${JENKINS_HOME}/workspace/${JOB_NAME}/${csprojDir} \
113
+ -c Release -o ${webDir}/${JOB_NAME} /p:Version=1.0.${BUILD_NUMBER}
114
+
115
+ # 打包
116
+ rm -rf ${JENKINS_HOME}/workspace/${JOB_NAME}/publish
117
+ mkdir ${JENKINS_HOME}/workspace/${JOB_NAME}/publish
118
+ tar -czvf ${JENKINS_HOME}/workspace/${JOB_NAME}/publish/${JOB_NAME}.${BUILD_NUMBER}.tar.gz \
119
+ -C ${webDir}/${JOB_NAME} .
120
+
121
+ echo "success!"
122
+ ```
123
+
124
+ ### 建置後操作(Send Build artifacts over SSH)
125
+
126
+ | 設定 | 值 |
127
+ |------|------|
128
+ | Source files | `publish/` |
129
+ | Remote directory | `/mudata/webroot/publish/` |
130
+ | Exec command | `bash /mudata/shell/publish.sh ${JOB_NAME} yourcontainer ${JOB_NAME}.${BUILD_NUMBER} 9994` |
131
+
132
+ > Source files 必須是 workspace 下的路徑。Jenkins 環境變數都可使用。
133
+
134
+ ### 遠端執行腳本(publish.sh)
135
+
136
+ ```bash
137
+ #!/bin/bash
138
+ # 遠端伺服器部署腳本
139
+
140
+ solutionName=$1
141
+ containerName=$2
142
+ filename=$3
143
+ port=$4
144
+ baseDir=/mudata/webroot/publish
145
+ webDir=${baseDir}/publish/${filename}
146
+
147
+ # 解壓
148
+ rm -rf ${webDir} && mkdir ${webDir}
149
+ tar -zxvf ${baseDir}/publish/${filename}.tar.gz -C ${webDir}/
150
+
151
+ # 替換正式環境設定
152
+ rm -f ${webDir}/appsettings.json
153
+ mv ${webDir}/appsettings.Prod.json ${webDir}/appsettings.json
154
+
155
+ # 停止並移除舊容器
156
+ CID=$(docker ps -a | grep "${containerName}" | awk '{print $1}')
157
+ if [ "$CID" != "" ]; then
158
+ docker stop ${containerName}
159
+ docker rm ${containerName}
160
+ docker rmi ${containerName}
161
+ fi
162
+
163
+ # 建置並執行
164
+ cd ${webDir}/ && docker build -t ${containerName} .
165
+ docker run --name ${containerName} --restart=always -d \
166
+ -p ${port}:${port} -v /etc/localtime:/etc/localtime:ro ${containerName}
167
+ ```
168
+
169
+ > 流程:Jenkins 發佈打包 → SSH 傳送到遠端 → 解壓 → 替換設定檔 → `docker build` → `docker run`。每次建置都帶版本號。
@@ -0,0 +1,275 @@
1
+ # 36.1 單元測試 / 整合測試
2
+
3
+ ---
4
+
5
+ ## 36.1.1 概述
6
+
7
+ 單元測試是對軟體中最小可測試單元進行檢查和驗證的過程。好處包括:消滅低級錯誤、找出潛在 bug、上線前保證、重構機會、重新 review 程式碼。
8
+
9
+ 測試類型:基於 API 介面測試(白盒 + 淺度黑盒)、基於專案程式碼測試(深度白盒)。
10
+
11
+ > Furion 框架使用 **xUnit** 進行單元測試。
12
+
13
+ ---
14
+
15
+ ## 36.1.5 第一個範例
16
+
17
+ ### 建立 xUnit 專案並編寫測試
18
+
19
+ ```csharp
20
+ using Xunit;
21
+
22
+ public class UnitTest1
23
+ {
24
+ [Fact]
25
+ public void Test1()
26
+ {
27
+ Assert.Equal(2, 1 + 1);
28
+ }
29
+ }
30
+ ```
31
+
32
+ > 標記 `[Fact]` 的方法為測試方法,使用 `Assert` 類進行斷言。
33
+
34
+ ### 帶參數的測試
35
+
36
+ ```csharp
37
+ [Theory]
38
+ [InlineData(1, 2)]
39
+ [InlineData(3, 4)]
40
+ [InlineData(5, 7)]
41
+ public void 帶參數測試(int i, int j)
42
+ {
43
+ Assert.NotEqual(0, (i + j) % 2);
44
+ }
45
+ ```
46
+
47
+ ---
48
+
49
+ ## 36.1.6 整合 Furion
50
+
51
+ ### 安裝套件
52
+
53
+ ```bash
54
+ # 完整版
55
+ dotnet add package Furion.Xunit
56
+
57
+ # 純淨版
58
+ dotnet add package Furion.Pure.Xunit
59
+ ```
60
+
61
+ > `Furion.Xunit` 已包含 `Furion`,無需重複安裝。請確保已安裝 `xunit` 套件。
62
+
63
+ ### 新增初始設定類 TestProgram.cs
64
+
65
+ ```csharp
66
+ using Furion.Xunit;
67
+ using Xunit.Abstractions;
68
+ using Xunit.Sdk;
69
+
70
+ [assembly: TestFramework("TestProject1.TestProgram", "TestProject1")]
71
+
72
+ namespace TestProject1;
73
+
74
+ public class TestProgram : TestStartup
75
+ {
76
+ public TestProgram(IMessageSink messageSink) : base(messageSink)
77
+ {
78
+ Serve.RunNative(services =>
79
+ {
80
+ services.AddHttpRemote(); // 註冊所需服務
81
+ });
82
+ }
83
+ }
84
+ ```
85
+
86
+ > 若出現 `did not have matching fixture data` 錯誤,可設定 `urls: Serve.IdleHost.Urls`。
87
+
88
+ ### 編寫測試方法
89
+
90
+ ```csharp
91
+ [Fact]
92
+ public async Task 測試請求百度()
93
+ {
94
+ var res = await _httpRemoteService.GetAsync("https://www.baidu.com");
95
+ Assert.True(res.IsSuccessStatusCode);
96
+ }
97
+ ```
98
+
99
+ ---
100
+
101
+ ## 36.1.8 相依性注入
102
+
103
+ ### 建構子注入
104
+
105
+ ```csharp
106
+ public class UnitTest1
107
+ {
108
+ private readonly ICalcService _calcService;
109
+
110
+ public UnitTest1(ICalcService calcService)
111
+ {
112
+ _calcService = calcService;
113
+ }
114
+
115
+ [Fact]
116
+ public void 測試加法()
117
+ {
118
+ Assert.Equal(3, _calcService.Plus(1, 2));
119
+ }
120
+ }
121
+ ```
122
+
123
+ > Furion 會在建立測試實例時建立 `IServiceScope`,所有測試案例完成後自動 `Dispose`。
124
+
125
+ ### 輸出日誌
126
+
127
+ ```csharp
128
+ public class UnitTest1
129
+ {
130
+ private readonly ITestOutputHelper Output;
131
+
132
+ public UnitTest1(ITestOutputHelper tempOutput) => Output = tempOutput;
133
+
134
+ [Fact]
135
+ public void Test()
136
+ {
137
+ Output.WriteLine("我是 Furion");
138
+ Assert.NotEqual("Furion", "Fur");
139
+ }
140
+ }
141
+ ```
142
+
143
+ ### 三種 Fixture 注入方式
144
+
145
+ | 方式 | 有效範圍 | 用法 |
146
+ |------|---------|------|
147
+ | `[AssemblyFixture(typeof(T))]` | 全域所有測試類 | 在 `TestProgram.cs` 頂部標記 |
148
+ | `IClassFixture<T>` | 單個測試類 | 測試類實作該介面 |
149
+ | `ICollectionFixture<T>` + `[Collection]` | 多個測試類 | 定義 Collection 配置器 |
150
+
151
+ **AssemblyFixture 範例:**
152
+
153
+ ```csharp
154
+ [assembly: AssemblyFixture(typeof(MyAssemblyFixture))]
155
+
156
+ public class MyAssemblyFixture : IDisposable
157
+ {
158
+ public MyAssemblyFixture() { }
159
+ public void Dispose() { }
160
+ }
161
+ ```
162
+
163
+ **IClassFixture 範例:**
164
+
165
+ ```csharp
166
+ public class UnitTest1 : IClassFixture<MyClassFixture>
167
+ {
168
+ public UnitTest1(ICalcService calcService, MyClassFixture fixture) { }
169
+ }
170
+ ```
171
+
172
+ **ICollectionFixture 範例:**
173
+
174
+ ```csharp
175
+ [CollectionDefinition("MyCollection")]
176
+ public class MyCollection : ICollectionFixture<MyCollectionFixture> { }
177
+
178
+ [Collection("MyCollection")]
179
+ public class UnitTest1
180
+ {
181
+ public UnitTest1(MyCollectionFixture collectionFixture) { }
182
+ }
183
+ ```
184
+
185
+ ---
186
+
187
+ ## 36.1.9 Web 整合測試
188
+
189
+ ### 方式一:對現有專案進行整合測試
190
+
191
+ 1. 安裝 `Microsoft.AspNetCore.Mvc.Testing`
192
+ 2. 設定 Web 專案:
193
+
194
+ **.NET 5**:新增 `FakeStartup.cs`(空類別)
195
+
196
+ **.NET 6+**:編輯 `.csproj` 新增 `<InternalsVisibleTo Include="測試專案名" />`,並在 `Program.cs` 加入 `public partial class Program { }`
197
+
198
+ 3. 編寫測試:
199
+
200
+ ```csharp
201
+ // .NET 5
202
+ public class UnitTest1 : IClassFixture<WebApplicationFactory<WebApplication1.FakeStartup>>
203
+ {
204
+ private readonly WebApplicationFactory<WebApplication1.FakeStartup> _factory;
205
+
206
+ public UnitTest1(WebApplicationFactory<WebApplication1.FakeStartup> factory)
207
+ {
208
+ _factory = factory;
209
+ }
210
+
211
+ [Theory]
212
+ [InlineData("/default")]
213
+ public async Task TestEnsureSuccessStatusCode(string url)
214
+ {
215
+ using var client = _factory.CreateClient();
216
+ using var response = await client.GetAsync(url);
217
+ response.EnsureSuccessStatusCode();
218
+ }
219
+ }
220
+
221
+ // .NET 6+:將泛型參數改為 WebApplicationFactory<Program>
222
+ ```
223
+
224
+ 主機額外設定(如環境變數):
225
+
226
+ ```csharp
227
+ _factory = factory.WithWebHostBuilder(builder =>
228
+ {
229
+ builder.UseEnvironment("Stage");
230
+ });
231
+ ```
232
+
233
+ ### 方式二:獨立主機方式
234
+
235
+ ```csharp
236
+ [Fact]
237
+ public void Test1()
238
+ {
239
+ var builder = WebApplication.CreateBuilder();
240
+ builder.Services.AddScoped<IYourService, YourService>();
241
+
242
+ using var app = builder.Build();
243
+ app.Services.GetRequiredService<IYourService>();
244
+ }
245
+ ```
246
+
247
+ ### 方式三:系統整合 / 環境 / 設定部署測試
248
+
249
+ 安裝 `Microsoft.AspNetCore.TestHost`,使用 `[assembly: HostingStartup(...)]` 特性。參考微軟官方範例。
250
+
251
+ ---
252
+
253
+ ## 36.1.10 Assert 斷言速查
254
+
255
+ 常用方法(第一個參數為期望值,第二個為實際值):
256
+
257
+ | 方法 | 說明 |
258
+ |------|------|
259
+ | `Assert.Equal(expected, actual)` | 相等 |
260
+ | `Assert.NotEqual(expected, actual)` | 不相等 |
261
+ | `Assert.True(condition)` | 為 true |
262
+ | `Assert.False(condition)` | 為 false |
263
+ | `Assert.Null(object)` | 為 null |
264
+ | `Assert.NotNull(object)` | 不為 null |
265
+ | `Assert.Contains(expected, collection)` | 集合包含 |
266
+ | `Assert.Throws<T>(action)` | 拋出指定例外 |
267
+ | `Assert.IsType<T>(object)` | 型別檢查 |
268
+
269
+ > 完整 Assert 方法請查閱 xUnit 官方文件。
270
+
271
+ ---
272
+
273
+ ## 36.1.11 單元測試覆蓋率
274
+
275
+ Visual Studio 提供內建的測試覆蓋率分析工具,可在「測試」選單中啟用。
@@ -0,0 +1,80 @@
1
+ # 36.3 基準測試(Benchmarking)
2
+
3
+ ---
4
+
5
+ ## 36.3.1 概述
6
+
7
+ 基準測試是一種測量和評估軟體效能指標的活動。透過建立已知的效能水準(基準線),在系統軟硬體環境變更後重新測試,以確定變更對效能的影響。其他用途包括:測定負載極限、管理環境變化、發現潛在效能問題等。
8
+
9
+ ### 特質
10
+
11
+ - **可重複性**:可進行重複測試,比較結果取得長期變化趨勢
12
+ - **可觀測性**:全方位監控(執行機、伺服器、資料庫)
13
+ - **可展示性**:直觀呈現結果(儀表板、圖表)
14
+ - **真實性**:反映客戶真實體驗
15
+ - **可執行性**:可快速定位、分析、調優
16
+
17
+ ### 意義
18
+
19
+ 確定系統極限、提供設定參考依據、驗收系統能力、建立效能基線。
20
+
21
+ ---
22
+
23
+ ## 36.3.3 BenchmarkDotNet
24
+
25
+ .NET 平台的基準測試工具,可將方法轉換為基準測試,追蹤效能並產生可重複的測量結果。
26
+
27
+ ### 使用方式
28
+
29
+ 1. 建立**主控台應用程式**
30
+ 2. 安裝 `BenchmarkDotNet` NuGet 套件
31
+ 3. 編寫測試:
32
+
33
+ ```csharp
34
+ using System;
35
+ using System.Security.Cryptography;
36
+ using BenchmarkDotNet.Attributes;
37
+ using BenchmarkDotNet.Running;
38
+
39
+ namespace MyBenchmarks
40
+ {
41
+ public class Md5VsSha256
42
+ {
43
+ private const int N = 10000;
44
+ private readonly byte[] data;
45
+ private readonly SHA256 sha256 = SHA256.Create();
46
+ private readonly MD5 md5 = MD5.Create();
47
+
48
+ public Md5VsSha256()
49
+ {
50
+ data = new byte[N];
51
+ new Random(42).NextBytes(data);
52
+ }
53
+
54
+ [Benchmark]
55
+ public byte[] Sha256() => sha256.ComputeHash(data);
56
+
57
+ [Benchmark]
58
+ public byte[] Md5() => md5.ComputeHash(data);
59
+ }
60
+
61
+ public class Program
62
+ {
63
+ public static void Main(string[] args)
64
+ {
65
+ var summary = BenchmarkRunner.Run<Md5VsSha256>();
66
+ }
67
+ }
68
+ }
69
+ ```
70
+
71
+ ### 結果範例
72
+
73
+ | Method | Runtime | N | Mean | Ratio |
74
+ |--------|---------|-------|----------|-------|
75
+ | Sha256 | .NET 4.7.2 | 10000 | 74.509 μs | 1.00 |
76
+ | Sha256 | .NET Core 3.0 | 10000 | 36.049 μs | 0.49 |
77
+ | Md5 | .NET 4.7.2 | 10000 | 17.308 μs | 1.00 |
78
+ | Md5 | .NET Core 3.0 | 10000 | 15.726 μs | 0.90 |
79
+
80
+ > BenchmarkDotNet 還支援匯出各種圖表報表。
@@ -0,0 +1,153 @@
1
+ # Admin.NET 自訂 Attribute 參考
2
+
3
+ ## 業務邏輯 Attribute
4
+
5
+ ### [IdempotentAttribute] — 冪等請求防重複
6
+ ```csharp
7
+ [IdempotentAttribute(IntervalTime = 5, Message = "請勿重複提交", ThrowBah = false)]
8
+ public async Task<Result> CreateOrder(OrderInput input)
9
+ {
10
+ // 5 秒內重複呼叫會返回第一次的結果(或拋出例外)
11
+ }
12
+ ```
13
+ | 參數 | 說明 |
14
+ |------|------|
15
+ | IntervalTime | 防重複間隔秒數(預設 5) |
16
+ | Message | 重複時的錯誤訊息 |
17
+ | ThrowBah | true=拋出例外,false=返回快取結果 |
18
+
19
+ **原理**:組合 路由+UserId+參數 產生 Hash,用分散式快取鎖防重複。
20
+
21
+ ---
22
+
23
+ ### [DataMask] — 資料遮罩
24
+ ```csharp
25
+ // 手機號碼:134****1234
26
+ [DataMask(3, 4)] // 從第3位開始,遮罩4個字元
27
+ public string PhoneNumber { get; set; }
28
+
29
+ // 身分證:110***********1234
30
+ [DataMask(3, 11)]
31
+ public string IdCard { get; set; }
32
+ ```
33
+ JSON 序列化時自動套用遮罩,不影響資料庫中的原始資料。
34
+
35
+ ---
36
+
37
+ ### [Dict] — 字典值驗證
38
+ ```csharp
39
+ // 使用 Enum 驗證
40
+ [Dict(SmsProviderEnum.Aliyun)]
41
+ public SmsProviderEnum? Provider { get; set; }
42
+
43
+ // 使用字典代碼驗證
44
+ [Dict("user_status", AllowNullValue = true)]
45
+ public string Status { get; set; }
46
+ ```
47
+ | 參數 | 說明 |
48
+ |------|------|
49
+ | AllowNullValue | 是否允許 null(預設 false) |
50
+ | AllowEmptyStrings | 是否允許空字串(預設 false) |
51
+
52
+ ---
53
+
54
+ ### [OwnerUser] — 資料擁有者標記
55
+ ```csharp
56
+ [OwnerUser]
57
+ public long? CreateUserId { get; set; }
58
+ ```
59
+ 標記此欄位為資料擁有者 ID,用於資料權限過濾。EntityBase 的 CreateUserId 已套用此 Attribute。
60
+
61
+ ---
62
+
63
+ ## 資料表初始化 Attribute
64
+
65
+ ### 資料庫路由 Attribute
66
+ | Attribute | 用途 |
67
+ |-----------|------|
68
+ | `[SysTableAttribute]` | 強制使用主資料庫(不受多租戶影響) |
69
+ | `[TenantAttribute]` | 路由至租戶專屬資料庫 |
70
+ | `[LogTableAttribute]` | 路由至獨立 Log 資料庫 |
71
+ | `[IgnoreTableAttribute]` | SqlSugar 不建立此資料表 |
72
+
73
+ ### 初始化行為 Attribute
74
+ | Attribute | 用途 |
75
+ |-----------|------|
76
+ | `[SeedDataAttribute]` | 此實體有對應的種子資料類別 |
77
+ | `[IncreTableAttribute]` | 允許增量更新資料表結構(新增欄位) |
78
+ | `[IncreSeedAttribute]` | 允許增量更新種子資料(新增記錄) |
79
+ | `[IgnoreUpdateSeedAttribute]` | 即使有 IncreTableAttribute 也跳過種子更新 |
80
+ | `[IgnoreUpdateSeedColumnAttribute]` | 種子更新時忽略此欄位的比對 |
81
+
82
+ ---
83
+
84
+ ## 匯入/匯出 Attribute
85
+
86
+ ### [ImportDictAttribute] — 匯入時字典轉換
87
+ ```csharp
88
+ [ImportDictAttribute("gender")] // Excel 匯入時,將"男/女"轉換為對應的字典 Key
89
+ public string Gender { get; set; }
90
+ ```
91
+
92
+ ### [IgnoreEnumToDictAttribute] — 跳過 Enum 字典轉換
93
+ ```csharp
94
+ [IgnoreEnumToDictAttribute]
95
+ public SomeEnum InternalStatus { get; set; } // 不加入字典轉換
96
+ ```
97
+
98
+ ---
99
+
100
+ ## API/回應 Attribute
101
+
102
+ ### [CustomUnifyResultAttribute] — 自訂回應格式
103
+ ```csharp
104
+ [CustomUnifyResultAttribute(typeof(MyResultProvider))]
105
+ public class SpecialApiService : IDynamicApiController, ITransient
106
+ {
107
+ // 此服務使用自訂回應格式(不使用預設的統一回應)
108
+ }
109
+ ```
110
+
111
+ ### [CustomJsonPropertyAttribute] — 自訂 JSON 屬性名
112
+ ```csharp
113
+ [CustomJsonPropertyAttribute("order_no")]
114
+ public string OrderNo { get; set; } // JSON 序列化為 "order_no"
115
+ ```
116
+
117
+ ---
118
+
119
+ ## 常數分組 Attribute
120
+
121
+ ### [ConstAttribute] — 常數分組
122
+ ```csharp
123
+ [ConstAttribute("SMS供應商")]
124
+ public class SmsProviderConst
125
+ {
126
+ public const string Aliyun = "aliyun";
127
+ public const string Tencent = "tencent";
128
+ }
129
+ ```
130
+
131
+ ### [EnumAttribute] — Enum 標記
132
+ ```csharp
133
+ [EnumAttribute]
134
+ public enum OrderStatusEnum
135
+ {
136
+ [Description("待付款")] Pending = 0,
137
+ [Description("已付款")] Paid = 1,
138
+ [Description("已完成")] Completed = 2
139
+ }
140
+ ```
141
+
142
+ ---
143
+
144
+ ## Attribute 目錄
145
+ 所有自訂 Attribute 位於:`Admin.NET.Core/Attribute/`
146
+
147
+ 常用 Attribute 快速查找:
148
+ - 防重複提交 → IdempotentAttribute
149
+ - 手機/身分證遮罩 → DataMaskAttribute
150
+ - 欄位字典驗證 → DictAttribute
151
+ - 路由至主DB → SysTableAttribute
152
+ - 有種子資料 → SeedDataAttribute
153
+ - 增量更新表結構 → IncreTableAttribute