2025年12月28日 星期日

使用GitHub Copilot協助撰寫Blazor Server應用程式 - 1

 


在人工智慧快速發展的時代,程式開發的方式正悄然改變。過去,程式開發人員需要花費大量時間從零開始建立專案結構、撰寫樣板程式碼與設定開發環境,如今,生成式AI 輔助工具的出現,正大幅改變這種傳統冗長的開發流程。

在這一系列《使用GitHub Copilot協助撰寫Blazor Server應用程式》文章中,我們將以一個實際範例來介紹如何在Visual Studio Code開發工具中運用 GitHub Copilot 與其進階功能代理模式(Agent Mode)來開發 ASP.NET Core Blazor Server 專案,讓開發者能以自然語言與 AI 對話,從專案建立、元件設計、API 撰寫到單元測試與除錯,自動化完成專案設計。


自動產生專案結構框架

GitHub Copilot可以透過產生一個專案基本結構框架來幫助我們建立新項目,能夠根據開發者的需求,自動生成一個新專案的基本資料夾結構和必要檔案,協助快速啟動一個應用程式的開發流程。更詳細的說它可以幫我們進行以下作業:

 

l  自動建立專案結構:GitHub Copilot 能根據開發人員輸入的提示(例如「建立一個 ASP.NET Core  Blazor Server 應用程式專案」),便自動產生對應的目錄結構、主要程式檔案(例如:Program.cs)、組態設定檔(例如:appsettings.json),以及必要的資料夾(例如 PagesModels)。

l  支援專案範本與熱門框架:GitHub Copilot支援多種主流程式設計框架(例如:ASP.NET CoreReactVue.jsNode.js等等),能根據您指定的技術,自動生成符合該框架慣例的專案結構與基本程式碼。例如,對於ASP.NET Core Blazor應用程式類型的專案,GitHub Copilot 會自動建立 Pages」、「Models」等特殊資料夾,並產生基本的元件和模型程式碼。

l  節省時間與減少錯誤:透過工具自動生成專案結構,不需手動建立每個檔案或資料夾,能大幅節省初始化專案的時間,並減少因手動操作可能產生的人為錯誤。

l  依需求進行客製化:可以在 GitHub Copilot 的提示中加入特定需求(例如:「使用 Entity Framework Core」套件開發資料存取程式),GitHub Copilot 會根據這些需求,生成相應的結構和程式碼。

 

使用GitHub Copilot代理模式(Agent Mode)

GitHub Copilot 代理模式(Agent Mode)是一個自主的 AI 程式設計輔助工具,能夠即時根據您的自然語言提示,執行需要多步驟的程式任務。在代理模式下,GitHub Copilot像一個小助手,能夠與您一同解決問題,理解您的意圖,並在建置的解決方案需要調整時,持續反覆修正直到達到理想結果。讓我們先來利用代理模式建立新專案。

 

Visual Studio Code開發工具的GitHub Copilot的聊天視窗中輸入「/new」,可使用自然語言快速建立新專案。我們可以從先在聊天視窗下方選取「Agent」開啟GitHub Copilot代理模式(Agent Mode),然後在文字方塊中輸入以下提示:

/new 建立一個ASP.NET Core 9.0 Blazor Server 應用程式,包含首頁(Home)與版權宣告(Privacy)兩個頁面。首頁上方提供選單可以切換到Privacy

 

請參考下圖所示:

1:使用斜線命令(Slash Command)與自然語言建立新專案


通常在聊天介面、機器人或開發工具中,以「
/」符號開頭的特殊命令稱做斜線命令(Slash Command)。只要在聊天介面輸入框中輸入「/」符號加上命令名稱,即可快速觸發特定動作或工作流程。

 

GitHub Copilot執行時可能會要求您進行授權以在終端機視窗執行一些命令,這時可以選擇「Allow」按鈕以允許執行,請參考下圖所示:

 

2:進行授權允許執行命令

 

若有必要,您會需要重複進行授權的動作讓GitHub Copilot能夠完成專案的建立,完成後可以檢視它產生的程式檔案,確認程式碼是否符合需求。若GitHub Copilot詢問是否儲存當下新增的程式碼,可以按下「Keep」按鈕,請參考下圖所示:

3:檢視產生的程式檔案


待專案建立完成之後,通常
GitHub Copilot也會啟動開發階段網站伺服器執行網站,並自動賦予一個埠號,這時我們便可使用瀏覽器便連接到這個網站,首頁的畫面請參考下圖所示:
 

4:使用瀏覽器連接到網站

 

Visual Studio Code開發工具的 GitHub Copilot Chat 視窗中,與其進行互動式對話,協助進行程式開發的過程中,我們希望GitHub Copilot能夠遵循一些團隊開發的準則來生成程式碼,自訂指令是一個解決的方法。

我們可以在GitHub Copilot Chat 視窗中的設定開啟「Generate Agent Instructions」功能,它可以自動產生代理指令(Instruction)檔案,協助自訂 GitHub Copilot 的行為。點選「Generate Agent Instructions」這個項目後GitHub Copilot會試著建立「copilot-instructions.md」檔案,請參考下圖所示:

5:使用「Generate Agent Instructions」功能產生代理指令(Instruction)檔案


這個檔案通常是用來說明或規範在專案中如何使用
GitHub Copilot 這類 AI 程式輔助工具。其主要功能包括可以指定GitHub Copilot 產生程式碼時應遵循的風格或標準;說明哪些檔案、資料夾或程式碼片段不應由 GitHub Copilot 產生或修改,並提供團隊成員使用 GitHub Copilot 的建議、限制或注意事項。簡而言之,這個檔案是協助團隊有效管理和運用 GitHub Copilot,確保 AI 產生的程式碼符合專案需求與品質標準。在這步驟GitHub Copilot
的回應請參考下圖所示:

6:使用「Generate Agent Instructions」產生「copilot-instructions.md」檔案


由於筆者在
GitHub Copilot Chat視窗下方語言模型選擇「Auto」模式,因此可能會使用到未在官網啟用的語言模型,例如筆者測試時GitHub Copilot想要使用「Claude 3.5 Sonnet」模型,GitHub Copilot會貼心的詢問是否直接幫您啟用,這樣就不需要再手動設定,請參考下圖所示:

7:啟用「Claude 3.5 Sonnet」語言模型


接著便自動在「
.github」資料夾中建立「copilot-instructions.md」檔案,您可以點選「keep」儲存這個檔案,請參考下圖所示:

8:點選「keep」儲存「copilot-instructions.md」檔案


GitHub Copilot
會分析目前專案中的程式碼,然後在「copilot-instructions.md」檔案中加入專案的描述。為了滿足需求,筆者修改這個檔案,在檔案一開始要求後續使用繁體中文來回覆,並在檔案後方加上「## 程式碼風格指南」之後的設定:

copilot-instructions.md

# Blazor Server 應用程式開發指南

在對談的過程中,使用繁體中文來回覆,產生的文件與註解皆採用繁體中文。

 

## 專案架構

 

這是一個基於 ASP.NET Core 9.0 Blazor Server 專案,採用以下結構:

 

- `Components/` - 包含所有 Blazor 元件

  - `Pages/` - 頁面元件 ( `Home.razor`, `Privacy.razor`)

  - `Layout/` - 布局相關元件 (`MainLayout.razor`, `NavMenu.razor`)

- `wwwroot/` - 靜態資源目錄

- `Program.cs` - 應用程式入口點和服務配置

 

## 關鍵開發模式

 

### 元件命名與位置

- 頁面元件放在 `Components/Pages/` 目錄

- 共享布局元件放在 `Components/Layout/` 目錄

- 元件檔案使用 `.razor` 副檔名

 

### 路由規則

- 使用 `@page` 指令定義路由

- 路由路徑與檔案名對應(如 `Privacy.razor` → `/privacy`

- 首頁使用 `@page "/"`

 

### 導航模式

- 使用 `NavLink` 元件進行導航

- `NavMenu.razor` 中定義導航結構

 

## 開發工作流程

 

### 建置與運行

```powershell

dotnet build

dotnet run

```

 

### 新增頁面步驟

1. `Components/Pages/` 建立新的 `.razor` 檔案

2. 加入 `@page` 指令定義路由

3. `NavMenu.razor` 中添加導航連結

 

## 重要提示

- 使用 `@using` 指令在 `_Imports.razor` 中管理命名空間

- 頁面標題使用 `<PageTitle>` 元件

- 所有頁面元件都需要 `@page` 指令

 

## 相依性

- ASP.NET Core 9.0

- Bootstrap (用於 UI 樣式)

 

## 程式碼風格指南

 

### 一般

- 使用一致的縮排(4 個空格)

- 遵循標準 C# 命名慣例:

  - 類別、方法、屬性使用 PascalCase

  - 區域變數與參數使用 camelCase

  - 私有欄位使用 _camelCase

- 保持方法簡潔,專注於單一職責

- 避免在單一方法中使用過於複雜的邏輯

 

### C# 特定

- 當型別在賦值右側明確時使用 `var`

- 優先使用不可變型別與屬性

- 使用現代 C# 特性(pattern matching, nullable reference types等)

- 非同步操作使用 async/await

- 公開 API 加入 XML 文件註解

 

## 程式撰寫慣例

 

- 在適當情況下使用 C# 12 的新功能

- 元件命名使用 PascalCase(例如:`WeatherDisplay.razor`

- 保持元件簡潔,專注於單一職責

- 複雜的元件邏輯使用 code-behind 檔案(.razor.cs

- CSS 類別名稱遵循 BEM 命名規則

- 顏色、間距與字體排版使用 CSS 變數

 

### Blazor 元件

- 使用具描述性的元件名稱

- UI 與邏輯分離

- 複雜元件邏輯優先使用 code-behind 模式

- 保持元件簡潔且可重複使用

 

 

## 關鍵模式

 

### 依賴注入

應用程式使用 ASP.NET Core 內建的依賴注入容器:

- `Program.cs` 中註冊服務

- 避免使用服務定位器模式

- 優先使用建構式注入

 

### 設定

- 使用 `appsettings.json` 進行應用程式設定

- 透過 `IConfiguration` 或強型別設定存取設定值

- 使用 `appsettings.{Environment}.json` 進行環境特定設定

 

### API 通訊

- 使用型別化 HttpClient 模式進行服務間通訊

- 優雅地處理暫時性錯誤

- 實作適當的錯誤處理機制

 

### 響應式設計

- 使用 Bootstrap 網格系統實現響應式版面配置

- 採用行動優先設計

- 確保符合無障礙設計標準

 

## 測試

 

### 單元測試

- 為商業邏輯與服務類別撰寫單元測試

- 使用 xUnit 作為測試框架

- 遵循 AAA 模式(ArrangeActAssert

 

### 整合測試

- 使用 HttpClient 測試 API 端點

- 使用 TestServer 進行記憶體內整合測試

- 驗證回應狀態碼與內容

 

### UI 測試

- 使用 bUnit 測試 Blazor 元件

- 驗證元件的渲染與互動性

- 測試使用者操作流程的端對端行為

 

設計資料模型(Models)

下一步來設計應用程式所需的資料模型(Models),一般程式檔案建議放在「Models」資料夾中,我們可以先在Visual Studio Code開發工具檔案總管中點選建立「Models」資料夾,請參考下圖所示:

9:建立「Models」資料夾


在資料夾中建立「
Employee.cs」檔案,請參考下圖所示:

10:建立「Employee.cs」檔案


這次我們試試「
Inline Chat」功能,將游標停留在「Employee.cs」程式撰寫視窗中,按下「CTRL+I」組合鍵開啟視窗,然後使用提示如下:

Employee 類別,定義 IdName Email 屬性,並加入一個方法用來驗證 Email 的格式是否正確。

請參考下圖所示:

11:使用Inline Chat功能

您可以看到程式編輯視窗會顯示GitHub Copilot產生的程式碼,若沒有太大問題,可以直接按下「Accept」按鈕接受程式變更;若產出的程式不如需求,可以繼續在「Inline Chat視窗的文字方塊中輸入新的提示,要求GitHub Copilot重複修改程式碼,請參考下圖所示:

12:按下「Accept」按鈕可接受程式變更

 

在筆者進行測試時,產生的「Employee」類別如下列表,您可以看到類別、屬性與方法的程式碼會根據「copilot-instructions.md」檔案的指示來撰寫,例如在每個項目的上方加上XML文件註解。不過目前產生的「IsEmailValid」方法中的程式碼並沒有使用規則運算式來檢查電子郵件格式是否正確:

Employee.cs

#nullable enable

using System;

using System.Net.Mail;

 

namespace BlazorDemo.Models

{

    /// <summary>

    /// 員工模型

    /// </summary>

    public class Employee

    {

        /// <summary>

        /// 員工 Id

        /// </summary>

        public int Id { get; set; }

 

        /// <summary>

        /// 員工姓名

        /// </summary>

        public string Name { get; set; } = string.Empty;

 

        /// <summary>

        /// 員工 Email

        /// </summary>

        public string Email { get; set; } = string.Empty;

 

        /// <summary>

        /// 驗證 Email 格式是否正確

        /// </summary>

        /// <returns>格式正確回傳 true,否則回傳 false</returns>

        public bool IsEmailValid()

        {

            if ( string.IsNullOrWhiteSpace( Email ) )

            {

                return false;

            }

 

            try

            {

                var addr = new MailAddress( Email );

                return string.Equals( addr.Address, Email, StringComparison.OrdinalIgnoreCase );

            }

            catch ( FormatException )

            {

                return false;

            }

        }

    }

}

 

我們可以再使用「Inline Chat」要求程式碼進行重構,在視窗中加入提示如下

使用Regex 改良IsValidEmail 方法

請參考下圖所示:

13:使用「Inline Chat」進行程式碼重構

 

改良過的「IsEmailValid」方法程式碼參考如下:

Employee.cs

/// <summary>

        /// 驗證 Email 格式是否正確

        /// </summary>

        /// <returns>格式正確回傳 true,否則回傳 false</returns>

        /// <summary>

        /// 使用 Regex(搭配 MailAddress 作最後確認)驗證 Email 格式是否正確

        /// </summary>

        /// <returns>格式正確回傳 true,否則回傳 false</returns>

        public bool IsEmailValid()

        {

            if ( string.IsNullOrWhiteSpace( Email ) )

            {

            return false;

            }

 

            var email = Email.Trim();

 

            // 簡潔且實務上常用的 Email Regex:允許常見字元並要求頂級域至少 2 個字母

            const string pattern = @"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$";

 

            var regexOptions = System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.Compiled;

            if ( !System.Text.RegularExpressions.Regex.IsMatch( email, pattern, regexOptions ) )

            {

            return false;

            }

 

            // 使用 MailAddress 進行最後的格式化/解析確認(若解析失敗視為不合法)

            try

            {

            var addr = new MailAddress( email );

            return string.Equals( addr.Address, email, StringComparison.OrdinalIgnoreCase );

            }

            catch ( FormatException )

            {

            return false;

            }

        }

 

 

設計Web API控制器

我們將繼續利用代理(Agent Mode)來設計一個Restful API控制器,並對後端服務進行多項變更,以提升程式碼品質與功能。先在Chat視窗使用「Add Context」功能,加入「Program.cs」與「Employee.cs」兩個檔案,要求設計一個提供員工清單的Restful API。使用「Add Context」功能能夠將這些項目變成提示的一部分,讓GitHub Copilot更了解您的意圖,請參考下圖所示:

 

14:使用「Add Context」加入項目當做提示


Chat視窗輸入提示如下要求撰寫服務程式碼:

在專案中註冊Web API服務。

加入一個Restful API控制器類別,名為EmployeesController提供查詢Employee功能。

建立三個Employee物件,隨意填屬性值。當收到HTTP Get請求時,回傳所有Employeey資料。

接著執行提示,請參考下圖所示:

15:執行提示


GitHub Copilot沒有幫您將網站執行起來,可點選Visual Studio Code開發工具的「Run and Debug」按鈕執行網站來進行測試,請參考下圖所示:

16:執行網站測試


我們可以在瀏覽器輸入服務所在的路由位址(服務路由的位址可能會不同,請檢視產生出來的程式碼
RouteAttribute的設定),例如:

執行的結果請參考下圖所示(服務執行的結果可能會不同,請檢視產生出來的程式碼),「EmployeesController」控制器會在收到HTTP Get請求時,將員工清單轉成JSON格式送到呼叫端程式

17:測試服務


檢視
GitHub Copilot產生出的程式碼,它在「Program.cs」新增「加入 Web API 服務」,以及「加入 Web API 路由映射」的程式碼,參考如下:

Program.cs

using BlazorDemo.Components;

 

var builder = WebApplication.CreateBuilder(args);

 

// Add services to the container.

builder.Services.AddRazorComponents()

    .AddInteractiveServerComponents();

 

// 加入 Web API 服務

builder.Services.AddControllers();

builder.Services.AddEndpointsApiExplorer();

 

var app = builder.Build();

 

// Configure the HTTP request pipeline.

if ( !app.Environment.IsDevelopment() )

{

    app.UseExceptionHandler( "/Error", createScopeForErrors: true );

    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.

    app.UseHsts();

}

 

app.UseHttpsRedirection();

 

app.UseAntiforgery();

 

app.MapStaticAssets();

app.MapRazorComponents<App>()

    .AddInteractiveServerRenderMode();

 

// 加入 Web API 路由映射

app.MapControllers();

 

app.Run();

 

自動產生的Web API控制器的程式碼如下列:

EmployeesController.cs

using Microsoft.AspNetCore.Mvc;

using BlazorDemo.Models;

 

namespace BlazorDemo.Controllers

{

    /// <summary>

    /// 員工資料 API 控制器

    /// </summary>

    [ApiController]

    [Route( "api/[controller]" )]

    public class EmployeesController : ControllerBase

    {

        private static readonly List<Employee> _employees = new()

        {

            new Employee

            {

                Id = 1,

                Name = "張小明",

                Email = "xiaoming.zhang@example.com"

            },

            new Employee

            {

                Id = 2,

                Name = "李美玲",

                Email = "meiling.li@example.com"

            },

            new Employee

            {

                Id = 3,

                Name = "王大同",

                Email = "datong.wang@example.com"

            }

        };

 

        /// <summary>

        /// 取得所有員工資料

        /// </summary>

        /// <returns>員工資料清單</returns>

        [HttpGet]

        public ActionResult<IEnumerable<Employee>> Get()

        {

            return Ok( _employees );

        }

    }

}

 


小結

在這一篇文章中,我們探討透過GitHub Copilo的進階功能代理模式(Agent Mode 來開發 ASP.NET Core Blazor Server 專案,讓開發者能以自然語言與AI對談來建立專案、設計模型、撰寫Web API。在本系列下一篇文章中我們將延續這篇文章的情境,加入單元測試與除錯,以AI輔助開發的強大與高效率來自動化完成專案設計。

 

0 意見:

張貼留言