使用 Azure Functions + Line Notify 來定時提醒公車到站時間
在上週的 使用 Powershell + 工作排程器 + Line Notify 來定時提醒公車到站時間,我們利用工作排程器來定時觸發腳本,藉此用 Line 提醒我下班的公車還有多久才來。
做完之後靈機一動,對呀!最近上班挺常接觸到 Azure Functions 這個方便東東,不如就把這個小提醒給架設到 Azure Functions 上吧!
這樣就省卻了特定主機要開著掛工作排程器的困擾,又可以用香香的 Azure 工具來控制監聽的開關,豈不美哉。
如此如此這般這般,讓我們開始建立 Azure Functions 服務吧!
建立 Azure Functions 資源
Azure Functions 是 Azure 推出的一款無伺服器(Serverless)服務,簡單來說就是伺服器之類的麻煩事就交給 Azure 去處理,我們只要專心寫功能就好。對我這種愛寫小腳本的偷懶工程師來說,可以說是香到爆的服務。
小提醒:Azure Functions 是一款收費服務,使用前請務必確認定價。
在這篇文章撰寫當下,Azure Functions 有提供每月免費執行一百萬次的授權,對我們每天一次的公車通知來說綽綽有餘了(我們應該不會搭這麼多趟吧…?)
首先讓我們到 Azure 建立一個函數應用程式(如果用英文,請找 Azure Functions):
接著進到建立 Functions 的頁面,讓我們先選好資源群組,並取個好名字
因為「MyFunctions」之類的都被取走了,這邊就直接取「林北ㄟ Functions」:
執行階段堆疊請選擇自己開發用的語言,我這邊使用 .Net 6 進行開發,作業系統則按照建議的選擇。
這邊要稍微注意方案的選擇!如同前面提到的定價,也可以參照 Microsoft Docs 的預估 Azure Functions 中的取用方案成本說明,裡面會有使用量、進階等方案的說明。
這次我們要做的只是簡單的提醒通知,所以就選費用最低的使用量計價就好囉~
按下確認後就會開始部屬:
部屬完成就可以前往我們建立的資源囉,可以在這裡確認記憶體、執行次數等資訊:
從左側的「函式」可以確認我們現在有哪些 Functions,當然目前還是空的:
接著就讓我們來撰寫第一個 Function 吧!
使用 Azure Functions 開發公車到站提醒服務
因為這篇的功能完全是使用 Powershell + 工作排程器 + Line Notify 來定時提醒公車到站時間的完美復刻版,因此我們要做的事情還是一樣:
- 每天下班前十分鐘(定時執行)
- 告訴我(通知功能)
- 下一班到達的公車時間(查詢資訊)
只是這次的功能使用 .Net 6 撰寫,並且使用 Visual Studio 為範例來記錄,定時功能則從臭臭又綁電腦的工作排程器改用香香 Azure Functions 的定時觸發功能。
建立 Azure Funtcions 專案
首先讓我們新增專案,內建已經有 Azure Functions 的範例可以使用:
取個好名字,這邊沿用剛剛開資源的命名:
接著就要選擇版本,這邊要注意 Azure Function 目前還有分出隔離版(Isolated):
簡單來說,原本的 Azure Functions 和主機環境太耦合了,如果用到同一個套件不同版本就有可能翻車。因此推出了隔離式的 Azure Functions 讓我們可以乾乾淨淨地用。
想更了解隔離式版本的差異,可以參見:
- 在隔離式程序中執行 C# Azure Functions 的指南 | Microsoft Docs
- Is it time to start creating C# Azure Functions in isolated mode? (markheath.net)
由於 .NET on Azure Functions Roadmap 的示意圖:
明確指出將來的主軸會是隔離式(Isolated),因此我們這邊專案也選擇 .Net 6 已隔離的版本。這樣我往後抄起來比較方便
小提示:查詢 Azure Functions 相關資料時也要注意版本的差異!在 .Net 開發隔離式的 SDK 並不一樣,連最基本標示 Function 的語法,原本是
[FunctionName()]
,隔離式也改成了更簡潔的[Function()]
,因此查資料或開發時要特別注意版本差異,避免被 IDE 畫了紅線卻搞不懂為什麼。
接著我們就可以選擇 Function 的觸發條件,因為我們要定時提醒,因此這邊選擇 Timer Trigger 就可以了:
同樣常用的還有當成 API 打的 Http Trigger,以及和我們上一次介紹過的 ServiceBus 一起使用的 Service Bus Queue/Topic Trigger 等等。
關於提供的觸發方式和程式碼範例,可以參照 Microsoft Docs 的 Azure Functions 中的觸發程序和繫結
最後因為我們選擇了 Timer Trigger,這邊提供我們直接設定時間。使用的是 NCrontab 格式,可以參考 NCRONTAB expressions 的說明,Visuat Studio 上也有簡短地介紹:
按照需求,我們希望下班前,也就是每天的 17:45 左右能提醒公車預估到站的時間。
NCrontab 和常見的 Crontab 差在多了第一個欄位來控制秒,因此這邊果斷直接使用 Cronitor 查一下,再往前加上一欄當作秒數即可。
補充:另一個香香工具 DevToys 也能迅速組裝和確認 Cron 語法呦!
每天的 17:45 在 Crontab 表示為「45 17 * * *」:
我們希望在 0 秒的時候觸發,因此轉 NCrontab 時需要在秒的位置指定 0,也就是「0 45 17 * * *」
但在填到 Azure Functions 要注意,在伺服器的時間會是 UTC+0。為了在台灣,也就是 UTC+8 的 17:45 觸發,因此將時間更改為「0 45 9 * * *」,否則 Line 就會在半夜通知你起來搭公車
這樣其他資訊的頁面就填寫完了,可以按下建立囉!
建立後會看到 Visual Studio 已經使用我們剛剛的設置建立了一個 Function 及 Timer Trigger,時間也填好了(如果後續還要調整時間,就修改 TimerTrigger
的值就好):
public class Function1
{
private readonly ILogger _logger;
public Function1(
ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<Function1>();
}
[Function("Function1")]
public void Run([TimerTrigger("0 45 9 * * *")] MyInfo myTimer)
{
_logger.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
_logger.LogInformation($"Next timer schedule at: {myTimer.ScheduleStatus.Next}");
}
}
為了後續管理方便,我們先改個名。這邊就叫做 BusReminderFunctions
吧:
public class BusReminderFunctions
{
private readonly ILogger _logger;
public BusReminderFunctions(
ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<BusReminderFunctions>();
}
[Function("BusReminder-TimerTrigger")]
public void RunTimerTrigger([TimerTrigger("0 45 9 * * *")] MyInfo myTimer)
{
_logger.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
_logger.LogInformation($"Next timer schedule at: {myTimer.ScheduleStatus.Next}");
}
}
並且為了測試方便,我們再增加一個 HttpTrigger,這時候會需要先去 Nuget 安裝相關的套件
搜尋 Microsoft.Azure.Functions.Worker.Extensions
就會看到各種 Trigger,這邊就安裝一下 Http 需要的套件吧:
現在讓我們回到 Functions,增加一個 HttpTrigger
,調整一下非同步,並建立一個私有方法 TrackBusAsync
,讓 HttpTrigger
和 TimerTrigger
都去呼叫這個方法,這樣我們就可以定時觸發也可以手動觸發它,後續測試起來也比較方便:
[Function("BusReminder-TimerTrigger")]
public async Task RunTimerTrigger([TimerTrigger("0 45 9 * * *")] MyInfo myTimer)
{
await TrackBusAsync();
}
[Function("BusReminder")]
public async Task<HttpResponseData> HttpTrigger(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req,
FunctionContext executionContext)
{
await TrackBusAsync();
var response = req.CreateResponse(HttpStatusCode.OK);
await response.WriteAsJsonAsync<object>(new { result = true });
return response;
}
private async Task TrackBusAsync()
{
throw new NotImplementedException();
}
補充:HttpTrigger 的參數有三個部份,可以拆分成:
- 授權層級:Anonymous, Admin 之類的,可參照授權層級
- 方法:Get, Post 之類的,沒指定就會是不限方法
- 路由:用來定義 API 路由,預設會拿 FunctionName,在這例子就是
BusReminder
都有指定的樣子會像這樣:
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]
這樣事前準備就差不多了,讓我們開始撰寫邏輯部分吧!
呼叫 MOTC Api 查詢公車到站預估時間
首先我們需要取得公車到站預估時間,這部分跟上一期一樣就直接從公共運輸動態服務 MOTC Transport API 的「市區公車之預估到站資料」(EstimatedTimeOfArrival/City/{City}/{RouteName}
) 這支 API 取得就行了。
2024.11.25 更新:發現 MOTC 的 API 已經下架了,現在公車資訊已經被整合到運輸資料服務 TDX (Transport Data eXchange),有要動手串公車資訊的朋友可能得觀察新版 API 再進行調整了 QQ
註:為了避免被查水表,以下就用台北的 307 號公車為例,並假設目標站點是「台北車站(忠孝)」
嘗試把縣市和公車路線名稱代入後,可以取得公車行經的站牌資訊,其中就有我們最想要的估計到站時間(秒):
在這個步驟我們還會需要調整 $top
參數的筆數,順便取得我們要監聽公車到站的站牌 ID(StopId)以及行進方向(Direction) 在這個例子中「台北車站(忠孝)」的站牌 ID 會是 15250
確保了資料來源之後,讓我們回到專案裡。
這次為了之後方便擴展,決定將公車名稱、站牌 ID 等查詢資訊放到組態裡。
註:接下來會使用到 依賴注入 以及讀取 Config 的 IOptions;對這兩項不太熟悉的朋友可以先看過去,並且在後續 BusReminderFunctions 的建構式裡把公車資訊寫死就好,並不會影響功能。
一般的 .Net 6 API 專案我們會把組態設定放到 appsettings.json
中,而在開發 Azure Functions 的時候,則會需要用到 host.json
和 local.settings.json
:
其中 host.json
用來設定站台相關的組態,例如在先前調整 ServiceBus Trigger 的時候,我們就是在 host.json
修改重新傳遞訊息到 Azure Functions 的時間。
而 local.settings.json
則是讓我們在本機開發時使用,對應到線上的組態設定:
可以看到 Azure 上的組態有「應用程式設定」和「連接字串」兩個區塊,而在本機開發時會對應到「Values」以及「ConnectionStrings」:
有個大概的認識之後,現在讓我們填入一些值吧。
現在我希望能從組態中,使用 IOptions 取得查詢公車估計時間相關的設定,因此我先建立了一個 Class BusTrackerOption
:
/// <summary>
/// 公車到站監聽設定
/// </summary>
public class BusTrackerOption
{
/// <summary>
/// 公車路線名稱
/// </summary>
public string RouteName { get; set; }
/// <summary>
/// 要預估到站的站牌 ID
/// </summary>
public int StopId { get; set; }
/// <summary>
/// 公車路線行進方向
/// </summary>
public int Direction { get; set; } = 0;
}
並且到 local.settings.json
加上組態。這邊要特別提到的是:原本我們在 appsettings.json
加上組態,會用這種階層式的寫法:
{
"BusTracker": {
"RouteName": "307",
"StopId" : 15250,
"Direction": 0
}
}
但我們前面已經看到了,在 Azure 上的組態實際上是一個單層的列表。因此我們會使用 __
當作分隔符號來將設定攤平,並放到 local.settings.json
的 Values
裡(如果是連線字串就放到 ConnectionStrings
裡),也就是像這樣:
{
"Values": {
// ...這裡會有其他組態設定
// 加上 BusTracker 的 參數,用 __ 來表示階層
"BusTracker__RouteName": 307,
"BusTracker__StopId": 15250,
"BusTracker__Direction": 0
}
}
接著讓我們到 Program.cs
來將 json 的設定值繫結到 BusTrackerOption
,Section 名稱要記得和 json 中的階層名稱對上
// 注意 Azure Functions 的 settings.json 的階層要用 __ 來區隔
services.AddOptions();
services.Configure<BusTrackerOption>(hostContext.Configuration.GetSection("BusTracker"));
註:如果像我一樣開 .Net 6,只看到
HostBuilder
的朋友,可以自行加入ConfigureServices((hostContext, services) => {})
的部份來註冊,如下:
接著就可以回到我們的 BusReminderFunctions
來把 IOptions<BusTrackerOption>
注入進來:
public class BusReminderFunctions
{
private readonly ILogger _logger;
private readonly BusTrackerOption _busTrackerOption;
public BusReminderFunctions(
ILoggerFactory loggerFactory,
IOptions<BusTrackerOption> busTrackerOption)
{
_logger = loggerFactory.CreateLogger<BusReminderFunctions>();
_busTrackerOption = busTrackerOption.Value;
}
// ...略
}
對依賴注入還不太熟悉的朋友,可以在這邊的建構式裡宣告出
BusTrackerOption
並賦值即可。但還是推薦閱讀依賴注入的筆記來了解一下呦
現在公車路線等組態都準備得差不多了,只剩下回傳時候要用來接收資料的 Model 還沒開。這時候就直接偷懶,拿 MOTC Transport API 的 Swagger 打回來的 Json,直接到 Json2Cshrp 之類的轉換網站直接產生 C# Class 就好了:
記得轉換結果的 Class Root
要改個名稱,這邊就直接取名叫做 BusEstimateInfo
吧:
現在我們有傳過去的參數,也有接回來的 Model 了,讓我們來開一個私有方法,從 MOTC API 取回資料吧:
/// <summary>
/// 查詢公車估計到站時間
/// </summary>
/// <param name="routeName">路線名稱</param>
/// <param name="stopId">站牌 ID</param>
/// <param name="direction">去返程</param>
private async Task<BusEstimateInfo> FetchBusEstimateTime(
string routeName,
int stopId,
int direction = 0)
{
var api = $"https://ptx.transportdata.tw/MOTC/v2/Bus/EstimatedTimeOfArrival/City/Taipei/{routeName}";
// 將站牌 ID 及路線方向 加入到查詢參數中
var filter = $"stopId eq '{stopId}'";
if (direction != 0)
{
filter += $" and direction eq {direction}";
}
var query = new Dictionary<string, string>()
{
["$filter"] = filter,
["$top"] = 1.ToString(),
["$format"] = "JSON"
};
// 使用套件 Microsoft.AspNetCore.WebUtilities 提供的 QueryHelpers
// 直接組出帶 QueryString 的 Url
var url = QueryHelpers.AddQueryString(api, query);
// 建立 request;注意直接呼叫 API 會要求驗證
// 必須將 Header 掛成瀏覽器才能吃到每日 50 次的呼叫額度
var request = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri(url)
};
request.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
using var client = new HttpClient();
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode is false)
{
throw new Exception(response.StatusCode.ToString());
}
var body = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<IEnumerable<BusEstimateInfo>>(body)?.FirstOrDefault();
return result ?? throw new Exception("呼叫 API 失敗,無法取得估計到站資訊");
}
這支呼叫 API 的 Method 步驟相當簡單:組出參數,呼叫 API,取回資料。
這邊有偷懶不想組字串,直接使用 Microsoft.AspNetCore.WebUtilities
的 QueryHelpers.AddQueryString
來把 GET 的 QueryString 參數組到 Url 裡,不想多安裝一個套件的朋友也可以自己手動組。
註:MOTC 的 文件 有提到非會員一天有 50 次的免費 Swagger 呼叫次數,實測如果是從程式呼叫時會需要吃驗證,要掛 Header 假裝成瀏覽器才能取得資料,不確定是不是還有其他限制。如果是要給自己開發的工具或產品使用的話,還是可以考慮了解一下 MOTC 的會員制度。
註:這邊的 HttpClient 也可以直接改用注入 HttpClientFactory 的方式來製作。可以參照 Yowko’s Notes 的這篇:在 .NET Core 與 .NET Framework 上使用 HttpClientFactory
現在取得公車資料的 FetchBusEstimateTime
已經建好了,讓我們調整一下外面的 Trigger 和共通的私有方法,來把 BusTrackerOption
的資訊帶到參數裡吧:
public BusReminderFunctions(
IOptions<BusTrackerOption> busTrackerOption,
ILoggerFactory loggerFactory)
{
_busTrackerOption = busTrackerOption.Value;
_logger = loggerFactory.CreateLogger<BusReminderFunctions>();
}
[Function("BusReminder-TimerTrigger")]
public async Task RunTimerTrigger([TimerTrigger("0 45 9 * * *")] MyInfo myTimer)
{
var routeName = this._busTrackerOption.RouteName;
var stopId = this._busTrackerOption.StopId;
var direction = this._busTrackerOption.Direction;
await TrackBusAsync(routeName, stopId, direction);
}
[Function("BusReminder")]
public async Task<HttpResponseData> HttpTrigger(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req,
FunctionContext executionContext)
{
var routeName = this._busTrackerOption.RouteName;
var stopId = this._busTrackerOption.StopId;
var direction = this._busTrackerOption.Direction;
await TrackBusAsync(routeName, stopId, direction);
var response = req.CreateResponse(HttpStatusCode.OK);
await response.WriteAsJsonAsync<object>(new { result = true });
return response;
}
private async Task TrackBusAsync(
string routeName,
int stopId,
int direction = 0)
{
var busEstimateInfo = await FetchBusEstimateTime(routeName, stopId, direction);
throw new NotImplementedException();
}
就像前面提到的,我們在這邊讓 TimerTrigger
和 HttpTrigger
取出 BusTrackerOption
的公車相關參數,例如公車路線名稱後,再傳遞到共用的 TrackBusAsync
,現在第一部份的查詢公車資訊已經完工,就讓我們先添加上去。
註:這邊之所以要讓查詢參數交由外面決定,就是以後如果我想把
HttpTrigger
改成可以從外部呼叫 API 時可以指定公車路線之類的參數,又或者是將來要註冊多組公車路線到資料庫之類的改動時,可以不用再動「查詢公車到站資訊」之類的邏輯。畢竟懶惰的訣竅在於提早準備
發送 Line Notify
2024.10 更新: Line Notify 將於 2025 年 3 月停止服務(LINE Notify 結束服務公告),有看到這篇的朋朋請選擇一組新的通知服務來串吧 QQ
現在搞定取得公車資訊的段落了,接著就讓我們來撰寫發送 Line Notify 的部份吧。
這邊為了過程完整一點,就重播一下上次衝刺去申請 Line Notify Token 的過程吧:
當下一個直衝 Line Notify 高速申請權杖:
好的回想完畢,現在讓我們把拿到的 Line Notify Token 也丟到 local.settings.json
的 Values
裡方便管理:
{
"Values": {
// ...這裡會有其他組態設定
// 加上 LineNotify 的 Token,用 __ 來表示階層
"LineNotify__Token": "YOUR LINE NOTIFY TOKEN"
}
}
一樣建立一個 Class,方便後續用 IOption
從組態中取得值:
public class LineNotifyOptions
{
public string Token { get; set; }
}
接著到 Program.cs
來將 json 的設定值繫結到 LineNotifyOptions
,Section 名稱要記得和 json 中的名稱對上:
services.Configure<LineNotifyOption>(hostContext.Configuration.GetSection("LineNotify"));
接著就可以回到我們的 BusReminderFunctions
來把 IOptions<LineNotifyOptions>
注入進來:
這樣從 Config 取得 Token 的準備就完成了,現在讓我們來撰寫傳送訊息的方法本體吧
發送 Line Notify 實際上就是傳送一個 Post 請求到 /api/notify
,並將 Token 放到 Header 的 Authorization
、訊息丟到 Body 就行了,因此我們可以直接把這方法包裝成接收到訊息就傳遞給 API:
/// <summary>
/// 發送 Line Notify 通知
/// </summary>
/// <param name="message">The message.</param>
/// <exception cref="System.Exception">發送失敗</exception>
private async Task SendLineNotify(string message)
{
if (string.IsNullOrEmpty(_lineNotifyOptions.Token))
{
throw new Exception("取得 Line Notify Token 失敗");
}
const string lineNotifyApi = "https://notify-api.line.me/api/notify";
var requestBody = new Dictionary<string, string>
{
["message"] = message
};
var request = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri(lineNotifyApi),
Content = new FormUrlEncodedContent(requestBody)
};
request.Headers.Add("Authorization", $"Bearer {_lineNotifyOptions.Token}");
using var client = new HttpClient();
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode is false)
{
throw new Exception("Line Notify 發送失敗");
}
}
現在我們也已經有了傳送訊息的方法,是時候把它們倆串起來了!
組合查詢公車資訊與發送到站通知
先把鏡頭回到我們讓 Trigger 們共用的 TrackBusAsync
方法:
private async Task TrackBusAsync(
string routeName,
int stopId,
int direction = 0)
{
var busEstimateInfo = await FetchBusEstimateTime(routeName, stopId, direction);
throw new NotImplementedException();
}
可以看到我們已經嘗試取得公車資訊,現在我們要組裝訊息,然後傳遞到剛剛撰寫的 Line Notify 通知方法裡。
而我想要的訊息是這樣的:「您追蹤的公車 307 將在 10 分鐘後(18:00)抵達 台北車站(忠孝)」
因此我會需要計算出剩餘的分數,以及抵達時間,再從前面拿到的公車資訊來組成訊息並傳遞到方法中:
private async Task TrackBusAsync(
string routeName,
int stopId,
int direction = 0)
{
var busEstimateInfo = await FetchBusEstimateTime(routeName, stopId, direction);
// 將預估幾秒後抵達 轉換成 預估幾分鐘後抵達
var estimateMin = new TimeSpan(0, 0, busEstimateInfo.EstimateTime).Minutes;
// 取得台北時區的目前時間,並和預估秒數計算出預估抵達時間
var timeZone = TimeZoneInfo.FindSystemTimeZoneById("Taipei Standard Time");
var convertedTime = TimeZoneInfo.ConvertTime(DateTime.UtcNow, timeZone);
var estimateTime = convertedTime.AddSeconds(busEstimateInfo.EstimateTime).ToString("HH:mm");
var message = $"您追蹤的公車 {busEstimateInfo.RouteName.Zh_tw} 將在 {estimateMin} 分鐘後({estimateTime})抵達 {busEstimateInfo.StopName.Zh_tw}";
await SendLineNotify(message);
}
這邊要特別注意取得時間的部份,因為在伺服器的時間會是 UTC+0,因此我們這邊使用 TimeZoneInfo.ConvertTime
轉換成台北時區的時間。
註:像這種丟到雲端平台的服務,會時常遇到時區時間的轉換。單純的時間轉換可以參照之前筆記的 C#: 時區轉換、民國西元、國曆農曆、中文月份週期
或是可以嘗試更優雅的 DateTimeOffset,請參考 還在用 DateTime 嗎?試試 DateTimeOffset 吧 - demo小鋪
現在我們已經將前面撰寫的兩個小方法組裝起來,是時候來測試看看了!
本機測試 Functions
總之,啟動鍵先用力給它按下去:
接著就會看到小黑窗跑起來,告訴你已經啟動了哪些 Functions:
可以看到我們的 Http Trigger 以及 Timer Trigger
因為我們的 Http Trigger 有支援 GET,所以這邊直接複製 Api 網址丟到瀏覽器打看看就可以試囉:
這時候小黑窗也會記錄到這次呼叫:
看起來運行良好,該放上 Azure 上啦!
補充:在 Azure 上要看小黑窗的話,可以從左邊選單找到「監視 > 紀錄資料流」:
使用 Visual Studio 發佈到 Azure Functions
現在讓我們把寫好的 Functions 佈到前面申請的 Azure Functions 服務上運行。為了方便這邊就使用 Visual Studio 來示範,首先讓我們對專案點選發佈:
接著選取發佈目標,我們想要發到 Azure 雲端上:
接著會讓我們選擇目標,因為我們前面建立時的作業系統是選用建議的 Windows,因此選擇 Azure Functions (Windows):
接著就可以選取符合條件的 Azure Functions,這邊當然是選擇我們前面建立好的「林北ㄟ Functions」
註:如果先前沒有建立過 Azure Functions 服務,發佈的時候也可以從 Visual Studio 中建立,可以說是相當貼心:
按下完成之後,我們的發佈檔就建立完囉!
這邊要特別注意的是,我們先前有在 local.settings.json
加入一些設定值,例如 BusTracker 的公車路線等設定。因此我們這邊可以順手同步到目標服務上,在裝載的右上角點開「管理 Azure App Service 設定」:
就可以看到我們目前在 Local 的組態設定值,以及 Azure 服務裡的組態設定值。這邊為了將 Local 的設定值同步上去,就直接按下「插入本機的值」:
註:按下「插入本機的值」並確定後,設定值就會同步到 Azure Functions 服務的組態中:
反過來說,如果沒有從本機同步上去,而是在 Azure 上設定組態也是完全 OK 的
現在一切就緒,讓我們按下發佈吧!
接著就可以看到我們撰寫的 Functions 被發佈上去,並且幫我們重啟了 Azure Functions 服務:
現在讓我們回到 Azure Functions 服務的函式看看:
可以確認我們撰寫的 Functions 已經出現囉!
回到概觀來複製一下我們 Azure Functions 的 Url:
並且加上我們的 HttpTrigger 路由 api/BusReminder
呼叫看看:
大功告成!
小結
終於把這個小提醒給上雲啦!唉呀不得不說 Azure Functions 真是香。
接下來只要下班前收到公車到站通知,然後在公車來之前下班就可以啦!
……只要在公車來之前下班,就可以……吧?
參考資料
- 公司前輩的 Azure Functions 範例
- Azure Functions ⚡ 介紹及Serverless入門輕鬆學 - iT 邦幫忙
- 使用 Azure Function 輕易打造屬於自己的Web API | 工程良田的小球場 - 點部落 (dotblogs.com.tw)
- 建立一個 function App. 使用 Azure Functions | by (KJH) Kuan-Jung, Huang | Medium
- Is it time to start creating C# Azure Functions in isolated mode? (markheath.net)
- .NET on Azure Functions Roadmap - Microsoft Tech Community
其他文章
哈囉,如果你也有 LikeCoin,也覺得我的文章有幫上忙的話,還請不吝給我拍拍手呦,謝謝~ ;)