# [112]天方科技 ASP.net core 教育訓練 1120321(IIS版更、HTTP Status Code、Controllers Action、C#修飾詞補充) ## C#常用命名規則 **駝峰式大小寫** (建議,非必要,為了避免與C#原生關鍵字衝突) Pascal Case(大駝峰):定義class時,或是修飾詞為public的屬性/方法,外部使用範圍 ```csharp= public class SkyTek ``` Camel Case(小駝峰):定義區域變數,或者使用修飾詞為private/internal時,內部使用範圍 ```csharp= private class skyTek ``` 參考: [**駝峰式大小寫**](https://zh.wikipedia.org/zh-tw/%E9%A7%9D%E5%B3%B0%E5%BC%8F%E5%A4%A7%E5%B0%8F%E5%AF%AB) ## 憑證安裝地點 ### 搜尋mmc→開啟 ![](https://i.imgur.com/3UhHYEl.png) ### 檔案→新增/移除嵌入式管理單元 ![](https://i.imgur.com/Goy54ld.png) ### 憑證→新增→我的使用者帳戶→完成 ![](https://i.imgur.com/vYSfeku.png) ![](https://i.imgur.com/hGFQh8c.png) ![](https://i.imgur.com/GgrUx71.png) ### 主控台跟目錄→憑證→受信任的跟憑證授權單位→可看到當前帳戶所允許的憑證 ![](https://i.imgur.com/i6hNhJz.png) ## IIS發佈資料夾更新(版更) ### 在發佈資料夾修改設定檔 發佈資料夾內的appsettings.json以及web.config檔可被直接修改,但是儲存後,**IIS Server會自動重啟**,假如當下有用戶使用中,會被踢出Server ![](https://i.imgur.com/qXtuwub.png) ### 更新專案並發佈後,也可以指複製專案發佈資料夾內更新過的核心檔案,取代IIS發佈資料夾 ![](https://i.imgur.com/56IJVko.png) ### 複製時出現警告 雖然寫著權限警告,但是真實原因是,IIS Server一但有被使用過,應用程式集區就會執行,並鎖住核心檔案,造成更新失敗 ![](https://i.imgur.com/63PVyDq.png) ### 開啟IIS管理員→應用程式集區→點擊所使用的應用程式(SkyTekDNC)→進階設定 拉到最下方可以看到應用程式的設定 識別:IIS存取SQL Server使用的身分 閒置逾時:時限內沒有用戶使用應用程式,就執行動作,通常與預設Session存活時間一樣 閒置逾時動作:設定動作,預設Terminate(終止) ![](https://i.imgur.com/NDUrGb7.png) ![](https://i.imgur.com/N1j0enM.png) ### 假如沒有要修改設定,重啟應用程式 點擊停止→啟動 停止過後便會解鎖核心檔案,可以進行更新 一旦停止使用者一樣會被踢出 ![](https://i.imgur.com/ll5h895.png) ## 精簡IIS發佈資料夾檔案 ### 原始開發專案在產生發佈資料夾時,會產生大量正式執行時非必要的EF Core Tool/套件相關檔案 ![](https://i.imgur.com/tqEfay4.png) ![](https://i.imgur.com/dUQ98vF.png) ### 為了降低Server負擔,可以在相同設定下新增一個專案,不使用EF Core Tool,而是直接將開發完成的原始專案檔案複製,放入新專案中,如Controllers、Models資料夾和appsettings.json、Program.cs的設定 Demo專案→Edu專案 ![](https://i.imgur.com/wusqT2P.png) ![](https://i.imgur.com/0hZJZbI.png) ### 轉移後須修改namespace以及同步與原始專案的設定 ```csharp= //Controllers、Models namespace Demo.Controllers ↓ namespace Edu.Controllers ---------------------- namespace Demo.Models ↓ namespace Edu.Models ``` ```csharp= //appsettings.json "ConnectionStrings": { "edu": "Data Source=.;Initial Catalog=edu;Persist Security Info=True;TrustServerCertificate=true;User ID=sa;Password=localhost" } ``` ```csharp= //Program.cs builder.Services.AddDbContext<eduContext>( options => options.UseSqlServer(builder.Configuration.GetConnectionString("edu"))); builder.Services.AddControllers().AddJsonOptions(x => x.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles); ``` ![](https://i.imgur.com/7gfsN5I.png) ### 使用搜尋功能 在VS 按下Ctrl + H 可呼叫取代功能,在第一個輸入框輸入要搜尋的文字,或是選取文字後按下Ctrl + H 第二個視窗輸入取代文字,輸入框右側第一個按鈕為取代一筆,另一個是取代全部 下方下拉式選單可選擇搜尋/取代範圍 ![](https://i.imgur.com/1S7Ujzf.png) ![](https://i.imgur.com/1VdEQF8.png) ![](https://i.imgur.com/PU8tjdJ.png) ### 取代完後還需要自行安裝EF Core運作必要套件(原本是由EF Core Tool安裝) ![](https://i.imgur.com/6kqpOcw.png) ### 專案右鍵→管理方案的NuGet套件 ![](https://i.imgur.com/Kzh9i4K.png) ### 瀏覽並安裝套件 `Microsoft.EntityFrameworkCore.SqlServer` `Microsoft.EntityFrameworkCore.Tools` ![](https://i.imgur.com/T2PKPQV.png) ### 對新專案建置並且發佈→開啟發佈資料夾 少了不必要的套件後,發佈檔案大幅減少 ![](https://i.imgur.com/106GQB3.png) ![](https://i.imgur.com/6ViEaeo.png) ![](https://i.imgur.com/m4PligB.png) ## HTTP Status Code 表明一個 HTTP 要求是否已經被完成,常見到的狀態碼: **成功回應** >200 OK:請求成功 201 Created:請求成功且新的資源成功被創建,通常用於 POST 或一些 PUT 請求後的回應 204 No Content:此請求沒有要發送的內容 205 Reset Content:通知客戶端重置文件視圖,例如:清除表單內容、重置畫布狀態或刷新使用者介面 **用戶端錯誤** >400 Bad Request:伺服器因為收到無效語法,而無法理解請求 403 Forbidden:用戶端並無訪問權限,例如未被授權,所以伺服器拒絕給予應有的回應 404 Not Found:伺服器找不到請求的資源 418 I'm a teapot:用戶端錯誤碼表明了伺服器是個茶壺,所以拒絕煮咖啡 **伺服器端錯誤** >500 Internal Server Error:伺服器端發生未知或無法處理的錯誤 504 Gateway Timeout:伺服器作為閘道器時無法及時得到回應 參考: [**HTTP狀態碼**](https://developer.mozilla.org/zh-TW/docs/Web/HTTP/Status) ## Controllers Action Controllers在一開始建置好時,已經帶有基本查詢、新增、修改、刪除的功能,可以使用Swagger 或者 Postman進行測試 ![](https://i.imgur.com/7zJ9fc6.png) Controllers將語法轉為SQL指令,在使用VS執行Swagger時會出現Server,裡面會顯示執行該功能時產生的SQL語法 ![](https://i.imgur.com/y1MdNFo.png) 或是在VS執行時的輸出視窗也可以看到 ![](https://i.imgur.com/eM1wfm6.png) ### POST Post預設為新增,需要傳入Json格式的body,可以先在Swagger使用Get取得格式 ![](https://i.imgur.com/JqjHtDD.png) 然後在Post放入body格式,點擊Execute,如果有未被寫入的欄位,值為**null** ![](https://i.imgur.com/H2QBbUJ.png) 執行結果 ![](https://i.imgur.com/cy3LY57.png) ```csharp= //studentController.cs [HttpPost] public async Task<ActionResult<s30_student>> Posts30_student(s30_student s30_student)//收到json { if (_context.s30_student == null) { return Problem("Entity set 'eduContext.s30_student' is null."); } _context.s30_student.Add(s30_student);//在DbSet(s30_student)新增json,由DbSet紀錄CRUD異動 try { await _context.SaveChangesAsync();//掃描DbSet異動,連接資料庫,產生相應指令 } catch (DbUpdateException)//資料庫連線失敗,攔截例外資訊 { if (s30_studentExists(s30_student.std_key))//檢查是否Key值有衝突 { return Conflict(); } else { throw; } } //成功的情況下呼叫CreatedAtAction([HttpGet{id}]函式, new { [HttpGet{id}]函式參數(id) = [HttpPost]函式參數(json).Key值 }, [HttpPost]函式參數) return CreatedAtAction("Gets30_student", new { id = s30_student.std_key }, s30_student); } ``` ### Put Put是更新,需要傳入id以及Json格式的body,可以先在Swagger使用Get取得格式,需注意Put沒有辦法局部更新,只能全部欄位更新,沒寫到的欄位變成**null**值 ![](https://i.imgur.com/kxk5ERe.png) 執行結果 ![](https://i.imgur.com/OFv0DD0.png) ```csharp= //studentController.cs [HttpPut("{id}")] public async Task<IActionResult> Puts30_student(decimal id, s30_student s30_student)//收到url id和json body { if (id != s30_student.std_key) { return BadRequest(); } _context.Entry(s30_student).State = EntityState.Modified;//將json資料加入DbSet,並將狀態改為'修改' try { await _context.SaveChangesAsync();//掃描DbSet異動,連接資料庫,產生相應指令 } catch (DbUpdateConcurrencyException) { if (!s30_studentExists(id)) { return NotFound(); } else { throw; } } //更新成功後,只有狀態碼204,不回任何內容,也可以修改成其他回應方式 return NoContent(); } ``` ### Delete Delete是刪除,只需傳入id ![](https://i.imgur.com/39bSDwc.png) 執行結果 ![](https://i.imgur.com/07fGT2T.png) ```csharp= [HttpDelete("{id}")] public async Task<IActionResult> Deletes30_student(decimal id)//收到url所帶的值 { if (_context.s30_student == null)//檢查DB Moudel是否存在 { return NotFound(); } var s30_student = await _context.s30_student.FindAsync(id);//以id取得該筆資料 if (s30_student == null)//檢查是否有找到資料 { return NotFound(); } _context.s30_student.Remove(s30_student);//使用Remove語法刪除該筆資料 await _context.SaveChangesAsync();//掃描DbSet異動,連接資料庫,產生相應指令 //更新成功後,只有狀態碼204,不回任何內容,也可以修改成其他回應方式 return NoContent(); } ``` ### .NET 7.0版本 可使用DbSet.Execute...<資料集合>語法進行批次修改、刪除 ![](https://i.imgur.com/hfIHIwq.png) ## Postman ### 用來測試API的工具 [**Postman下載**](https://www.postman.com/downloads/) ![](https://i.imgur.com/k4JKO3g.png) ### 可以選擇方法和傳值方式,點擊Send可向Http發送請求,下方會出現請求結果 ![](https://i.imgur.com/qmbwm5H.png) ### Get 方法預設為Get,輸入API url,點擊Send ![](https://i.imgur.com/HDtdoqI.png) ### Get("{id}") API url + /id,取得單筆資料 ![](https://i.imgur.com/QIwKy2h.png) ### Post 方法改為Post,輸入API url 傳值方式選擇body,post請求類型選擇raw(任意格式文字),最右側下拉式選單選擇使用json格式 下方寫入要新增的json資料 ![](https://i.imgur.com/NIRBTkf.png) ### Put("{id}") 方法改為Put,輸入API url + /id 下方傳值一樣使用body→raw→json格式 下方寫入要更新的json資料 ![](https://i.imgur.com/CE6No50.png) ### Delete("{id}") 方法改為Delete,輸入API url + /id,刪除該筆資料 ![](https://i.imgur.com/RmcGVoP.png) ## C#修飾詞補充 async:非同步 await:呼叫非同步方法,使程式不會停止在這裡,等到非同步工作完成,在跳回這裡繼續執行,需搭配async Task:非同步工作物件,類似Thread 執行緒類別 <>:泛型 IEnumerable:此資料集合中的成員可以被列舉,只能回傳資料,不包括Http code IActionResult:可以回傳HTTP Status Code,使用`Ok()`、`NotFound()`等方法 ActionResult:可以回傳HTTP Status Code,有可以指定回傳多種型別 參考: [**ASP.NET Core Web API 中的控制器動作傳回類型**](https://learn.microsoft.com/zh-tw/aspnet/core/web-api/action-return-types?view=aspnetcore-7.0) [**ASP.NET Core web API 中的回傳型別**](https://waynecheng.coderbridge.io/2021/02/18/Actionresult/) ```csharp= public async Task<ActionResult<IEnumerable<s30_student>>> Gets30_student() { if (_context.s30_student == null) { return NotFound(); } return await _context.s30_student.Include(a => a.cls).ToListAsync(); } ```