練習:
- 串接
API- 以URL取得JSON資料並反序列化(Deserialize) 為物件 - 透過
Telegram Bot發送訊息 - 每隔一段時間自動執行某個方法(使用
PeriodicTimer異步化定時器)
串接 API - 以 URL 取得 JSON 資料並反序列化(Deserialize) 為物件
[C# 筆記] 練習串接 API - 以 URL 取得 JSON 資料並反序列化(Deserialize) 為物件
把 JSON 資料轉換為對應的 Class
- 利用網站 JSON Editor Online 顯示查看了
JSON資料樹狀圖。![]()
建立對應的類別(class)
用一個偷懶的方式去建立類別,複製 JSON 字串裡的一個物件的資料
使用「編輯 > 選擇性貼上 > 貼上 JSON 做為類別」的方式來建立。- 新增一個類別 Vocabulary.cs 的檔案
- 將游標移至你要產生類別的位置上,使用「編輯 > 選擇性貼上 > 貼上 JSON 做為類別」的方式來建立。
再稍微修改一下:把 Rootobject 改成 Vocabulary
1
2
3
4
5
6
7
8
9
10
11
12
public class Vocabulary
{
public int letterCount { get; set; }
public string word { get; set; } = string.Empty;
public Definition[] definitions { get; set; } = new Definition[2];
}
public class Definition
{
public string text { get; set; } = string.Empty;
public string partOfSpeech { get; set; } = string.Empty;
}
以 URL 取得 JSON 資料
使用 HttpClient.GetStringAsync() 取得指定 URI 所回傳的資料
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
static async Task Main(string[] args)
{
//取得api數據
var content = await FetchApiData("https://raw.githubusercontent.com/AppPeterPan/TaiwanSchoolEnglishVocabulary/main/6級.json");
//將JSON 資料反序列化(Deserialize)為物件(自定義的類別Class)
var data = JsonSerializer.Deserialize<List<Vocabulary>>(content)!;
}
//取得api數據
static async Task<string> FetchApiData(string url)
{
//使用HttpClient發出Get請求,並接收回傳的內容
HttpClient client = new HttpClient(); //建立HttpClient物件
return await client.GetStringAsync(url); //接收回傳的內容
}
透過 Telegram Bot 發送訊息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//發送TG訊息
static async Task SendMessage(string msg)
{
var botClient = new Telegram.Bot.TelegramBotClient("999999:AAEqPs3--n5jAk2qhjg2YnPH0MflxbkWsoo");
await botClient.SendTextMessageAsync(
chatId: "-123456789",
text: msg);
}
static async Task Main(string[] args)
{
//取得api數據
var content = await FetchApiData("https://raw.githubusercontent.com/AppPeterPan/TaiwanSchoolEnglishVocabulary/main/6級.json");
//將JSON 資料反序列化(Deserialize)為物件(自定義的類別Class)
var data = JsonSerializer.Deserialize<List<Vocabulary>>(content)!;
//發送TG訊息
await SendMessage("test send message");
}
組字串 - 使用Random隨機數取得某一單字
1
2
3
4
5
6
//使用隨機數取得某一單字
Random random = new Random(); //建立隨機數物件
int rndNum = random.Next(data.Count); //產生0~單字量之間的數字
//組字串
var s = $"{data[rndNum].word}\r\n{data[rndNum].definitions[0].text}\r\n{data[rndNum].definitions[0].partOfSpeech}";
每隔一段時間自動執行某個方法(使用 PeriodicTimer 異步化定時器)
[C# 筆記].Net6 新定时器 PeriodicTimer (異步化的定時器)
什麼是 PeriodicTimer 異步化定時器
在.NET 6中引入了新Timer:System.Threading.PeriodicTimer,它和之前的Timer相比,最大的區別就是新的PeriodicTimer事件處理可以方便地使用異步,消除使用callback機制減少使用複雜度。
1
2
3
4
5
using PeriodicTimer timer = new(TimeSpan.FromSeconds(2));
while (await timer.WaitForNextTickAsync())
{
Console.WriteLine(DateTime.UtcNow);
}
與Timer的區別
消除了回呼,不再需要綁定事件
不會發生重入,只允許有一個消費者,不允許同一個
PeriodicTimer在不同的地方同時WaitForNextTickAsync,不需要自己做排他鎖來實現不能重入非同步化,之前的幾個
timer的callback都是同步的,使用新的timer我們可以更好的使用非同步方法,避免寫Sync over Async之類的程式碼
加上 PeriodicTimer 異步化定時器,透過 Telegram Bot定時發送單字
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
static async Task Main(string[] args)
{
//取得api數據
var content = await FetchApiData("https://raw.githubusercontent.com/AppPeterPan/TaiwanSchoolEnglishVocabulary/main/6級.json");
//將JSON 資料反序列化(Deserialize)為物件(自定義的類別Class)
var data = JsonSerializer.Deserialize<List<Vocabulary>>(content)!;
//定時發送TG訊息
using PeriodicTimer timer = new(TimeSpan.FromHours(1)); //每小時
while (await timer.WaitForNextTickAsync())
{
//使用隨機數取得某一單字
Random random = new Random(); //建立隨機數物件
int rndNum = random.Next(data.Count); //產生0~單字量之間的數字
//組字串(單字)
var s = $"{data[rndNum].word}\r\n{data[rndNum].definitions[0].text}\r\n{data[rndNum].definitions[0].partOfSpeech}";
//發送TG訊息
await SendMessage(s);
}
}
//發送TG訊息
static async Task SendMessage(string msg)
{
var botClient = new Telegram.Bot.TelegramBotClient("999999:AAEqPs3--n5jAk2qhjg2YnPH0MflxbkWsoo");
await botClient.SendTextMessageAsync(
chatId: "-123456789",
text: msg);
}
//取得api數據
static async Task<string> FetchApiData(string url)
{
//使用HttpClient發出Get請求,並接收回傳的內容
HttpClient client = new HttpClient(); //建立HttpClient物件
return await client.GetStringAsync(url); //接收回傳的內容
}
Code
Program.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
using System.Text.Json;
using Telegram.Bot;
using Telegram.Bot.Types;
namespace TestDemo
{
internal class Program
{
static void Log(string s)
{
Console.WriteLine(s);
}
static async Task Main(string[] args)
{
Log($"{DateTime.Now} - 開始取得api資料.");
//取得api數據
var content = await FetchApiData("https://raw.githubusercontent.com/AppPeterPan/TaiwanSchoolEnglishVocabulary/main/6級.json");
Log($"{DateTime.Now} - 完成取得api資料.");
Log($"{DateTime.Now} - 開始轉換 JSON 為 Object.");
//將JSON 資料反序列化(Deserialize)為物件(自定義的類別Class)
var data = JsonSerializer.Deserialize<List<Vocabulary>>(content)!;
Log($"{DateTime.Now} - JSON 為 Object,並開始組字串(單字).");
//定時發送TG訊息
using PeriodicTimer timer = new(TimeSpan.FromSeconds(2)); //每小時
while (await timer.WaitForNextTickAsync())
{
//使用隨機數取得某一單字
Random random = new Random(); //建立隨機數物件
int rndNum = random.Next(data.Count); //產生0~單字量之間的數字
var s = $"{data[rndNum].word}\r\n{data[rndNum].definitions[0].text}\r\n{data[rndNum].definitions[0].partOfSpeech}"; //組字串
Log($"{DateTime.Now} - 要傳送的單字為:\r\n{s}\r\n");
Log($"{DateTime.Now} - 開始發送TG訊息.");
await SendMessage(s); //發送TG訊息
Log($"{DateTime.Now} - 完成發送TG訊息.");
}
//Console.ReadKey();//可以使窗口停留一下,直到點擊鍵盤任一鍵為止
}
//取得api數據
static async Task<string> FetchApiData(string url)
{
//使用HttpClient發出Get請求,並接收回傳的內容
HttpClient client = new HttpClient(); //建立HttpClient物件
return await client.GetStringAsync(url); //接收回傳的內容
}
//發送TG訊息
static async Task SendMessage(string msg)
{
var botClient = new Telegram.Bot.TelegramBotClient("6460822229:AAEqPs3--n5jAk2qhjg2YnPH0MflxbkWsoo");
await botClient.SendTextMessageAsync(
chatId: "-1002101862034",
text: msg);
}
}
}
Vocabulary.cs
1
2
3
4
5
6
7
8
9
10
11
12
public class Vocabulary
{
public int letterCount { get; set; }
public string word { get; set; } = string.Empty;
public Definition[] definitions { get; set; } = new Definition[2];
}
public class Definition
{
public string text { get; set; } = string.Empty;
public string partOfSpeech { get; set; } = string.Empty;
}
執行結果:
1
2
3
4
5
6
7
8
9
10
11
2024/4/3 上午 03:25:26 - 開始取得api資料.
2024/4/3 上午 03:25:27 - 完成取得api資料.
2024/4/3 上午 03:25:27 - 開始轉換 JSON 為 Object.
2024/4/3 上午 03:25:27 - JSON 為 Object,並開始組字串(單字).
2024/4/3 上午 03:25:29 - 要傳送的單字為:
trek
(長途而辛苦的)旅行或移居
n
2024/4/3 上午 03:25:29 - 開始發送TG訊息.
2024/4/3 上午 03:25:31 - 完成發送TG訊息.
不要寫「假的」非同步方法 - by Huanlin學習筆記
閱讀筆記 - 使用 .NET Async/Await 的常見錯誤 - by 黑暗執行緒
async 與 await - by Huanlin學習筆記
.Net6 新特性 - PeriodicTimer - 异步化的定时器
[C# 筆記] 每隔一段時間自動執行某個方法(使用執行緒)
[C# 筆記] 練習串接 API - 以 URL 取得 JSON 資料並反序列化(Deserialize) 為物件
[C# 筆記] 透過 Telegram Bot 發送訊息
[C# 筆記].Net6 新定时器 PeriodicTimer (異步化的定時器)
[C# 筆記] 將主程式進入點 Main()方法改成 async 非同步
