本來我還想介紹以下VSCode或者donet core,但是發現都是廢話,沒有必要,大家如果對這個不了解可以直接google這兩個關鍵字,或者也根本不會看我這邊文章。
好直接進入主題了,本文的前提條件:
- 已經安裝好了.NET Core SDK
- 已經安裝了VSCode
0x00. 磨刀不誤砍柴工
使用VSCode編寫dotnet core項目除了其 默認的功能外,我推薦還要安裝一些非常有特色,並且有用的擴展,正是因為VSCode的插件機制,才讓它變得更加強大,滿足我們各式各樣的需求
C#語言擴展: https://marketplace.visualstudio.com/items?itemName=ms-vscode.csharp
這個是使用VSCode編寫C#代碼必須的,安裝之后在默認打開.cs文件時 還會自動下載調試器等(不過過程可能比較慢,在牆外的原因)
[C# XML注釋]: https://marketplace.visualstudio.com/items?itemName=k--kato.docomment
這個可以插件可以快速的幫你添加注釋,選擇安裝吧
[C# Extensions]: https://marketplace.visualstudio.com/items?itemName=jchannon.csharpextensions
這個插件,強烈推薦,可以幫你在建立文件的時候初始化文件內容包括對應的命名空間等
還有一些其他輔助類的,比如EditorConfig,Guildes,One Dark Theme,Project Manager ,Setting Sync等。
0x01. 新建多項目解決方案
打開命令行工具,在命令行工具中輸入:
$:> dotnet new sln -o vscode_tutorial //在當前目錄下 創建名為vscode_tutorial
以上命令使用dotnet sdk,新建一個解決方案文件,你可以不用命令行手動創建,但是使用dotnet new
可以更加方便的創建dotnet core相關的項目. 順便提一下使用dotnet new 命令可以新建類庫項目,控制台項目,網站項目等等,詳細使用可以使用dotnet help new
命令來查看,如下圖所示:
建完解決方案我們要來建立項目了,包括一個控制台項目,一個類庫項目和一個單元測試項目
首先建立一個公共的類庫項目用於存放我們的業務方法(假設我們在做一個真實的項目)
$:> dotnet new classlib -o VSCodeTutorial.Common //在當前目錄下新建類庫項目VSCodeTutorial.Common
$:> dotnet sln add VSCodeTutorial.Common/VSCodeTutorial.Common.csproj //將項目添加到解決方案中
通過同樣的方式,我們建立好控制台項目和單元測試項目
$:> dotnet new console -o VSCodeTutorial.ConsoleApp
$:> dotnet sln add VSCodeTutorial.ConsoleApp/VSCodeTutorial.ConsoleApp.csproj
$:> dotnet new xunit -o VSCodeTutorial.UnitTest
$:> dotnet sln add VSCodeTutorail.UnitTest/VSCodeTutorial.UnitTest.csproj
這里要注意控制的模板名稱叫console
而單元測試我們使用xunit
這個時候我們的項目結構已經建立完成了,我們用VsCode來打開當前目錄來看看完成的項目結構吧,如下圖所示
0x02. 添加項目間的依賴關系
使用VsCode打開項目文件VSCodeTutorial.ConsoleApp.csproj,在其中添加對Common項目的引用
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>
<!--添加項目引用-->
<ItemGroup>
<ProjectReference Include="..\VSCodeTutorial.Common\VSCodeTutorial.Common.csproj" />
</ItemGroup>
</Project>
同樣打開VSCodeTutorial.UnitTest.csproj項目文件,在其中添加對Common項目的引用
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>
<!--nuget 上的類庫引用-->
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0" />
<PackageReference Include="xunit" Version="2.2.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
</ItemGroup>
<!--本地項目引用-->
<ItemGroup>
<ProjectReference Include="..\VSCodeTutorial.Common\VSCodeTutorial.Common.csproj" />
</ItemGroup>
</Project>
和上面的那個項目不同,這里有一些額外的依賴,這里可以剛好了解下,如果添加nuget中包的依賴,只需像上面一樣使用PackageReference
並填入類庫名稱和版本號即可
添加完依賴后,我們在根目錄下使用dotnet restore
來初始化以下,也可以再用dotnet build
命令來嘗試編譯一下先
項目依賴關系如圖2:
0x03. 開始編寫代碼
這個項目的整體需求:我需要打開一個控制台程序,運行時需要用戶輸入一個小於50的整數,控制台接收到這個數字后計算出這個數字的階乘,並把結果輸出到控制台上。
經過簡單的思考,我決定把階乘的實現放到Common項目中,並且對其進行單元測試,測試的代碼則放到UnitTest項目中
首先我們把之前生成的項目中不需要的文件給刪除掉VsCodeTutorial.Common中的Class1.cs和VSCodeTutorial.UnitTest中的UnitTest1.cs ,當然你也可以留着。
第一步,我們在VsCodeTutorial.Common
項目中新建文件MathHelper.cs
並在文件中添加如下代碼,實現我們的階乘,代碼比較簡單就不詳述了。
namespace VSCodeTutorial.Common
{
public class MathHelper
{
/// <summary>
/// 階乘,本例中暫不考慮 溢出的問題哦 Factorial(n) = n*(n-1)*(n-2)...*1;
/// </summary>
/// <param name="n">輸入參數n</param>
/// <returns></returns>
public static int Factorial(int n){
if(n <=0 ){
throw new System.ArgumentOutOfRangeException("n","參數錯誤,不能小於等於零");
}
if(n == 1){
return 1;
}
return n*Factorial(n-1);
}
}
}
第二步,我們要來測試這個代碼,看看是否達到了我們的目標,在VSCodeTutorial.UnitTest
項目中新建文件MathHelpTest.cs
向文件中添加測試Factorial
函數的方法,如下所示:
using System;
using VSCodeTutorial.Common;
using Xunit;
namespace VSCodeTutorial.UnitTest
{
public class MathHelperTest
{
[Fact]
public void TestFactorial()
{
//先測試一下邊界的情況
int zero = 0 ;
var exception = Assert.Throws<ArgumentOutOfRangeException>(() => MathHelper.Factorial(zero));
int one = 1;
var oneResult = MathHelper.Factorial(one);
Assert.Equal(1, oneResult);
//再測一下正常的情況
int five = 5;
var fiveResult = MathHelper.Factorial(five);
Assert.Equal(5*4*3*2*1, fiveResult);
int ten = 10;
var tenResult = MathHelper.Factorial(ten);
Assert.Equal(10*9*8*7*6*5*4*3*2*1, tenResult);
}
}
}
0x04 使用命令行運行單元測試
在使用配置VSCode之前 我還是建議大家先使用命令行來運行一下單元測試,這有利於更好的理解配置內容。
在根目錄下輸入命令:dotnet test ./VSCodeTutorial.UnitTest/VSCodeTutorial.UnitTest.csproj
查看運行結果:
很差勁會出現編碼錯誤,而且這個錯誤暫時還沒有辦法解決..但是我猜單元測試通過了,這個問題相信在后續的版本中肯定會得到解決,事實上在Console項目中是可以解決輸出亂碼問題的。不過可喜的是在VSCode中運行單元測試是沒有亂碼的問題的😁。
0x05 使用VSCode 運行單元測試
首先當你打開項目的時候,VSCode 可能已經建議你配置一下相關的內容,如下圖所示:
選擇Yes, 會幫你新建這個一個目錄和兩個文件,luanch.json是用來執行調試程序的配置,而tasks.json則是配置各種任務的,其中運行單元測試就是一種任務。
首先我們打開tasks.json
,默認已經添加好了一個任務,如下所示
{
"version": "0.1.0",
"command": "dotnet", //全局命令,即所有的任務都使用這個命令,也可以在各個任務中設置
"isShellCommand": true,
"args": [],
"tasks": [
{
"taskName": "build", //任務名稱 當設置了主的command 之后這個taskName也會作為一個命令參數
"args": [
"${workspaceRoot}\\VSCodeTutorial.ConsoleApp\\VSCodeTutorial.ConsoleApp.csproj"
],
"isBuildCommand": true, //一個解決方案只能設置一個編譯任務,多設置了也是白搭,當然也能執行,只是不能利用快捷方式運行了
"problemMatcher": "$msCompile"//C#項目的problemMatcher
}
]
}
默認使用了全局命令行,這樣可以在任務中省去配置dotnet命令,但是如果你的解決方案中包括多個項目需要不同的命令行編譯方式,如果前端網站使用grunt打包資源,那么頂部應該留空,而在各個子任務中配置command。還有如果存在多個編譯項目時(如客戶端和服務端在一個解決方案時),也應該把command配置在子任務中,並設置個性化的taskName以便區別,所以我推薦把command設置在任務中,下面我們修改一下以上代碼,並添加一個運行單元測試的人。
{
"version": "0.1.0",
"isShellCommand": true,
"args": [],
"tasks": [
{
"taskName": "build_console",
"command":"dotnet"
"args": [
"build", //組成dotnet build
//設置需要編譯的項目,如果存在多個啟動項目可以設置成解決方案文件(.sln),這里只有一個項目所以設置運行項目也可以
"${workspaceRoot}\\VSCodeTutorial.ConsoleApp\\VSCodeTutorial.ConsoleApp.csproj"
],
"isBuildCommand": true, //設置是否編譯項目
"problemMatcher": "$msCompile"
},
{
"taskName": "UnitTest",
"command":"dotnet",
"args": [
"test",//組成dotnet test 命令
"${workspaceRoot}\\VSCodeTutorial.UnitTest\\VSCodeTutorial.UnitTest.csproj"
],
"isTestCommand": true,//設置為單元測試項目
"problemMatcher": "$msCompile"
}
]
}
上面的代碼中,我將command命令移到了任務中,並給每個任務起了一個好識別的名字,現在這里一個有2個任務了
第一個任務build_console
運行時 會編譯VSCodeTutorial.ConsoleApp
項目及其依賴的項目
第二個任務UnitTest
則是單元測試項目,運行dotnet test
命令,這里有個特殊的設置就是"isTestCommand": true
標識為測試項目后可以通過快捷方式運行該命令
任務建好了,我們來運行任務把,windows按下 ctrl+shift+p,在彈出的對話框中輸入:task 過濾命令可以得到以下的選項
選擇任務:運行測試任務
這條來運行我們之前編寫好的單元測試項目,可以看到運行成功的情況,如下圖所示
這里中文顯示正常,沒有亂碼哦,但是我不知道是什么原因..就是這么神奇
對於經常執行的任務,可以通過設置鍵盤快捷方式來方便調用,可以看到我分別設置了ctrl+shift+t 運行測試任務ctrl+shift+b 運行編譯任務,ctrl+shift+r 啟動選擇任務,大家可以根據自己的喜好來設置。
0x06 開始編寫控制台代碼
打開VSCodeTutorial.ConsoleApp項目中的Program.cs文件,修改其中的代碼,如下所示
using System;
using VSCodeTutorial.Common;
namespace VSCodeTutorial.ConsoleApp
{
class Program
{
static void Main(string[] args)
{
while(true)
{
Console.WriteLine("請輸入一個小於10的數字,回車結束:");
string input_str = Console.ReadLine();
if(int.TryParse(input_str ,out var input_int))
{
if(input_int>0 && input_int<=10){
int result = MathHelper.Factorial(input_int);
Console.WriteLine("你輸入的數字是{0},它的階乘結果是{1},退出請按ctrl+c,按其他鍵再試一次",input_int,result);
Console.ReadKey();
}
}
else{
Console.WriteLine("輸入的字符不是有效的數字");
}
}
}
}
}
代碼比較 簡單,就不做解釋了,我們直接來看運行的結果,這里順便提一下啊,在我們之前做的眾多工作之后,我們這里編寫代碼有美美噠的智能提示哦,如下圖所示:
好,再根目錄下輸入以下命令運行ConsoleApp
$:> dotnet run -p ./VSCodeTutorial.ConsoleApp/VSCodeTutorial.ConsoleApp.csproj
也可以在VSCodeTutorial.ConsoleApp
目錄下直接運行dotnet run
命令即可.
結果運行還是亂碼中,但是這次我們有辦法解決,我們在控制台代碼中添加一句代碼即可onsole.OutputEncoding = Encoding.UTF8
using System;
using System.Text;
using VSCodeTutorial.Common;
namespace VSCodeTutorial.ConsoleApp
{
class Program
{
static void Main(string[] args)
{
Console.OutputEncoding = Encoding.UTF8; // 設置控制台編碼
while(true)
{
Console.WriteLine("請輸入一個小於10的數字,回車結束:");
string input_str = Console.ReadLine();
if(int.TryParse(input_str ,out var input_int))
{
if(input_int>0 && input_int<=10){
int result = MathHelper.Factorial(input_int);
Console.WriteLine("你輸入的數字是{0},它的階乘結果是{1},退出請按ctrl+c,按其他鍵再試一次",input_int,result);
Console.ReadKey();
}
}
else{
Console.WriteLine("輸入的字符不是有效的數字");
}
}
}
}
}
使用dotnet build編譯后,再次運行Console項目看到了我們期望的界面
程序運行正確,當然了,我們都跑過單元測試了不是。。
0x07 開始調試程序了
如下圖提示操作
終於輪到我們之前生成的launch.json文件出場了,先來看下它的代碼,代碼中已經添加了配置的說明
{
"version": "0.2.0",
"configurations": [
{
"name": ".NET Core Launch (console)", //配置名稱 可以改成更好識別的名字
"type": "coreclr", // .net core類型的調試
"request": "launch", //調試方式 不用改
"preLaunchTask": "build", // 前置任務,這里是編譯,但是默認的編譯任務,已經被我改了名字了,所以這里要改一下哦
"program": "${workspaceRoot}\\VSCodeTutorial.ConsoleApp\\bin\\Debug\\netcoreapp1.1\\VSCodeTutorial.ConsoleApp.dll", //需要調試的DLL的位置
"args": [], //額外的參數
"cwd": "${workspaceRoot}\\VSCodeTutorial.ConsoleApp", //工作目錄
"console": "internalConsole", //控制台模式,這里是內嵌控制台,一會要改成外置的,不然沒法交互輸入
"stopAtEntry": false,
"internalConsoleOptions": "openOnSessionStart"
},
{
"name": ".NET Core Attach", //名稱
"type": "coreclr", //類型
"request": "attach", //使用附加的方式
"processId": "${command:pickProcess}" //附加的進程ID
}
]
}
根據實際情況,需要對上面的配置進行以下變更,變更的部分已經添加了注釋,附加調試不是本文的重點,就不改了
{
"version": "0.2.0",
"configurations": [
{
"name": "調試ConsoleApp", //修改下命令
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build_console", //修改前置任務名和task.json中配置一致
"program": "${workspaceRoot}\\VSCodeTutorial.ConsoleApp\\bin\\Debug\\netcoreapp1.1\\VSCodeTutorial.ConsoleApp.dll",
"args": [],
"cwd": "${workspaceRoot}\\VSCodeTutorial.ConsoleApp",
"externalConsole":true, //使用外置的控制台
"stopAtEntry": false,
"internalConsoleOptions": "openOnSessionStart"
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach",
"processId": "${command:pickProcess}"
}
]
}
修改完成后,我們點擊運行按鈕可以開始調試了,調試的方式和使用VS是一致的,快捷鍵為F5 F10 F11
簡直太強大了!
0x08 多項目啟動調試
有時候我們會同時在一個解決方案中 同時啟動兩個項目來調試,那么怎么配置呢,其實很簡單,另外一個項目和之前的一樣各自配置一個編譯的Task(當然最好是兩個項目使用.sln來統一編譯),然后各配置一個launch配置,然后使用compounds
配置來同時啟動即可,示例如下
{
"version": "0.2.0",
"configurations": [
"HelloRpcClientLaunch"
{
"name": "HelloRpcServer",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "buildServer",
"program": "${workspaceRoot}\\src\\sample\\HelloRpc\\HelloRpc.Server\\bin\\Debug\\netcoreapp1.1\\HelloRpc.Server.dll",
"args": [],
"cwd": "${workspaceRoot}\\src\\sample\\HelloRpc\\HelloRpc.Server",
"externalConsole":true,
"stopAtEntry": false,
"internalConsoleOptions": "openOnSessionStart"
},
"HelloRpcClientLaunch"
{
"name": "HelloRpcClient",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "buildClient",
"program": "${workspaceRoot}\\src\\sample\\HelloRpc\\HelloRpc.Client\\bin\\Debug\\netcoreapp1.1\\HelloRpc.Client.dll",
"args": [],
"cwd": "${workspaceRoot}\\src\\sample\\HelloRpc\\HelloRpc.Client",
"externalConsole":true,
"stopAtEntry": false,
"internalConsoleOptions": "openOnSessionStart"
}
]
"compounds": [
{
"name": "Server/Client",
"configurations": ["HelloRpcServer", "HelloRpcClient"]
}
]
}
這時候就會有個Sever/Client的調試選項供選擇了,如圖:
好了,讓我們一起使用VSCode來編寫.NetCore項目吧