<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Tim Tsai 的技術筆記</title><description>軟體工程師 Tim Tsai 的個人技術部落格，分享 C#、Web 開發與 AI 輔助開發心得。</description><link>https://skytim.github.io/</link><language>zh-TW</language><item><title>【範例】Hello World / 為什麼開始寫部落格</title><link>https://skytim.github.io/blog/hello-world/</link><guid isPermaLink="true">https://skytim.github.io/blog/hello-world/</guid><description>這是一篇範例文章，說明為什麼重新開始寫技術部落格，以及這個網站想記錄什麼。</description><pubDate>Wed, 21 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;注意：&lt;/strong&gt; 這是示範用的範例文章，方便預覽版型與排版，之後可以刪除或改寫。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;2018 年時我曾在 GitHub Pages 上放過幾篇前端框架筆記，後來忙於工作就停更了。現在重新用 Astro 架站，希望把&lt;strong&gt;可重複查閱&lt;/strong&gt;的技術筆記與&lt;strong&gt;實驗心得&lt;/strong&gt;整理在同一個地方。&lt;/p&gt;
&lt;h2&gt;我想記錄什麼&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;後端與 API 設計（C# / ASP.NET、Java）&lt;/li&gt;
&lt;li&gt;前端與全端整合（Angular 等）&lt;/li&gt;
&lt;li&gt;AI 輔助開發的流程、工具與取捨&lt;/li&gt;
&lt;li&gt;偶爾的學習雜記與除錯過程&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;給自己的提醒&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;短文也沒關係&lt;/strong&gt;，重點是留下脈絡。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;程式碼範例要可讀&lt;/strong&gt;，將來的自己也會感謝現在的自己。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;中英文混用可以&lt;/strong&gt;，但標題與摘要盡量寫清楚。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;若你也是很久沒更新個人網站的人，歡迎從一篇「為什麼開始」寫起——這篇就是這樣誕生的。&lt;/p&gt;
</content:encoded><category>範例</category><category>部落格</category><category>隨筆</category></item><item><title>【範例】C# async/await：避免常見的 fire-and-forget 陷阱</title><link>https://skytim.github.io/blog/csharp-async-example/</link><guid isPermaLink="true">https://skytim.github.io/blog/csharp-async-example/</guid><description>範例文章：以 C# 程式碼說明 async/await 的基本用法，以及為什麼不該忽略 await 回傳的 Task。</description><pubDate>Tue, 20 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;注意：&lt;/strong&gt; 以下內容為教學範例，非 production 完整實作。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在 ASP.NET 或背景工作中，&lt;code&gt;async/await&lt;/code&gt; 幾乎是日常。最常見的問題不是語法，而是&lt;strong&gt;沒有 await 就放行 Task&lt;/strong&gt;，導致例外被吞掉或請求提早結束。&lt;/p&gt;
&lt;h2&gt;正確：await 完成再繼續&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;public async Task&amp;lt;User?&amp;gt; GetUserAsync(int id, CancellationToken cancellationToken)
{
    var response = await _httpClient.GetAsync($&quot;/api/users/{id}&quot;, cancellationToken);
    response.EnsureSuccessStatusCode();

    return await response.Content.ReadFromJsonAsync&amp;lt;User&amp;gt;(cancellationToken: cancellationToken);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;await&lt;/code&gt; 會在 I/O 完成前讓出執行緒，但不會阻塞執行緒池——這正是 async 在伺服器端的價值。&lt;/p&gt;
&lt;h2&gt;陷阱：fire-and-forget&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;// ❌ 不要這樣做：例外可能變成 UnobservedTaskException
_ = SendAuditLogAsync(userId);

public async Task SendAuditLogAsync(int userId)
{
    await _queue.PublishAsync(new AuditEvent(userId));
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;若 audit 失敗你應該知道。較安全的做法包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在 HTTP 請求路徑上 &lt;strong&gt;await&lt;/strong&gt; 關鍵工作；&lt;/li&gt;
&lt;li&gt;或使用 &lt;code&gt;BackgroundService&lt;/code&gt; / 訊息佇列，並在邊界記錄失敗；&lt;/li&gt;
&lt;li&gt;若真的必須 detach，使用明確的錯誤處理（例如 &lt;code&gt;Task.Run&lt;/code&gt; 包裝並 log），而不是裸 &lt;code&gt;_ = task&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;小結&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;async/await&lt;/code&gt; 讓非同步程式碼讀起來像同步，但&lt;strong&gt;Task 的生命週期仍然要管理&lt;/strong&gt;。寫 API 時，問自己一句：「如果這個 Task 失敗，誰負責記錄與重試？」&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;這篇範例主要展示&lt;strong&gt;程式碼區塊&lt;/strong&gt;在淺色 / 深色模式下的 Shiki 高亮效果。正式文章請刪除【範例】標記並替換成你的內容。&lt;/p&gt;
</content:encoded><category>範例</category><category>C#</category><category>.NET</category></item></channel></rss>