參考系列影片:[凱哥寫程式] ASP.NET CORE WEB API 入門教學
實作參考:[Day21] C# MVC RESTful API (下) 實作RESTful API - C#&AspNetCore
實作參考 + 完整資訊補充:菜雞新訓記 (2): 認識 Api & 使用 .net Core 來建立簡單的 Web Api 服務吧
Swagger 相關:ASP.NET Core Web API 入門心得 - 改善 Enum 註解
for macOS
如果是 Visual Studio for mac ,安裝時 .NET 預設版本如果沒有8.0可選,請自行安裝 .NET 8.0,最新版本的SDK有較完整功能可使用
Note
新增 > 新增檔案 > ASP.NET CORE > WEB API 控制器
,更改檔案名稱為 HelloWorldController(.cs),按下建立。
[controller]
的部分就會是下面 class 的名稱(不含 controller)ControllerBase
而非 Controller
[APIController]
會自動處理模型驗證和錯誤回應。Visual Studio for Mac 不支援 IIS Express,這是因為 IIS Express 是 Windows 環境中的一個工具,主要用於本地開發和測試 ASP.NET 應用程序。由於 Mac OS 不支援 IIS,因此在 Visual Studio for Mac 中無法使用 IIS Express。
appsettings.json
appsettings.Development.json
appsettings.Development.json
的值去覆蓋 appsettings.json
的設定參考:
POST MAN 安裝+基本操作
EF Core = Entity Framework Core
需要先安裝二個套件:資料庫 & Tool
先到
專案資料夾>相依性
按右鍵,管理 Nuget 套件,搜尋套件名稱後安裝
原本先用 postgresql,後來有成功用 docker 執行 sql server ,可看 [note] 使用 docker 在 mac 上運行 SQL Server
參考:Entity Framework Core資料庫連線,使用Database First
- 有提到 依賴注入
資料庫設定(以 postgres 為例):
Scaffold-DbContext
資料庫變動
後續只要資料庫有變動,重新執行一次 dbcontext scaffold 完整指令即可
TrustServerCertificate=true
:信任伺服器憑證-OutputDir Models
or -o Models
:將檔案輸出到Models資料夾-Force
會覆蓋原本相同名稱的資料夾,在更新資料庫時會使用到-NoOnConfiguring
DbContext 不要產生 OnConfiguring 實體化資料庫的設定(以前使用 using 才需要這個寫法)。因為改以依賴注入處理,所以這段可以省略。如果沒加上這個參數,會自動產生以下程式碼:
將連線字串寫入 appsettings.json
DI 注入,寫入 Program.cs
postgresContext
看Models 資料夾建立時生成的檔案名UseNpgsql
依資料庫,如果是 SQL Server 就會是 UseSqlServerConfiguration.GetConnectionString("DefaultConnection")
可以從 appsettings.json 內抓出 "DefaultConnection":
後的內容[APIController]
如果套用在組件時,組件中所有控制器都會套用這個屬性。
官方文件:組件上的屬性
在 .NET 中,組件是一個編譯後的單位,通常是 .dll 或 .exe 檔案。它是由 C# 檔案編譯而成的,並且可以包含類、接口、資源等。
private readonly postgresContext _postgresContext;
第一個 postgresContext 是資料庫名稱,第二個_postgresContext 是變數名稱,習慣加上底線新增 > 新增檔案 > 一般 > 類別是空的
新增 > 新增檔案 > 一般 > 類別是空的
Microsoft.EntityFrameworkCore
postgresContext
看Models 資料夾建立時生成的檔案名UseNpgsql
依資料庫,如果是 SQL Server 就會是 UseSqlServerConfiguration.GetConnectionString("DefaultConnection")
可以從 appsettings.json 內抓出 "DefaultConnection":
後的內容builder.Services.AddControllers();
之前builder.Build
指令前,這個指令是在創建一個 app 實例,所以所有服務都要在此之前註冊完成$ dotnet ef migrations add InitialCreate
InitialCreate
是描述檔名稱$ dotnet ef database update
--context webContext
IEnumerable<T> 寫法
<T> = <Type>
關於 IEnumerable : 傳回 IEnumerable<T> 或 IAsyncEnumerable<T>
IActionResult 寫法 *
DTO = Data Transfer Object 資料傳輸物件
參考:建立資料傳輸物件
{ get; set; }
get/set
訪問器,分別用於 讀取屬性的值 和 設置屬性的值。set
訪問器可以添加驗證邏輯。{ get; set; }
,無需顯式定義私有字段。private set
和 readonly
: { get; private set; }
,或 readonly
只使用 get
訪問器而不使用 set
訪問器,屬性在物件創建後就不會被更改。.SingleOrDefault()
只取得一筆資料,且如果沒有這個 id,也不會報錯(只是回傳 null).Single()
只取一筆資料,如果沒有取得資料,會報錯[FromBody]
是指請求主體
Task
表示一個不返回結果的異步操作。Task<T>
表示一個返回結果的異步操作,其中 T 為返回的類型。JWT = Json Web Token
參考:
appsettings.cs
裡面放上 JWT 設定參數
如何讀取到 appsettings.cs 內的字串
可使用 Configuration / IConfiguration
Confuguration -
program.cs
IConfuguration - Service / Middleware / Controller 等其他地方
Nuget 管理套件:
如果無法從 Nuget 管理套件的介面操作,可以在終端機下指令
$dotnet add package 套件名
Microsoft.AspNetCore.Authentication.Bearer
Microsoft.AspNetCore.Identity.EntityFrameworkCore
Microsoft.AspNetCore.Identity
System.IdentityModel.Tokens.Jwt
安裝後至 .csproj
檔案確認,是否有更新
可參考:
SwashBuckle: 菜雞新訓記 (4): 使用 Swagger 來自動產生可互動的 API 文件吧
Nswag: [Day09]使用Swagger自動建立清晰明瞭的REST API文件 - 我與 ASP.NET Core 的 30天
啟用 XML 註解,可提供未記載之公用類型與成員的偵錯資訊。
可以透過專案設定檔去忽略特定警告碼。也可以在特定類別上用pragma
去隱藏。
.csproj
檔案
.csproj
檔案<PropertyGroup>
內
專案
進去,選擇 XXX(專案名)屬性編譯器
,勾選 產生 XML 文件program.cs
配置 JWT 身份驗證服務錯誤訊息:
The entity type 'IdentityUserLogin<string>' requires a primary key to be defined. If you intend.
想法:
認為我有在模型類別中提供 [key]Id
問 GPT:
後來又出現,但把 id 移除也沒效果
解決方法:改在 context檔案內 on model creating 方法內設定以基類去做處理才能 Migration
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
因為希望可以依照上述users路由去設置功能,所以一開始就定好登入時以信箱去判斷是否已有信箱號碼,如果已有信箱號碼,則去驗證密碼是否正確,如果沒有這個信箱在資料庫內,則創建一個新帳號
後來考量到 Identity 功能可以實現密碼雜湊、身份驗證以及完整的資料關聯功能,所以想加入 Identity 相關功能做使用,但因為其本身的密碼驗證過於複雜(這部分可以透過 program.cs 設定去關掉),以及 Identity 是以用戶名(UserName)去做主要身份認證,也就是 UserName 不能重複也不能為空
這會造成無法透過同一路徑去實現登入及註冊功能,因為如果將用戶名設為信箱,則會在用戶需再次登入時得到用戶名重複的錯誤訊息
測試及看文件、參考資料花了一段時間後,暫且還是找不到可以同時滿足的解法,最後只能換個角度處理問題,想到以下兩個處理方法,最後選擇先以第二個方法去處理
1. 新增註冊路徑,就可以在註冊時處理 UserName,登入時就只需信箱密碼處理即可
2. 不使用 Identity 功能,手動處理密碼雜湊、資料庫關聯的功能
需要先存 使用者 再存 todo
但抓不到當前使用者 ID
原本要去解析 jwt 的 claimtype >> userid
但 claimtype 是字串(不是這個問題)
但不管怎麼存都無法成功,就是說存取順序問題