平時我們許多操作都離不開命令列介面 (Command-Line Interface, CLI),例如顯示或變更目前目錄的 cd、列出檔案和資料夾的 ls 。在 dotnet 中我們也可能會使用到 dotent new, run, watch 等,那要如何自己寫一個呢?
我們先使用 .NET 7 建立一個 Console 應用程式
在 ConsoleAppHoliday.csproj 檔案中增加下面三行
其中 ToolCommandName 可以選擇不輸入,若有該資訊則指令名稱就是 ToolCommandName 的內容,以上面的例子就是 ruyut
PackageOutputPath 則是打包的目標路徑
因為本文的重點是在建立 CLI 工具,所以筆者使用 C# 簡單寫了一個讀取中華民國政府行政機關辦公日曆表 API 的小程式,略過程式碼說明直接開始建立 CLI 工具。完整程式碼附在文末,有興趣的讀者可以自行取用。
打包專案:
全域安裝套件:
註:ConsoleAppHoliday 為本示範專案的名稱,請自行替換。
查看全域安裝的套件:
解除安裝全域套件:
使用本程式的指令判斷今天是否為假日:
使用本程式的指令判斷指定日期是否為假日:
使用本程式的指令尋找下一個假日:
執行截圖:
話說在指令介面自己判斷和處理參數真的是有夠麻煩的,或許可以試試看現成的套件:C# 使用 CommandLineUtils 簡化處理傳入參數 (上)
參考資料:
Microsoft.Learn - Tutorial: Create a .NET tool using the .NET CLI
Tutorial: Install and use a .NET global tool using the .NET CLI
我們先使用 .NET 7 建立一個 Console 應用程式
在 ConsoleAppHoliday.csproj 檔案中增加下面三行
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PackAsTool>true</PackAsTool>
<ToolCommandName>ruyut</ToolCommandName>
<PackageOutputPath>./nupkg</PackageOutputPath>
</PropertyGroup>
</Project>
其中 ToolCommandName 可以選擇不輸入,若有該資訊則指令名稱就是 ToolCommandName 的內容,以上面的例子就是 ruyut
PackageOutputPath 則是打包的目標路徑
因為本文的重點是在建立 CLI 工具,所以筆者使用 C# 簡單寫了一個讀取中華民國政府行政機關辦公日曆表 API 的小程式,略過程式碼說明直接開始建立 CLI 工具。完整程式碼附在文末,有興趣的讀者可以自行取用。
打包專案:
dotnet pack
全域安裝套件:
dotnet tool install --global --add-source .\nupkg ConsoleAppHoliday
註:ConsoleAppHoliday 為本示範專案的名稱,請自行替換。
查看全域安裝的套件:
dotnet tool list -g
解除安裝全域套件:
dotnet tool uninstall -g ConsoleAppHoliday
使用本程式的指令判斷今天是否為假日:
ruyut isHoliday
使用本程式的指令判斷指定日期是否為假日:
ruyut isHoliday 20221225
使用本程式的指令尋找下一個假日:
ruyut nextHoliday
執行截圖:
話說在指令介面自己判斷和處理參數真的是有夠麻煩的,或許可以試試看現成的套件:C# 使用 CommandLineUtils 簡化處理傳入參數 (上)
參考資料:
Microsoft.Learn - Tutorial: Create a .NET tool using the .NET CLI
Tutorial: Install and use a .NET global tool using the .NET CLI
完整程式碼範例
using System.Globalization;
using System.Net;
using System.Text.Json;
using System.Text.Json.Serialization;
if (args.Length == 0)
{
Console.WriteLine("請輸入有效參數:");
Console.WriteLine("isHoliday [日期]");
Console.WriteLine("nextHoliday [日期]");
return;
}
DateTime date = DateTime.Now;
if (args.Length >= 2)
date = DateTime.ParseExact(args[1], "yyyyMMdd", CultureInfo.InvariantCulture);
List<TaiwanCalenderDto> taiwanCalender = GetTaiwanCalender(date);
if (args[0] == "isHoliday")
{
IsHoliday(taiwanCalender, date);
}
else if (args[0] == "nextHoliday")
{
GetNextHoliday(taiwanCalender, date);
}
else
{
Console.WriteLine("請輸入有效參數:");
Console.WriteLine("isHoliday [日期]");
Console.WriteLine("nextHoliday");
return;
}
// 呼叫 API 取得台灣假日資訊
List<TaiwanCalenderDto> GetTaiwanCalender(DateTime date)
{
string url = $"https://cdn.jsdelivr.net/gh/ruyut/TaiwanCalendar/data/{date.Year.ToString()}.json";
var client = new HttpClient();
var response = client.GetAsync(url).Result;
if (response.StatusCode == HttpStatusCode.NotFound)
{
Console.WriteLine("假日資訊取得錯誤,沒有該年度資料");
return new List<TaiwanCalenderDto>();
}
if (response.StatusCode != HttpStatusCode.OK)
{
Console.WriteLine($"假日資訊取得錯誤,錯誤代號: {response.StatusCode}");
return new List<TaiwanCalenderDto>();
}
var json = response.Content.ReadAsStringAsync().Result;
List<TaiwanCalenderDto> taiwanCalenderDtos = JsonSerializer.Deserialize<List<TaiwanCalenderDto>>(json) ?? new();
if (!taiwanCalenderDtos.Any())
{
Console.WriteLine("假日資訊取得錯誤,沒有該年度資料");
return new List<TaiwanCalenderDto>();
}
return taiwanCalenderDtos;
}
// 判斷是否為假日
bool IsHoliday(List<TaiwanCalenderDto> taiwanCalenderDtos, DateTime date)
{
string dateStr = date.ToString("yyyyMMdd");
TaiwanCalenderDto? taiwanCalenderDto = taiwanCalenderDtos
.FirstOrDefault(x => x.Date == dateStr);
if (taiwanCalenderDto == null)
{
Console.WriteLine("假日資訊取得錯誤,沒有該日期資料");
return false;
}
if (taiwanCalenderDto.IsHoliday)
{
Console.WriteLine(
$"{dateStr} 是假日,說明: {(string.IsNullOrWhiteSpace(taiwanCalenderDto.Description) ? "例假日" : taiwanCalenderDto.Description)}");
return true;
}
else
{
Console.WriteLine($"{dateStr} 不是假日");
return false;
}
}
void GetNextHoliday(List<TaiwanCalenderDto> taiwanCalenderDtos, DateTime date)
{
string dateStr = date.ToString("yyyyMMdd");
TaiwanCalenderDto? nextHoliday = taiwanCalenderDtos
.FirstOrDefault(x => x.IsHoliday && x.Date.CompareTo(dateStr) > 0);
if (nextHoliday == null)
{
Console.WriteLine("噢不!今年沒有假日了!");
}
else
{
Console.WriteLine(
$"下一個假日是 {nextHoliday.Date},說明: {(string.IsNullOrWhiteSpace(nextHoliday.Description) ? "例假日" : nextHoliday.Description)}");
}
}
/// <summary>
/// TaiwanCalendar Json Data
/// </summary>
public class TaiwanCalenderDto
{
[JsonPropertyName("date")] public string Date { get; set; }
[JsonPropertyName("week")] public string Week { get; set; }
[JsonPropertyName("isHoliday")] public bool IsHoliday { get; set; }
[JsonPropertyName("description")] public string Description { get; set; }
}
留言
張貼留言
如果有任何問題、建議、想說的話或文章題目推薦,都歡迎留言或來信: a@ruyut.com