[ASP.NET] 使用 Claude Code 開發 .Net Framework 網站,解決程式碼檔案的 UTF8 編碼相容問題

solve UTF8 Encoding at ASP.NET and Claude Code

環境

作業系統:Windows 

開發軟體:Visual Studio 2022

.Net 版本:.Net Framework 3.5 ~ 4.8

Claude Code 版本:v2.0.28

背景

最近維護 ASP.NET WebForm 的古蹟網站(.aspx),使用 Claude Code 幫忙開發專案,遇上程式碼檔案的UTF8編碼相容問題

原因

Visual Studio 2022 在 Windows 作業系統下,預設建檔、寫檔都使用UTF8 with BOM編碼,但是 Claude Code 預設使用 UTF8 編碼來寫入檔案。

※Visual Studio Code行為不太一樣,Visual Studio Code 預設建檔使用UTF8編碼、寫檔自動偵測。

上網爬文貌似 Windows 作業系統 + 微軟軟體,大部份都使用 UTF8 with BOM 來讀寫檔案(包含 Excel),和 Linux 環境不一樣。

造成錯誤

1.經過 Claude Code 寫檔過的 .aspx 網頁,網頁一執行會有亂碼

2.經過 Claude Code 寫檔過 .cs 程式碼,中文命名的變數與函數會讓 msbuild指令編譯錯誤 或 其它程式碼調用的時候找不到要呼叫的對象(因為變成亂碼了)。

解決方案

兩種解決方法:

1.調整 Visual Studio 寫檔的編碼為UTF8 以支援 Claude Code

2.調整 Claude Code 寫檔的編碼為UTF8 with BOM 以支援 ASP.NET (.Net Framework) 網站的開發

※已實測,ASP.NET 9 不管 UTF8 或 UTF8 with BOM,兩者編碼的檔案併存於同一專案裡都能正常編譯&顯示,也就是說你如果使用 ASP.NET 最新技術開發網站的話,應該和 Claude Code 能夠相處融洽。

實作

1. 調整 Visual Studio 寫檔的編碼為UTF8

在 Visual Studio 的方案目錄下,新增一個 .editorconfig 檔案來定義 Visual Studio 為指定副檔名的檔案使用UTF8編碼來寫檔

[*.{cs,vb,aspx,cshtml,txt,html,htm,css,js,json,yaml,xml,config,ini,sh,ps1,csproj,vbproj,sln,gitignore,gitattributes,editorconfig,md,markdown,py}]
charset = utf-8

※留意僅管使用此方法,Visual Studio在建立新檔案時,仍然為預設的UTF8 with BOM編碼,你必須再透過Visual Studio編輯/寫檔,該檔案才會變成 .editorconfig 指定的編碼

最後 Web.config 加入以下設定就完成了

<system.web> 
 <!--讓 .aspx、.cshtml 網頁正常顯示 UTF-8 編碼的文字 -->
 <globalization fileEncoding="utf-8" />
</system.web>

此解決方案適用情況:

1.跟你一起寫 Code 的同事使用 Mac、Linux 作業系統,程式碼需要 UTF8 編碼來跨平台相容編輯

2.覺得讓 Claude Code 額外把 UTF8 編碼的檔案轉換成 UTF8 with BOM 的效率太慢(第二種解決方案)

如果你想讓ASP.NET 9的工作專案裡的檔案都統一使用UTF8編碼,此方法也是可以使用。

 

以下介紹另一個解決方案

2. 讓 Claude Code 使用UTF8 with BOM寫檔

由於 Claude Code 預設使用 UTF8 編碼寫檔,如果透過提示詞、記憶檔(User Memory)特別要求它使用 UTF8 with BOM 編碼來寫檔的話,

我自己是遇到以下兩種狀況:

1.Claude Code額外使用 Powershell 把寫完的檔案轉換成UTF8 with BOM,但每次 Powershell 腳本都寫得不一樣、不太穩定

2.Claude Code有時候會忘記&漏掉要做編碼轉換,誤以為 UTF8 就已經是 UTF8 with BOM,然後很有自信地回報我工作處理完畢…

所以這邊我使用 Claude Code Hooks 呼叫事先準備好的 Powershell 腳本檔案(.ps1) 執行編碼轉換,

確保 Claude Code 每次 Write/Edit 檔案完畢後,一定都會執行檔案編碼的轉換動作。

2-1. 以下是 Powershell 腳本內容

官網文件範例是 Python 和 Typescript ,但我用 Powershell 腳本是因為我電腦是 Windows 作業系統,再加上它不像 .exe 要先經過編譯才能執行,

選個自己方便的腳本好執行即可。

    # 把檔案轉換成 UTF-8 with BOM 編碼的腳本

    # 定義允許要轉換的副檔名白清單
    $allowedExtensions = @('.cs', '.vb', '.aspx', '.cshtml', '.html', '.htm', '.css', '.js', '.txt', '.config', '.json', '.ps1', '.md')

    # 從 Console 標準輸入(Claude Code傳遞的參數)取得 JSON 字串
    $inputJson = [Console]::In.ReadToEnd()
	# 將 JSON 字串轉換為 JSON 物件
    $objJson = $inputJson | ConvertFrom-Json

    # 取得 file_path 的值 ( Claude Code 叫用內部工具會傳入要寫檔的檔案路徑)
    $filePath = $objJson.tool_input.file_path
    # 取得檔案名稱
    $fileName = [System.IO.Path]::GetFileName($filePath)
    # 取得副檔名(轉小寫方便比較)
    $fileExtension = [System.IO.Path]::GetExtension($fileName).ToLower()
   
    # 檢查副檔名是否在允許清單中
    if ($allowedExtensions -notcontains $fileExtension) {
        # 無須處理,離開腳本並回傳成功狀態碼
        exit 0
    }
	
    # 通過白名單副檔名檢查,需要進行編碼轉換

    # 讀取檔案內容,使用 -Raw 參數以取得完整內容並當作一個字串
    $content = Get-Content -Path $filePath -Raw -Encoding UTF8
    
    # 建立帶 BOM 的 UTF8 編碼器
    $utf8BOM = New-Object System.Text.UTF8Encoding $true
    
    # 重新寫入檔案 (帶 BOM)
    [System.IO.File]::WriteAllText($filePath, $content, $utf8BOM) 

`$filePath = $objJson.tool_input.file_path`:Claude Code 執行內部工具觸發 Hooks 會傳遞給你的 Powershell 參數請參考官網↓

Powershell腳本我儲存在 Claude Code 的 User Memory (CLAUDE.md)所在目錄,供各專案使用。

記得檔案另存編碼為 UTF8 with BOM,因為 Powershell 是微軟的技術。

2-2. 在 Claude Code 的 設定檔(settings.json) 加入以下 hooks 的設定

"PostToolUse":Claude Code 的內部工具執行完畢之後。

指定matcher當建立(Write)檔案、編輯(Edit)檔案之後,要觸發 cmd指令(目前也只有"type": "command")

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "powershell -ExecutionPolicy Bypass -File C:/Users/shadow/.claude/ConvertTo-Utf8BOM.ps1"

          }
        ]
      }
    ]
  }
}

留意幾點:

"matcher":英文官方文件最新版已經沒有 MultiEdit 這個參數,哪天參數 Edit 改名稱叫 Update 也不意外(因為我看目前版本的 Claude Code 內部工具在編輯檔案用的是 Update 指令)

"command": "powershell -ExecutionPolicy Bypass C:/Users/shadow/.claude/ConvertTo-Utf8BOM.ps1 yourParam"

這段 command 最後面若有想要傳入你自己的參數(yourParam),這帶入的參數會是常數變量,從 settings.json 設定檔是無法取得 Claude Code 呼叫它內部工具時的參數,

因為 Claude Code 會傳遞的參數目前都放在 Console 的標準輸入裡,須透過執行腳本這類方法才能取得。(請參考上述的 Powsershell 的 `[Console]::In.ReadToEnd()`)

settings.json:Claude Code 的設定檔,不能寫入英文或中文註解,否則會無法套用。

每當設定檔編輯完畢,必須重新啟動 Claude Code,讓它重新載入 settings.json 才會生效。

設定檔的hooks視自己需求看是要寫在全域或是專案的 settings.json,生效的作用範圍不一樣:全域設定檔→Claude Code 的每個工作專案都生效;專案設定檔→僅限該工作專案。

以下圖片是設置在專案設定檔。啟動 Claude Code 的目錄通常也是 Visual Studio 的方案目錄

settings.json記得編碼要另存成 UTF-8 ,因為是 Claude Code 使用

Claude Code 的 Hooks 解決方案適用情況:

一人獨自開發、環境單純好掌握、公司全員同事都使用 Windows 作業系統、沒有想要跨平台、

程式碼檔案通通使用 UTF8 with BOM 編碼也無妨的重度使用微軟技術的工程師

 

結語

以上,挑選適合自己的解決方案使用

參考文章

Claude Docs 官方文件:Hooks reference

Hooks才是Claude Code CLI 的革命性更新