[TOC] ### 1) 安裝套件 (nuget) ``` Line.Messaging ``` ### 2) 新增LineBot控制器 #### 2.1) 注入服務 在Program.cs內新增 ```csharp= builder.Services.AddHttpContextAccessor(); ``` #### 2.2) 注入(DI) IServiceProvider 在LineBotController.cs中新增 ```csharp= private readonly IHttpContextAccessor _httpContextAccessor; private readonly HttpContext _httpContext; public LineBotController(IServiceProvider serviceProvider) { _httpContextAccessor = serviceProvider.GetRequiredService<IHttpContextAccessor>(); _httpContext = _httpContextAccessor.HttpContext; //...略 } ``` #### 2.3) 建立LineBot設定檔 ```csharp= public class LineBotConfig { public string channelSecret { get; set; } public string accessToken { get; set; } } ``` 在LineBotController.cs中新增變數 ```csharp= private LineBotConfig _lineBotConfig; ``` 在LineBotController的建構式中追加變數設定 ```csharp= _lineBotConfig = new LineBotConfig(); _lineBotConfig.channelSecret = "YOUR channelSecret"; _lineBotConfig.accessToken = "YOUR accessToken"; ``` ### 3) 撰寫相關處理程式 ```csharp= [HttpPost("run")] public async Task<IActionResult> Post() { var events = await _httpContext.Request.GetWebhookEventsAsync(_lineBotConfig.channelSecret); var lineMessagingClient = new LineMessagingClient(_lineBotConfig.accessToken); var lineBotApp = new LineBotApp(lineMessagingClient); await lineBotApp.RunAsync(events); return Ok(); } ``` #### 3.1) 改用 WebhookRequestMessageHelper (擴展方法) ```csharp= /* MIT License Copyright (c) 2017 pierre3 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ public static class WebhookRequestMessageHelper { public static async Task<IEnumerable<WebhookEvent>> GetWebhookEventsAsync(this HttpRequest request, string channelSecret, string botUserId = null) { if (request == null) { throw new ArgumentNullException(nameof(request)); } if (channelSecret == null) { throw new ArgumentNullException(nameof(channelSecret)); } var content = ""; using (var reader = new StreamReader(request.Body)) { content = await reader.ReadToEndAsync(); } var xLineSignature = request.Headers["X-Line-Signature"].ToString(); if (string.IsNullOrEmpty(xLineSignature) || !VerifySignature(channelSecret, xLineSignature, content)) { throw new InvalidSignatureException("Signature validation faild."); } dynamic json = JsonConvert.DeserializeObject(content); if (!string.IsNullOrEmpty(botUserId)) { if (botUserId != (string)json.destination) { throw new UserIdMismatchException("Bot user ID does not match."); } } return WebhookEventParser.ParseEvents(json.events); } internal static bool VerifySignature(string channelSecret, string xLineSignature, string requestBody) { try { var key = Encoding.UTF8.GetBytes(channelSecret); var body = Encoding.UTF8.GetBytes(requestBody); using (HMACSHA256 hmac = new HMACSHA256(key)) { var hash = hmac.ComputeHash(body, 0, body.Length); var xLineBytes = Convert.FromBase64String(xLineSignature); return SlowEquals(xLineBytes, hash); } } catch { return false; } } private static bool SlowEquals(byte[] a, byte[] b) { uint diff = (uint)a.Length ^ (uint)b.Length; for (int i = 0; i < a.Length && i < b.Length; i++) diff |= (uint)(a[i] ^ b[i]); return diff == 0; } } ``` >參考來源 [link](https://ithelp.ithome.com.tw/articles/10217452) #### 3.2) LineBotApp.cs ```csharp= public class LineBotApp : WebhookApplication { private readonly LineMessagingClient _messagingClient; public LineBotApp(LineMessagingClient lineMessagingClient) { _messagingClient = lineMessagingClient; } protected override async Task OnMessageAsync(MessageEvent ev) { var result = null as List<ISendMessage>; switch (ev.Message) { //文字訊息 case TextEventMessage textMessage: { //頻道Id var channelId = ev.Source.Id; //使用者Id var userId = ev.Source.UserId; //回傳 hellow result = new List<ISendMessage> { new TextMessage("hellow") }; } break; } if (result != null) await _messagingClient.ReplyMessageAsync(ev.ReplyToken, result); } } ``` ### 4) 測試 #### 4.1)利用ngrok轉換服務 ![](https://hackmd.io/_uploads/rkG6m9-d3.png) #### 4.2)設定Line WebHook ![](https://hackmd.io/_uploads/H1rVm9bu2.png)