[Cloud CICD] 後端篇 - .Net8 WebApi, Github Action, Azure App Service

前言:本篇記錄了將 .NET 8 Web API 專案部署到 Azure App Service 的完整流程,包含 GitHub Actions 自動化部署設定。重點包含 Publish Profile 設定環境變數階層設定,以及 Database 防火牆 IP 白名單設定

📦 技術堆疊

⚙️ 後端框架 .NET 8 Web API
🔄 CI/CD GitHub Actions
☁️ 雲端平台 Azure App Service

🗺️ 部署流程總覽

1. 推送 .NET 8 API 至 GitHub
2. 建立 Azure App Service
3. 下載 Publish Profile
4. 設定 GitHub Secrets
5. 建立 GitHub Actions Workflow
6. 設定 Environment Variables
7. 設定 Database 防火牆
8. 部署成功 🎉

📝 詳細步驟

1推送 .NET 8 Web API 專案至 GitHub

確保你的 .NET 8 Web API 專案已建立並推送到 GitHub Repository。

📁 專案結構檢查
project-root/
├── Controllers/           # API Controllers
├── Models/               # 資料模型
├── Services/             # 商業邏輯
├── appsettings.json      # 開發環境設定
├── appsettings.Production.json  # 正式環境設定
├── Program.cs
└── YourProject.csproj
💻 Git 指令
git init
git add .
git commit -m "Initial commit: .NET 8 Web API"
git remote add origin https://github.com/你的帳號/你的專案.git
git push -u origin main

2在 Azure Portal 建立 App Service

  1. 登入 Azure Portal
  2. 搜尋「App Services」→ 點擊「建立」→「Web 應用程式」
  3. 填寫基本資訊:
    • 訂用帳戶:選擇你的訂用帳戶
    • 資源群組:建立新的或選擇現有的
    • 名稱:輸入應用程式名稱(例如:my-dotnet8-api)
    • 發佈:程式碼
    • 執行階段堆疊:.NET 8 (LTS)
    • 作業系統:Windows 或 Linux
    • 區域:East Asia
  4. 定價方案:
    • 開發/測試:F1(免費)或 B1(基本)
    • 生產環境:S1 或以上
  5. 點擊「檢閱 + 建立」→「建立」

3下載 Publish Profile(關鍵步驟)

部署完成後,進入你的 App Service:

  1. 在左側選單找到「部署」→ 選擇「部署中心」
  2. 或直接在頂部工具列點擊「取得發行設定檔」按鈕
  3. 會下載一個 .PublishSettings 檔案
  4. 用文字編輯器開啟這個檔案,複製整個檔案的內容
⚠️ 重要提醒:

這個 Publish Profile 包含敏感資訊(帳號密碼),絕對不要直接提交到 Git Repository!我們會將它安全地儲存在 GitHub Secrets 中。

4在 GitHub 設定 Secrets

前往你的 GitHub Repository:

  1. 點擊「Settings」頁籤
  2. 在左側選單找到「Secrets and variables」→「Actions
  3. 點擊「New repository secret
  4. 設定如下:
    • Name:AZURE_WEBAPP_PUBLISH_PROFILE
    • Secret:貼上剛才複製的 Publish Profile 內容
  5. 點擊「Add secret」儲存
💡 提示:

Secret 名稱必須是 AZURE_WEBAPP_PUBLISH_PROFILE,這樣 GitHub Actions 才能正確讀取。

5建立 GitHub Actions Workflow

在專案根目錄建立 .github/workflows/azure-deploy.yml

📄 .github/workflows/azure-deploy.yml
name: Deploy .NET 8 API to Azure

on:
  push:
    branches:
      - main
  workflow_dispatch:

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    
    steps:
      # 1. Checkout 程式碼
      - name: Checkout code
        uses: actions/checkout@v3
      
      # 2. 設定 .NET 8
      - name: Setup .NET 8
        uses: actions/setup-dotnet@v3
        with:
          dotnet-version: '8.0.x'
      
      # 3. 還原套件
      - name: Restore dependencies
        run: dotnet restore
      
      # 4. 建置專案
      - name: Build
        run: dotnet build --configuration Release --no-restore
      
      # 5. 發行專案
      - name: Publish
        run: dotnet publish --configuration Release --no-build --output ./publish
      
      # 6. 部署到 Azure App Service
      - name: Deploy to Azure Web App
        uses: azure/webapps-deploy@v2
        with:
          app-name: 'my-dotnet8-api'  # 改成你的 App Service 名稱
          publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}
          package: ./publish
⚠️ 記得修改:

app-name: 'my-dotnet8-api' 改成你實際的 Azure App Service 名稱!

6推送程式碼,觸發部署

git add .github/workflows/azure-deploy.yml
git commit -m "Add GitHub Actions workflow for Azure deployment"
git push origin main

推送後,前往 GitHub Repository 的「Actions」頁籤,可以看到部署流程正在執行。

✅ 第一次部署完成!

現在 API 已經成功部署到 Azure,但還需要設定環境變數和資料庫連線。

⚙️ 關鍵設定:Environment Variables

7設定 Azure App Service 環境變數

🔑 為什麼需要環境變數?

在 Azure 上,不應該使用 appsettings.json 儲存敏感資訊(如資料庫連線字串、API Key)。正確做法是使用 Azure App Service 的環境變數功能。

設定步驟:

  1. 進入你的 Azure App Service
  2. 在左側選單找到「Settings」→「Environment variables
  3. 點擊「+ Add」新增應用程式設定

重要!使用雙底線(__)區隔階層

在 Azure App Service 中,環境變數使用 __(雙底線)來表示 JSON 的階層結構。

📌 範例對照表

原本的 appsettings.json:

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=myserver.database.windows.net;Database=mydb;..."
  },
  "JwtSettings": {
    "Key": "your-secret-key",
    "Issuer": "your-issuer",
    "Audience": "your-audience"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information"
    }
  }
}

轉換成 Azure Environment Variables:

Name(變數名稱) Value(值)
ConnectionStrings__DefaultConnection Server=myserver.database.windows.net;Database=mydb;...
JwtSettings__Key your-secret-key
JwtSettings__Issuer your-issuer
JwtSettings__Audience your-audience
Logging__LogLevel__Default Information
💡 規則總結:
  • appsettings.json 中的每一層用 __ 連接
  • 例如:Section:SubSection:KeySection__SubSection__Key
  • 環境變數會覆蓋 appsettings.json 中的相同設定

實際操作畫面:

在 Azure Portal 的 Environment variables 頁面中:

  1. 點擊「+ Add
  2. Name:輸入變數名稱(使用 __ 區隔)
  3. Value:輸入對應的值
  4. 點擊「OK
  5. 完成所有設定後,點擊頁面上方的「Apply」儲存變更
⚠️ 重要:

修改環境變數後,App Service 會自動重新啟動,可能會有短暫的服務中斷。

🔥 關鍵設定:Database 防火牆

8設定 Azure Database 防火牆規則

❌ 常見錯誤

部署完成後,API 無法連線到 Azure SQL Database,錯誤訊息類似:

Cannot open server 'xxx' requested by the login. 
Client with IP address 'x.x.x.x' is not allowed to access the server.

原因:Azure SQL Database 預設啟用防火牆,只有白名單內的 IP 才能連線。

解決步驟:取得 App Service 的 Outbound IP

  1. 進入你的 Azure App Service
  2. 在左側選單找到「Settings」→「Networking
  3. 找到「Outbound traffic configuration」區塊
  4. 記錄下「Outbound addresses」中列出的所有 IP(通常有 4-6 個)
💡 範例:

Outbound addresses 可能看起來像這樣:

20.195.XX.XX, 20.195.XX.XX, 20.195.XX.XX, 20.195.XX.XX

將 IP 加入 Azure SQL Database 防火牆

  1. 前往你的 Azure SQL Database
  2. 在左側選單找到「Security」→「Networking
  3. 在「Firewall rules」區塊,點擊「+ Add a firewall rule
  4. 設定規則:
    • Rule name:AppService-OutboundIP-1(自訂名稱)
    • Start IP:貼上第一個 Outbound IP
    • End IP:貼上第一個 Outbound IP(相同)
  5. 重複步驟 3-4,將所有 Outbound IP 都加入防火牆規則
  6. 點擊「Save」儲存變更
⚠️ 重要提醒:
  • Outbound IP 可能會在 App Service 重新啟動或擴展時變動
  • 建議將所有列出的 IP 都加入防火牆,以避免連線問題
  • 生產環境建議使用 VNet 整合私人端點提高安全性

替代方案:允許 Azure 服務存取

如果你的 Database 和 App Service 在同一個 Azure 區域,可以啟用「允許 Azure 服務和資源存取此伺服器」:

  1. 在 Database 的「Networking」頁面
  2. 找到「Exceptions」區塊
  3. 勾選「Allow Azure services and resources to access this server
  4. 點擊「Save
⚠️ 安全性提醒:

這個選項會允許所有 Azure 服務存取你的資料庫,包含其他 Azure 客戶的資源。生產環境建議使用 IP 白名單或 VNet 整合。

9設定 CORS(跨來源資源共用)

🌐 什麼是 CORS?

當你的前端(例如 Vue3 應用程式)部署在 https://your-frontend.azurestaticapps.net,而後端 API 在 https://your-api.azurewebsites.net 時,瀏覽器會阻擋這種跨網域請求。

CORS(Cross-Origin Resource Sharing)就是用來允許這種跨網域存取的機制。

設定方式比較

在 Azure App Service 中,有兩種方式設定 CORS:

方式 優點 缺點
方法 1:程式碼 + 環境變數 • 可以在程式碼中完全控制
• 支援複雜的 CORS 策略
• 可以條件式設定
• 需要修改程式碼
• 需要重新部署才能生效
方法 2:Azure Portal 設定 • 無需修改程式碼
• 立即生效,無需重新部署
• 操作簡單直觀
• 功能較為基礎
• 與程式碼設定可能衝突
💡 建議:
  • 開發/測試環境:使用 Azure Portal 設定,方便快速調整
  • 生產環境:使用程式碼 + 環境變數,更安全且可版控

方法 1:程式碼 + 環境變數設定(推薦)

步驟 1:修改 Program.cs

📄 Program.cs
var builder = WebApplication.CreateBuilder(args);

// 讀取環境變數中的 CORS 設定
var allowedOrigins = builder.Configuration
    .GetSection("CorsSettings:AllowedOrigins")
    .Get<string[]>() ?? Array.Empty<string>();

// 設定 CORS
builder.Services.AddCors(options =>
{
    options.AddPolicy("AllowSpecificOrigins", policy =>
    {
        policy.WithOrigins(allowedOrigins)
              .AllowAnyMethod()
              .AllowAnyHeader()
              .AllowCredentials();  // 如果需要傳送 Cookie
    });
});

builder.Services.AddControllers();
// ... 其他服務設定

var app = builder.Build();

// 啟用 CORS(必須在 UseRouting 之後、UseAuthorization 之前)
app.UseCors("AllowSpecificOrigins");

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();

步驟 2:在 appsettings.json 設定預設值(開發環境)

📄 appsettings.json
{
  "CorsSettings": {
    "AllowedOrigins": [
      "http://localhost:5173",  // Vite 開發伺服器
      "http://localhost:3000"   // 其他前端開發伺服器
    ]
  }
}

步驟 3:在 Azure App Service 設定環境變數(生產環境)

  1. 進入 Azure App Service
  2. 左側選單:SettingsEnvironment variables
  3. 點擊「+ Add」新增以下設定:
Name Value
CorsSettings__AllowedOrigins__0 https://your-frontend.azurestaticapps.net
CorsSettings__AllowedOrigins__1 https://your-custom-domain.com
⚠️ 陣列設定注意事項:
  • 陣列元素使用 __0__1__2 表示索引
  • 例如:CorsSettings:AllowedOrigins[0]CorsSettings__AllowedOrigins__0

方法 2:直接在 Azure Portal 設定

如果你不想在程式碼中處理 CORS,可以直接透過 Azure Portal 設定:

  1. 進入你的 Azure App Service
  2. 在左側選單找到「API」→「CORS
  3. 在「Allowed Origins」欄位中,每行輸入一個網址
    https://your-frontend.azurestaticapps.net
    https://your-custom-domain.com
    http://localhost:5173
  4. (可選)勾選「Enable Access-Control-Allow-Credentials」如果需要傳送 Cookie
  5. 點擊「Save」儲存
⚠️ 重要警告:

絕對不要在生產環境使用萬用字元 *

這會允許任何網站呼叫你的 API,造成嚴重的安全風險。

兩種方法衝突處理

⚠️ 注意:

如果你同時在程式碼中設定 CORS,又在 Azure Portal 設定 CORS,可能會造成衝突!

建議做法:

  • 只選擇其中一種方法使用
  • 如果使用程式碼設定,建議把 Azure Portal 的 CORS 設定保持空白
  • 如果使用 Azure Portal 設定,記得移除程式碼中的 CORS 設定

測試 CORS 設定

方法 1:使用瀏覽器開發者工具

  1. 開啟前端網站
  2. 按 F12 開啟開發者工具
  3. 切換到「Console」或「Network」頁籤
  4. 呼叫 API
  5. 檢查是否出現 CORS 錯誤:
    ❌ 錯誤範例:
    Access to fetch at 'https://your-api.azurewebsites.net/api/users' 
    from origin 'https://your-frontend.azurestaticapps.net' 
    has been blocked by CORS policy

方法 2:使用 cURL 測試

curl -i -X OPTIONS https://your-api.azurewebsites.net/api/users \
  -H "Origin: https://your-frontend.azurestaticapps.net" \
  -H "Access-Control-Request-Method: GET"

如果 CORS 設定正確,回應中應該包含:

Access-Control-Allow-Origin: https://your-frontend.azurestaticapps.net
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: *

常見 CORS 錯誤排解

錯誤 1:The CORS protocol does not allow specifying a wildcard

原因:當你設定了 AllowCredentials() 時,不能使用 AllowAnyOrigin()

解決:改用 WithOrigins() 明確指定網址

錯誤 2:Response to preflight request doesn't pass access control check

原因:OPTIONS 請求(Preflight)失敗

解決:

  • 確認 app.UseCors() 的順序正確(在 UseRouting 之後)
  • 確認 CORS 策略名稱正確

錯誤 3:網址末尾的斜線問題

現象:https://example.comhttps://example.com/ 被視為不同網址

解決:在 Azure 設定時不要在網址末尾加斜線

10從 SQL Database 取得連線字串並設定環境變數

完成資料庫建立和資料匯入後,需要將連線字串設定到 App Service,讓後端 API 能夠連接資料庫。

步驟 1:從 Azure SQL Database 複製連線字串

  1. 進入 Azure Portal,前往你的 SQL Database(不是 SQL Server)
  2. 在左側選單找到「Settings」→「Connection strings
  3. 選擇「ADO.NET (SQL authentication)」頁籤
  4. 複製完整的連線字串,看起來像這樣:
📄 原始連線字串(從 Azure 複製)
Server=tcp:your-server-name.database.windows.net,1433;Initial Catalog=YourDatabaseName;Persist Security Info=False;User ID=your-username;Password={your_password};MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;

步驟 2:修改連線字串(替換密碼)

注意到連線字串中的 {your_password} 是一個佔位符號,需要替換成你在建立 SQL Server 時設定的實際密碼。

⚠️ 注意:

{your_password}(包含大括號)整個替換成你的密碼,不要只是刪除大括號!

✅ 修改後的連線字串(範例)
Server=tcp:my-sql-server-2025.database.windows.net,1433;Initial Catalog=MyAppDB;Persist Security Info=False;User ID=sqladmin;Password=MyStr0ngP@ssw0rd!;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;

步驟 3:設定到 Azure App Service 環境變數

  1. 前往你的 Azure App Service
  2. 在左側選單找到「Settings」→「Environment variables
  3. 在「Application settings」區塊,點擊「+ Add
  4. 填寫以下資訊:
Name(變數名稱) Value(值)
ConnectionStrings__DefaultConnection 貼上步驟 2 修改後的完整連線字串
💡 重要提醒:
  • 變數名稱使用 雙底線 __ 來表示階層
  • ConnectionStrings:DefaultConnectionConnectionStrings__DefaultConnection
  • 如果你在 appsettings.json 中使用不同的名稱(例如 MyDbConnection),記得對應修改
  1. 點擊「OK
  2. 點擊頁面上方的「Apply」儲存變更
  3. App Service 會自動重新啟動(約 10-30 秒)

步驟 4:在程式碼中使用連線字串

確保你的 .NET 專案中正確讀取連線字串:

📄 Program.cs
var builder = WebApplication.CreateBuilder(args);

// 從 Configuration 讀取連線字串
var connectionString = builder.Configuration
    .GetConnectionString("DefaultConnection");

// 註冊 DbContext
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));

// ... 其他設定

var app = builder.Build();
app.Run();
📄 appsettings.json(本機開發環境)
{
  "ConnectionStrings": {
    "DefaultConnection": "Server=localhost;Database=MyAppDB;Trusted_Connection=True;"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information"
    }
  }
}
💡 工作原理:

Azure App Service 的環境變數會自動覆蓋 appsettings.json 中的相同設定。所以:

  • 本機開發:使用 appsettings.json 中的本機資料庫
  • Azure 部署:自動使用環境變數中的 Azure SQL Database
  • 不需要修改程式碼,也不會把敏感資訊提交到 Git

步驟 5:測試連線

部署後測試資料庫連線是否正常:

  1. 前往你的 API 網址:https://your-api.azurewebsites.net
  2. 測試需要資料庫的 API 端點(例如:/api/users
  3. 如果出現錯誤,查看 App Service 的 Log Stream:
    • App Service → Monitoring → Log stream
    • 選擇「Application logs」

常見錯誤排解

❌ 錯誤 1:Login failed for user

可能原因:

  • 密碼錯誤(包含大括號沒有移除)
  • 帳號名稱錯誤

解決方法:

  • 重新從 Azure 複製連線字串
  • 確認密碼完全正確(區分大小寫)
  • 確認 {your_password} 已被替換

❌ 錯誤 2:Cannot open server requested by the login

可能原因:

  • App Service 的 Outbound IP 沒有加入 SQL Database 防火牆

解決方法:

  • 回到第 6 步:設定後端防火牆(App Service Outbound IP)
  • 確認所有 Outbound IP 都已加入防火牆規則

❌ 錯誤 3:A network-related or instance-specific error

可能原因:

  • 連線字串格式錯誤
  • 伺服器名稱或資料庫名稱錯誤

解決方法:

  • 檢查連線字串中的 ServerInitial Catalog 是否正確
  • 確認沒有多餘的空格或換行

❌ 錯誤 4:The connection string is null or empty

可能原因:

  • 環境變數名稱錯誤(沒有使用雙底線)
  • 程式碼中讀取的名稱與環境變數不匹配

解決方法:

  • 確認環境變數名稱:ConnectionStrings__DefaultConnection
  • 確認程式碼中使用:GetConnectionString("DefaultConnection")

額外建議:設定開發環境連線字串

為了方便本機測試 Azure SQL Database,可以新增 appsettings.Development.json

📄 appsettings.Development.json
{
  "ConnectionStrings": {
    "DefaultConnection": "Server=tcp:your-server.database.windows.net,1433;Initial Catalog=YourDB;User ID=sqladmin;Password=YourPassword;Encrypt=True;"
  }
}
⚠️ 安全提醒:

如果將 appsettings.Development.json 包含密碼,記得將此檔案加入 .gitignore,避免密碼洩漏!

✅ 完整測試流程

部署後驗證清單

  1. ✅ 前往你的 API 網址:https://你的app名稱.azurewebsites.net
  2. ✅ 測試 Swagger UI(如果有啟用):/swagger
  3. ✅ 測試 API 端點是否正常回應
  4. ✅ 檢查資料庫連線是否正常(嘗試讀取/寫入資料)
  5. ✅ 查看 Azure App Service 的 Log Stream 確認沒有錯誤

如何查看 Log

  1. 進入 Azure App Service
  2. 左側選單找到「Monitoring」→「Log stream
  3. 選擇「Application logs
  4. 即時查看應用程式的 Console 輸出

🐛 常見問題排解

問題 1:部署成功但網站顯示 500 錯誤

可能原因:

  • 環境變數設定錯誤(檢查雙底線 __ 是否正確)
  • 缺少必要的環境變數
  • 資料庫連線失敗

解決方法:查看 Log Stream 找出具體錯誤訊息

問題 2:Cannot open server requested by the login

原因:App Service 的 Outbound IP 沒有加入 Database 防火牆白名單

解決方法:按照步驟 8 設定防火牆規則

問題 3:GitHub Actions 部署失敗

檢查項目:

  • 確認 AZURE_WEBAPP_PUBLISH_PROFILE Secret 已正確設定
  • 確認 workflow 檔案中的 app-name 正確
  • 檢查 Publish Profile 是否過期(重新下載並更新)

📚 重點整理

🔑 關鍵要點:
  1. Publish Profile:從 Azure 下載後儲存在 GitHub Secrets,變數名稱必須是 AZURE_WEBAPP_PUBLISH_PROFILE
  2. 環境變數:使用 __(雙底線)區隔 JSON 階層,例如 ConnectionStrings__DefaultConnection
  3. 防火牆設定:必須將 App Service 的所有 Outbound IP 加入 Database 防火牆白名單
  4. Log 查看:使用 Log Stream 即時監控應用程式運作狀況

🔗 相關資源


希望這篇文章能幫助你順利部署 .NET 8 API 到 Azure!
如果遇到其他問題,歡迎留言討論 😊

留言

這個網誌中的熱門文章

[C#] 無法載入檔案或組件 或其相依性的其中之一。 找到的組件資訊清單定義與組件參考不符。 (發生例外狀況於 HRESULT: 0x80131040)

[Cloud CICD] 前端篇 - Vue3, Github Action, Azure Static Web App