Complete guide to building an app with .Net Core and React

解釋Walking skeleton是什麼

這是烏的咪的一堂課,一邊聽課一邊做點筆記。
Complete guide to building an app with .Net Core and React


1-2教安裝.NET SDK

Creating the .Net projects and reference

Windows的話不要在system32裡面建,要在User folder裡建

dotnet –info
列出有安裝的SDK
dotnet new list 列出可以安裝的

專案的依賴關係



mkdir Reactivities
之後移到這個資料夾
dotnet -h
可以列出可以用的指令
dotnet new -h

先建好專案資料夾Reactivities
然後cd到裡面,建一個sln檔案當作專案的container,所以打指令:
dotnet new sln
之後還要建其它的專案。分成四種

API
Application (包含所有的business logic)
Domain (包含domain entities)
Persistence (負責和database溝通)

所以打以下指令:
dotnet new classlib -n Domain
dotnet new classlib -n Application
dotnet new classlib -n Persistence
dotnet new webapi -n API
-n表示它會開資料夾

建起來非常的快喔


dotnet sln list
打這個可以知道這個sln有哪些專案

建完還要給它加到sln。sln只有一個,是集中包這些class lib的咚咚
dotnet sln add API/API.csproj ….
全部加完之後打dotnet sln list檢查

之後要加reference,因為API有依賴Application,
所以移到API的資料夾,打
dotnet add reference ../Application (要cd到想加reference的資料夾

接著又到Application資料夾,因為它依賴了Domain和Persistence,所以加一下
Persistence也依賴了Domain,給它加一下。

然後作者說
/bin
/obj
這兩個資料夾基本上不會去跟它互動,就像前端的build,所以他在VS Code就隱藏起來了。

都加完之後,就可以從API專案開始
dotnet run
dotnet watch run
用第二個指令,它可以偵測你的程式有沒有變動,有的話會重新restart、rebuild

在RUN專案的時候,它其實是跑Program.cs裡面的Main方法
Our API project needs to be hosted.
因為打內有一個web server叫Kestrel,所以我們的API就會在上面跑。用它來HOST我們的API。
Kestrel web server implementation in ASP.NET Core

另外作者還教說要改這邊:
appsettings.Development.json

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Information",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  }
}

把Microsoft改成Information,在log的地方會有比較多資訊。
(章節:Reviewing the project files and startup

Summary of Key Points:

  1. File Precedence:
    • appsettings.development.json takes precedence over appsettings.json.
  2. Merging Configuration:
    • Settings from appsettings.{Environment}.json override conflicting settings from appsettings.json.
    • In your case, appsettings.development.json overrides the logging settings and TokenKey from appsettings.json.
  3. Checking Environment Mode:
    • launchSettings.json: Found in the Properties folder, it defines the ASPNETCORE_ENVIRONMENT for different profiles.

這裡是一個construct,它inject了configuration

然後這邊的程式代表這讓我們可以讀到我們在這些設定檔(例如JSON檔)裡面的設定。

ConfigureServices這是一個Dependency injection container

這個叫做Dependency injection,在這裡有這個概念的解釋。
What is IoC Container or DI Container

打prop + tab可以寫Auto-implemented properties

之後作者快速的帶過 postman,說他有提供一些collocations 讓我們import


Section 4: Creating a CRUD application using the CQRS + Mediator pattern

CQRS常常看到,可是沒有特別去花時間理解,上次看過又忘了,現在再來複習一次

DB只有一個的時候,CQRS的優勢不太明顯
二個DB,不同用途的時候,CQRS的優勢就比較明顯

Implementing CQRS in ASP.NET Core Web API with MediatR (youtube.com)

Application跟API層之間需要有一個Mediator,讓Application可以跟API說「我正在處理資料喔」
Application專案裡面含Command, Query,command 可以 do something with an entity or an object,
and a query handler when we want to get data from our API.
List.cs就是query handler


Creating a domain entity
開始規劃自己的domain entity。
這個章節教我們用Guid來當ID用,然後ID要取叫ID,是因為之後要用EF。不要取theID…
Guid它可以在server side產生,也可以在client side 產生,在client side 產生就不用等資料庫了。

Adding an Entity Framework Db Context
在Persistence專案安裝了Microsoft.EntityFrameworkCore.SqlLite 5.0.3
講師說記得要安裝跟runtime一樣的版本(假設是5.0.3就安裝5.0.3

要用SQL Server就安裝這個 Microsoft.EntityFrameworkCore.SqlServer ,加到persistence
在Persistence資料夾建一個class叫DataContext,繼承DbContext
還要安裝Microsoft.EntityFrameworkCore.Design,加到API,EF要用的



提到Mediator Pattern,查了一下是什麼意思,讀了一下又花惹好多時間,還去查了一下UML了解那個線圖是什麼意思,有好多種,有菱形什麼的…。

然後加了connection string,就開始要ef大遷移了!它就是幫我們建立資料庫。

安裝Microsoft.EntityFrameworkCore.Design到API這個專案

在應用開式開始跑的時候,檢查有沒有DB,如果沒有,就建造一個

後來我改用sql server…
如果要改用其它的,參考Section22的Switching to PostGreSQL這一篇
首先要刪除Migrations這個資料夾,安裝想要用的Package
然後打以下這個指令
dotnet ef migrations add InitailCreate -s API -p Persistence

接下來還要加scope才會幫忙建table喔!
例如以下代碼,加在Program.cs

using var scope = app.Services.CreateScope();
var services = scope.ServiceProvider;

try
{
var context = services.GetRequiredService<DataContext>();
await context.Database.MigrateAsync();

}
catch (Exception e)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(e, "An error occurred during migration");
}

加這個你在本地run,它就會幫你遠端建好資料庫惹www



之前的筆記:然後再佈署到我的FTP,發現成功轉換惹^O^ (之前失敗過,可能是沒有刪除資料夾就直接下指令了,Sqlite的跟SQL Server的不能混用)
dotnet ef migrations add IdentityAdded -p Persistence -s API
之後為了加註冊功能,再做一次migratioins

大概時隔一年?再來加一個Table看看



另外在2-13卡關中,因為我要用.NET6的寫法
後來發現講師在最後面有教!太好了
另外在建DB的時候一直提到
Service Locator Pattern
原來DbContext是一個services

後來開始寫API溜~先來建一個Controller,記得要繼承ControllerBase而不是Controller,原因在這裡有寫:
Create web APIs with ASP.NET Core
因為ControllerBase是純API在用,Controller則是可以return view的。

之後開始提到MediatR,對我來說開始有點複雜了起來。
Section 4 Creating our first query handler

在Application專案加了Create、Edit、Details、List

之後寫到Edit邏輯的API,需要安裝
AutoMapper.Extensions.Microsoft.DependencyInjection
到Application專案

這個套件還蠻好用的耶

之後要做一些參數的驗證了。
使用一個套件叫

FluentValidation.AspNetCore

安裝到Application。可以來看看它的文件
不過作者說這個文件有點過時了,它現在已經支援.NET 7了。
另外他還說文件上不建議用Automatic validation,但作者覺得不對,Automatic validation有支援Minimal APIs,而且也不會難Debug。(可能現在開發的案子比較不複雜)

Task<ActionResult<Activity>>
改成Task<IActionResult>
因為IActionResult可以收HTTP response

Section 12. Identity
接下來要做註冊的功能

In the field of programming, a data transfer object is just an object to carry data between processes.
這篇講到DTO

Creating a token service

If there’s something that you’re creating that doesn’t involve data access, then it’s not a repository.
接下來開了Services資料夾,建一個token service檔案,要為每個user產生token。
token裡面可以有claim
Claims are just something that a user claims about themsleves.

注意事項:
因為我是看教學一邊寫這個專案,然後教學的專案沒有enable nullable,但是我的專案有,所以在定義class model的時候要特別小心,例如這個user

using Microsoft.AspNetCore.Identity;

namespace Domain;

public class AppUser : IdentityUser
{
    public string DisplayName { get; set; }
    public string Bio { get; set; } = string.Empty;
}

我另外定義了它的預設值,這樣我在註冊會員的時候才可以註冊…
不然就會噴錯不能註冊了。是有點想要改成nullable,但我的Migration已經create了

章節【The API controller and using postman】有提到
string在.NET本來就是nullable的,加了enable nullable就會變成required, which means strings are required unless we explicitly say that they are optional. 加了 nullable flag 反而更麻煩

如果enable nullable了,And if I take away this question mark, then this summary is going to display a warning saying, Hey, this must contain a null and non null value when exiting the constructor.

This basically says that all strings are now required unless we do something to tell it otherwise.

Default Value for Reference Types:

  • When nullable reference types are not enabled, the default value for uninitialized reference type properties (like string) is null.

Nullable Reference Types Disabled:

  • The compiler does not enforce initialization of non-nullable reference type properties, allowing them to default to null.

Property Initialization:

  • Properties like DisplayName, Email, and UserName are explicitly set during the registration process, ensuring they are not null.
  • Optional properties like Bio can remain unset and default to null.

成功的feed user之後,測API加上 [Authorize] 就會回401,需要帶token才能打。

Storing secrets in development

然後講師開始看這篇文章 Safe storage of app secrets in development in ASP.NET Core
裡面有提到 Production secrets shouldn’t be used for development or test. Secrets shouldn’t be deployed with the app. Instead, production secrets should be accessed through a controlled means like environment variables or Azure Key Vault. 
然後講師說雖然機密的資訊用AppSetting.json裡的是可以的,可是把它放在伺服器算是不好的實作。

在development環境上可以使用Secret Manager來幫忙管理環境變數。不過因為只是development環境,講師覺得先用JSON檔裡的就好了,因為這也不是什麼機密資訊。(如果是third party API Key就不能這樣搞)

接下來教到 auth policy,要讓所有的API都限制要登入才能讀,這對我來說目前還不太需要…所以就先看看就好了吧。

※因為我心急想看看在線上會長怎麼樣子,所以開發一半就部署到線上去了,然後資料庫裡的table只有一開始的一個,之後EF新增的沒有,所以我查了一下要怎麼讓EF可以顧到Production上…查下來之後看來是直接叫EF產生SQL,直接到DB徒手下SQL了這個方法。

Applying Migrations
參考這篇,記得最後加個 -o filename.sql 就會產生SQL到指定的檔案(當然也要記得自己之前是在哪個點上…)

目前production的進度到IdentityAdded,後來更新到AddMangaTable,目前最新是AddItemsVersionTwo

記得要在API資料夾跑這個指令
run query前,把每一行GO刪掉,因為那是SSMS用的

做完馬上佈到production上,發現原本的API變成500 server error
先刪掉obj、bin資料夾,重新build solution,再按publish至local folder,然後上sharkAsp
把我的website關掉、restart pool,然後用FTP把publish資料夾的東西通通丟上去(包含runtime)
這樣嘗試之後恢復正常了,不確定是什麼問題。

===============================================================

在production上發現錯誤【HTTP Error 502.5 – Process Failure】
後來去看log,發現說我有一個套件沒有安裝,我檢查了一下確實是有安裝的,就刪掉bin和obj,重新restore,後來再build solution,build完後上傳到FTP去。
(在本機還有重裝一下.NET7 SDK,不確定之前是不是被我刪掉。還有安裝IIS Express,為了要run API,rider run API iis express的話port會是44xxx,只run另一個API就是 7000)


build完solution後,按publish,結果發現FTP禁止覆蓋一些檔案,例如 API.dll,用Rider也是有一樣的問題。
寫信去問客服,他竟然不久過後就回我了。

照著做就可以刪除了。真的是好客服捏!

複習一下加一個data model,做CURD的方法:

  1. 在Domain加上想要的class(記得要先加到git, 不然之後IDE會找不到…)
  2. 在Seed.cs塞一下資料
  3. 在資料庫下SQL同步一下
    dotnet ef migrations add 最新的 -p Persistence -s API(跑這行要在最外層資料夾跑)
    dotnet ef migrations script 最新的 -o test.sql (跑這行要在API資料夾跑) ※不能叫insert.sql,會塞不到資料
  4. 在Persistence的DataContext加上DbSet
  5. 加controller和在application專案加上List, Delete, Edit, Validator…
  6. 在MappingProfiles也要加Map

單純只想要改schema的話超級無敵簡單,只要

增加了ImageUrl


1. 修改class
2. dotnet ef migrations add 最新的 -p Persistence -s API
3. 專案本地直接run起來
上去看一下就發現我的table的schema改惹,哇哈哈