---
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
```