[食譜好菜] 實作一個存取資料庫 Web Api 來體驗一下 Azure Functions 的輕便

有一些專案它的生命週期不長,像是商業活動專案,活動過了,專案也就跟著結束,如果使用者不多,而且使用者大都集中在某個時段才會操作系統,那 Azure Functions 是挺合適的解決方案;又或者,我們有一些排程工作,執行的間隔時間很長,可能一天才一次,用 Azure Functions 也很適合。

Azure Functions 有一個計費方案是可以按「」以「」計費,就是它是按照呼叫次數及資源的使用時長來收錢,每個月的免費額度是 1,000,000 以內的呼叫次數,以及 400,000 GB 以內的資源使用量。

舉例來說,假設我們的 Web Api 一整個月被呼叫了 1,010,000 次,每次執行時長為 10 秒、耗用了 100 MB 的記憶體空間,那麼會被收兩筆費用,分別是 10,000 的呼叫次數,以及 586,328.125 GB 的資源使用量,Azure Functions 的相關定價資訊請參考這裡

建立 Function App

我們登入到 Azure 的後台之後,找到「函數應用程式」的服務,點擊「+建立」。

我打算用 .NET Core 3.1 去開發 Azure Functions,所以我們在跳出來的刀鋒畫面中,挑選或新建「資源群組」,輸入「函數應用程式名稱」,發佈選擇「代碼」,執行階段堆疊選擇「.NET」,版本選擇「3.1」,最後挑選「地區」。

下一步我們來到「裝載中」的頁面,Function App 需要一塊儲存空間用來存放發佈上來的程式、設定、...等等的檔案,挑選或新建一個「儲存體帳戶」,作業系統我選的是「Linux」,最後方案類型選擇「使用量 (無伺服器)

下面我們來到「監視」的頁面,在這邊我們可以選擇要不要啟用「Application Insights」,啟用的話會有額外的費用產生,這個就自己斟酌。

最後我們就按「檢閱+建立」,把 Function App 建立起來。

每個 Function App 都會有一個唯一的網址,瀏覽那個網址就會看到提示 Function App 正在執行中的畫面。

建立 Azure Functions 專案

接下來我們就要來開發程式了,我用的 Visual Studio 版本是 2019,在「雲端」的專案類型當中就可以找到「Azure Functions」的專案範本。

然後,我們選擇「Http trigger」。

這邊簡單說明一下,Azure Functions 的程式主體有兩個部分:Logic(程式邏輯)Trigger(觸發器),Logic 負責執行主要的工作,而 Trigger 則是負責觸發 Logic 執行,Http trigger 顧名思義就是用透過 HTTP Request 的方式來觸發程式執行,從上圖中我們可以看到還有好多種不同的 Trigger,我們可以按照我們的需要選擇合適的 Trigger。

畫面右手邊的 Authorization level 選項,我建議如果我們的 Function App 不會開放給不特定的對象來使用的話,至少選擇 Function Level,在呼叫 Web Api 的時候要帶上金鑰進行驗證。

撰寫 Function 程式

專案建立起來之後,我們可以看到範本已經有幫我們建好一個 Function 的範例,方便起見,我就不額外建立 Function,直接拿範本 Function 來改。

我們眼睛所看到的程式碼基本上都可以改,只有其中 FunctionNameHttpTrigger attribute 不能刪,不過裡面的參數可以改,那我的需求是從資料庫裡面撈一筆資料出來回傳,我就開始動手修改 Function。

假定我已經有建好的資料庫,裡面有一張 Member 資料表,包含了兩個欄位 IdName,然後我將整個 Function 改成可以傳入 Id 做為條件,去資料庫將 Member 撈出來。

public static class Function1
{
    [FunctionName("MemberFunction")]
    public static async Task<IActionResult> RunMemberFunction(
        [HttpTrigger(AuthorizationLevel.Function, "get", Route = "member/{id:int}")] HttpRequest req,
        int id,
        ILogger log)
    {
        var sql = @"
SELECT
    m.Id
   ,m.[Name]
FROM Member m WITH (NOLOCK)
WHERE m.Id = @Id";

        Member member;

        using (var db = new SqlConnection("ConnectionString"))
        {
            // Dapper required.
            member = await db.QuerySingleOrDefaultAsync<Member>(sql, new { Id = id });
        }

        return new JsonResult(member);
    }
}

public class Member
{
    public int Id { get; set; }

    public string Name { get; set; }
}

發佈

如果測試沒什麼問題,我們就可以嘗試將專案發佈到我們剛剛建好的 Function App,順著一路設定下去,沒什麼問題的話,應該是可以看到「已成功重新啟動函數應用程式。」的訊息。

在發佈的過程當中出現一點小亂流,發佈顯示失敗,查詢日誌叫我去「輸出」視窗看更詳細的資訊,但是根本看不到什麼錯誤訊息,這時候可以試著將 Function App 停止,再發佈看看。

金鑰

發佈完成後,我們如果直接去呼叫 Web Api 應該會收到 401 Unauthorized 的回應。

因為我們沒有將 Web Api 開放給匿名的使用者使用,所以要呼叫 Web Api 的話需要帶上一組「金鑰」,Function App 預設會給兩個「主機金鑰(Host Key)」,主機金鑰屬於應用程式層級的,它可以呼叫應用程式當中的所有 HTTP Function,所以請不要輕易給出去。

我們要給使用者的是「函式金鑰(Function Key),我們從「函式」頁面裡面去點擊某一個函式。

進到單一函式的頁面之後,我們找到「功能鍵(Function Keys)」,這一個金鑰才是函式專屬的金鑰。

帶上金鑰的方式是在 QueryString 加上 code={金鑰} 這個參數,再呼叫 Web Api 應該就能成功收到回應了。

這種用多少算多少的 PaaS 服務,對於使用量不大的應用程式來說,算是 CP 值相當高的解決方案,甚至有機會可以不用花一毛錢,市面上的其他雲端平台也有類似 Azure Functions 的服務,不過我個人覺得從開發到部署,微軟將整個過程整合得還不錯,推薦給各位朋友,各位朋友可以嘗試著使用看看。

相關資源

C# 指南
ASP.NET 教學
ASP.NET MVC 指引
Azure SQL Database 教學
SQL Server 教學
Xamarin.Forms 教學