namespace LineBotDemo.Controllers { [RoutePrefix("echo")] public class LineMessagesSampleController : ApiController { private static readonly ILog Log4netLogger = LogManager.GetLogger(typeof(LineMessagesSampleController)); private LineClient lineClient = new LineClient(ConfigurationManager.AppSettings["ChannelToken"].ToString()); private Logger Logger = new Logger(Log4netLogger); [Route] public async Task Post(HttpRequestMessage request) { if (!await VaridateSignature(request)) return Request.CreateResponse(HttpStatusCode.BadRequest); var content = await request.Content.ReadAsStringAsync(); Activity activity = JsonConvert.DeserializeObject(content); Logger.Info("request=" + content); // Line may send multiple events in one message, so need to handle them all. foreach (Event lineEvent in activity.Events) { Profile profile = await lineClient.GetProfile(lineEvent.Source.UserId); switch (lineEvent.Type) { case EventType.Beacon: Logger.Info("Beacon event"); break; case EventType.Follow: Logger.Info("Follow event"); break; case EventType.Join: Logger.Info("Join event"); break; case EventType.Leave: Logger.Info("Leave event"); break; case EventType.Message: Logger.Info("Message event"); Message message = JsonConvert.DeserializeObject(lineEvent.Message.ToString()); switch (message.Type) { case MessageType.Text: var textMessageReply = await HandleTextMessage(lineEvent); await Reply(lineEvent, textMessageReply); break; case MessageType.Audio: case MessageType.Image: case MessageType.Video: var mediaReplyMessage = await HandleMediaMessage(lineEvent); await Reply(lineEvent, mediaReplyMessage); break; case MessageType.Sticker: var stickerReplyMessage = await HandleStickerMessage(lineEvent); await Reply(lineEvent, stickerReplyMessage); break; case MessageType.Location: var locationReplyMessage = await HandleLocationMessage(lineEvent); await Reply(lineEvent, locationReplyMessage); break; } break; case EventType.Postback: Logger.Info("Postback event"); // var postbackReplyMessage = new TextMessage(lineEvent.Postback.Data); await Reply(lineEvent, postbackReplyMessage); break; case EventType.Unfollow: Logger.Info("Unfollow event"); break; } } return Request.CreateResponse(HttpStatusCode.OK); } private async Task VaridateSignature(HttpRequestMessage request) { var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(ConfigurationManager.AppSettings["ChannelSecret"].ToString())); var computeHash = hmac.ComputeHash(Encoding.UTF8.GetBytes(await request.Content.ReadAsStringAsync())); var contentHash = Convert.ToBase64String(computeHash); var headerHash = Request.Headers.GetValues("X-Line-Signature").First(); return contentHash == headerHash; } private async Task HandleTextMessage(Event lineEvent) { var textMessage = JsonConvert.DeserializeObject(lineEvent.Message.ToString()); Message replyMessage = null; if (textMessage.Text.ToLower() == "demo") { List actions = new List(); actions.Add(new MessageTemplateAction("Buttons", "buttons")); actions.Add(new MessageTemplateAction("Confirm", "confirm")); actions.Add(new MessageTemplateAction("Carousel", "carousel")); actions.Add(new MessageTemplateAction("Imagemap", "imagemap")); ButtonsTemplate buttonsTemplate = new ButtonsTemplate(null, "可用功能", "直接選比較快", actions); replyMessage = new TemplateMessage("Buttons", buttonsTemplate); } else if (textMessage.Text.ToLower() == "buttons") { List actions = new List(); actions.Add(new MessageTemplateAction("Message Label", "sample data")); // text 參數為 null 就不會有 message 在畫面上 actions.Add(new PostbackTemplateAction("Postback Label", "postback data", null)); actions.Add(new UriTemplateAction("Uri Label", "https://github.com/kenakamu")); ButtonsTemplate buttonsTemplate = new ButtonsTemplate("https://github.com/apple-touch-icon.png", "Sample Title", "Sample Text", actions); replyMessage = new TemplateMessage("Buttons", buttonsTemplate); } else if (textMessage.Text.ToLower() == "confirm") { // Actions List actions = new List(); actions.Add(new MessageTemplateAction("OK", "ok")); actions.Add(new MessageTemplateAction("Cancel", "cancel")); // Template ConfirmTemplate confirmTemplate = new ConfirmTemplate("Are you sure?", actions); // Message replyMessage = new TemplateMessage("Confirm", confirmTemplate); } else if (textMessage.Text.ToLower() == "carousel") { List columns = new List(); List actions = new List(); actions.Add(new MessageTemplateAction("Message Label", "sample data")); // text 內容為 "postback text", 可以和 buttons 的 Postback action 做比較 actions.Add(new PostbackTemplateAction("Postback Label", "postback data", "postback text")); actions.Add(new UriTemplateAction("Uri Label", "https://github.com/kenakamu")); columns.Add(new TemplateColumn() { Title = "Casousel 1 Title", Text = "Casousel 1 Text", ThumbnailImageUrl = "https://github.com/apple-touch-icon.png", Actions = actions }); columns.Add(new TemplateColumn() { Title = "Casousel 2 Title", Text = "Casousel 2 Text", ThumbnailImageUrl = "https://github.com/apple-touch-icon.png", Actions = actions }); CarouselTemplate carouselTemplate = new CarouselTemplate(columns); replyMessage = new TemplateMessage("Carousel", carouselTemplate); } else if (textMessage.Text.ToLower() == "imagemap") { // Base URL 圖片路徑請自行定義 var url = HttpContext.Current.Request.Url; var imageUrl = $"{url.Scheme}://{url.Host}:{url.Port}/images/githubicon"; List actions = new List(); actions.Add(new UriImageMapAction("https://github.com", new ImageMapArea(0, 0, 520, 1040))); actions.Add(new MessageImageMapAction("I love LINE!", new ImageMapArea(520, 0, 520, 1040))); replyMessage = new ImageMapMessage(imageUrl, "GitHub", new BaseSize(1040, 1040), actions); } else { replyMessage = new TextMessage(textMessage.Text); } return await Task.FromResult(replyMessage); } private async Task HandleMediaMessage(Event lineEvent) { Message message = JsonConvert.DeserializeObject(lineEvent.Message.ToString()); // Get media from Line server. Media media = await lineClient.GetContent(message.Id); // 統一回圖片 Message replyMessage = new ImageMessage("https://github.com/apple-touch-icon.png", "https://github.com/apple-touch-icon.png"); return await Task.FromResult(replyMessage); } private async Task HandleStickerMessage(Event lineEvent) { var stickerMessage = JsonConvert.DeserializeObject(lineEvent.Message.ToString()); // https://devdocs.line.me/files/sticker_list.pdf return await Task.FromResult(new StickerMessage("1", "1")); } private async Task HandleLocationMessage(Event lineEvent) { var locationMessage = JsonConvert.DeserializeObject(lineEvent.Message.ToString()); var replyMessage = new LocationMessage( locationMessage.Title, locationMessage.Address, locationMessage.Latitude, locationMessage.Longitude); return await Task.FromResult(replyMessage); } private async Task Reply(Event lineEvent, Message replyMessage) { try { await lineClient.ReplyToActivityAsync(lineEvent.CreateReply(message: replyMessage)); } catch { await lineClient.PushAsync(lineEvent.CreatePush(message: replyMessage)); } } } }