--- tags: Programing, C#, .NetCore, VSCode --- # 在VS code環境撰寫.NetCore [TOC] # 環境設定 ## 詳細請見[官網教學](https://docs.microsoft.com/zh-tw/dotnet/core/tutorials/with-visual-studio-code) # 建立.NetCore專案 ## 在目標資料夾CLI輸入 ### 建立專案 ```bash= dotnet new console # 當前目錄建立專案 # 或是 dotnet new console [project-name] # 在當前目錄建立資料夾 [project-name] ``` ### 執行專案 ```bash= dotnet run # 當前目錄下專案 #或是 dotnet run --project [project-name] # 開啟 [project-name] 此目錄 ``` 接著在VS Code內安裝C# Extension套件後 便可以進行Debug模式了 若要執行Release模式,可以執行 ```bash= dotnet run --configuration Release ``` Debug跟Release兩個模式的差異在於 --- ### Debug模式 不會對程式進行優化,以及提供break point的方式 讓使用者可以逐步、修改變數來進行測試 --- ### Release模式 則是會進行程序的最佳化 使程式能跑得更快、空間更小 潛在問題則是可能導致Race Condition --- # 發佈應用程式 執行以下指令來產生publish後結果 ```bash= dotnet publish --configuration Release ``` 在專案目錄底下的`bin/Release/netcoreapp3.1`分別有四個重要的檔案 ## [專案名稱].deps.json 這個檔案為應用程式runtime的參考套件檔 如果有應用其他 `dll` 或 `.net core components` ## [專案名稱].dll 這個檔案為可執行的動態連結函式庫 可透過以下指令來執行 ```bash= dotnet [專案名稱].dll ``` ## [專案名稱].exe 這個檔案為應用程式的可執行檔 不過某些作業系統不支援 ex. mac ## [專案名稱].pdb 這是debug的象徵檔(?) 當要對publich後的應用程式debug時便會需要用到 ## [專案名稱].runtimeconfig.json 這是應用程式的run-time設定檔 它會識別目前執行的 .NET Core版本 我們可以對它增加設定 詳情參考 [.NET Core run-time時的設定檔](https://docs.microsoft.com/zh-tw/dotnet/core/run-time-config/#runtimeconfigjson) # 執行方法 ## 詳情參見[官網教學](https://docs.microsoft.com/zh-tw/dotnet/core/tutorials/publishing-with-visual-studio-code#run-the-published-app) # 建立程式庫 ```bash= dotnet new sln ``` 依序建立 `Library` 、 `Console` 建立方式為:在專案目錄底下 ## 建立 Library ```bash= dotnet new classlib -o [LibraryName] dotnet sln add [LibraryName]/[LibraryName].csproj ``` 接著修改 `[LibraryName].csproj` 以下為範例 ```C#= using System; namespace UtilityLibraries { public static class StringLibrary { public static bool StartsWithUpper(this string str) { if (string.IsNullOrWhiteSpace(str)) return false; char ch = str[0]; return char.IsUpper(ch); } } } ``` 接著將此函式庫 build 起來 ```bash= dotnet build ``` libary的部分目前便完成了 ## 建立 Console 接下來建立Console應用程式 ```bash= dotnet new console -o [consoleAppName] dotnet sln add [consoleAppName]/[consoleAppName].csproj ``` 建立好Template後 便可以修改Progarm.cs 下面的程式碼著重在載入函式庫的部分 用的是 `[LibraryName]/[LibraryName].csproj` 內的 `namespace` ```C#= using System; using UtilityLibraries; // 重點在此 class Program { static void Main(string[] args) { //Todo //在此寫執行程式 } } ``` 到此 Console Application的部分也完成了 ## 加入專案參考 接下來要把Console Application所引用到的外部函式庫給加入參考 指令如下 ```bash= dotnet add [consoleAppName]/[consoleAppName].csproj reference [LibraryName]/[LibraryName].csproj ``` ## 執行應用程式 如標題 而指令如下= ```bash= dotnet run --project [consoleAppName]/[consoleAppName].csproj ``` # 對程式庫進行單元測試 ## 建立單元測試專案 首先得先在原先專案上新增單元測試專案 指令如下 ```bash= dotnet new mstest -o StringLibraryTest ``` 執行後便建立起後續需要用的專案了 接下來這裡解釋一下裡頭的`UnitTest1.cs` ```C#= using Microsoft.VisualStudio.TestTools.UnitTesting; namespace StringLibraryTest { [TestClass] public class UnitTest1 { [TestMethod] public void TestMethod1() { } } } ``` ## Microsoft.VisualStudio.TestTools.UnitTesting 提供用來單元測試的型別 ## TestClassAttribute 運用 [TestClass] 去定義 UnitTest1這個Class ## TestMethodttribute 運用 [TestMethod] 去定義 UnitMethod1這個Class ## 將測試專案加入專案 將單元測試的專案加入整個專案內 ```bash= dotnet sln add StringLibraryTest/StringLibraryTest.csproj ``` ## 對測試專案加入參考 在測試專案加入呼叫的函式庫的參考 ```bash= dotnet add [UnitTest]/[UnitTest].csproj reference [LibraryName]/[LibraryName].csproj ``` ## 加入並執行單元測試的方法 在測試傳案裡透過呼叫Assert內的函式來判斷測試對或錯 ex. `Assert.AreEqual`、`Assert.AreSame` ... 透過這些函式可以產生出測試結果 以下為範例 ```C#= using System; using Microsoft.VisualStudio.TestTools.UnitTesting; using UtilityLibraries; namespace StringLibraryTest { [TestClass] public class UnitTest1 { [TestMethod] public void TestStartsWithUpper() { // Tests that we expect to return true. string[] words = { "Alphabet", "Zebra", "ABC", "Αθήνα", "Москва" }; foreach (var word in words) { bool result = word.StartsWithUpper(); Assert.IsTrue(result, String.Format("Expected for '{0}': true; Actual: {1}", word, result)); } } [TestMethod] public void TestDoesNotStartWithUpper() { // Tests that we expect to return false. string[] words = { "alphabet", "zebra", "abc", "αυτοκινητοβιομηχανία", "государство", "1234", ".", ";", " " }; foreach (var word in words) { bool result = word.StartsWithUpper(); Assert.IsFalse(result, String.Format("Expected for '{0}': false; Actual: {1}", word, result)); } } [TestMethod] public void DirectCallWithNullOrEmpty() { // Tests that we expect to return false. string[] words = { string.Empty, null }; foreach (var word in words) { bool result = StringLibrary.StartsWithUpper(word); Assert.IsFalse(result, String.Format("Expected for '{0}': false; Actual: {1}", word == null ? "<null>" : word, result)); } } } } ``` 篇幅雖然很長 但著重的點在最後Assert的呼叫以及準備資料的設定 在修改完之後 執行以下指令來跑單元測試 ```bash= dotnet test [UnitTestLibrary]/[UnitTestLibrary].csproj ``` 以下測試為單元測試結果成功的輸出範例 ```tiddlywiki= Starting test execution, please wait... A total of 1 test files matched the specified pattern. Test Run Successful. Total tests: 3 Passed: 3 Total time: 5.1116 Seconds ``` 以下測試為單元測試結果失敗的輸出範例 ```tiddlywiki= Starting test execution, please wait... A total of 1 test files matched the specified pattern. X TestDoesNotStartWithUpper [283ms] Error Message: Assert.IsFalse failed. Expected for 'Error': false; Actual: True Stack Trace: at StringLibraryTest.UnitTest1.TestDoesNotStartWithUpper() in C:\ Projects\ClassLibraryProjects\StringLibraryTest\UnitTest1.cs:line 33 Test Run Failed. Total tests: 3 Passed: 2 Failed: 1 Total time: 1.7825 Seconds ``` ## 測試發行版本程式庫 執行 ```bash= dotnet test [UnitTestLibrary]/[UnitTestLibrary].csproj --configuration Release ``` ## 偵錯測試 在VS code的畫面中 會有`Run All Test`這個選項(在範例的7行跟8行之間) 如果看不到請重整畫面(Reload Window) 在VS Code重整頁面預設按鍵為`Ctrl + R` # 建立Web API ## 建立 WebAPI 專案 首先先建立Web API專案 接著在專案內加入需要的NuGet套件 ```bash= dotnet new webapi -o TodoApi cd TodoApi dotnet add package Microsoft.EntityFrameworkCore.SqlServer dotnet add package Microsoft.EntityFrameworkCore.InMemory code -r ../TodoApi ``` 這樣便建立了 WebAPI 的雛型了 ## 測試API功能 在上面我們建立好的WebAPI可以透過輸入按鍵Ctrl + F5來看效果 執行之後開啟`https://localhost:5001/WeatherForecast` 可以看到執行結果為回傳一個Json格式 ## 新增模型類型 在這裡模型指的是這個app管理的資料 以下為範例 首先 新增資料夾名稱為 `Models` 接下來新增`TodoItem`.cs 到Models並且撰寫下面的程式碼 ```C#= namespace TodoApi.Models { public class TodoItem { public long Id {get; set;} public string Name{get; set;} public bool IsComplete {get; set;} } } ``` 雖然模型類別可以到處放 但習慣上我們會將它放置在Models內以便管理 ## 新增資料庫內容 在 `Models` 新增`TodoContext.cs`這個類別 並且撰寫以下程式碼 ```C#= using Microsoft.EntityFrameworkCore; namespace TodoApi.Models { public class TodoContext : DbContext { public TodoContext(DbContextOptions<TodoContext> options) : base(options) { } public DbSet<TodoItem> TodoItems { get; set; } } } ``` ## 登錄資料庫內容 在ASP.NET Core許多服務必須註冊在dependency injection (DI) 容器上 像是上面提及的DB context 容器(Container)提供服務給這些controller們 接下來更新Startup.cs成以下這樣 ```C#= // Unused usings removed using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.EntityFrameworkCore; using TodoApi.Models; namespace TodoApi { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services) { services.AddDbContext<TodoContext>(opt => opt.UseInMemoryDatabase("TodoList")); services.AddControllers(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseHttpsRedirection(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); } } } ``` 在複製貼上之前說明一下行為 首先移除底下未用到的函式庫 接下來加入DB Context到DI container中 最後是指定DB Context將使用在in-memory資料庫 ## 建置控制器(Controller) 執行以下指令建置控制器 ```bash= dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design dotnet add oackage Microsoft.EntityFrameworkCore.Desion dotnet tool install --global dotnet-aspnet-codegenerator dotnet tool update -g dotnet-aspnet-codegenerator dotnet aspnet-codegenerator controller -name TodoItemsController --async -api -m TodoItem -dc TodoContext -outDir Controllers ```