iT邦幫忙

2022 iThome 鐵人賽

DAY 17
0
Software Development

讓 C# 也可以很 Social - 在 .NET 6 用 C# 串接 LINE Services API 的取經之路系列 第 17

[Day 17] .NET 6 C# 與 Line Services API 開發 - Rich Menu 製作(二) 建立 rich menu

  • 分享至 

  • xImage
  •  
tags: .NET6 C#, LineBot, Line Messaging API, C#, dotnet core

[Day 17] 讓 C# 也可以很 Social - .NET 6 C# 與 Line Services API 開發 - Rich Menu 製作(二) 建立 rich menu

前言

Hello 大家好,今天這篇補上 前一篇留空的 RichMenuService,並建立第一張 rich menu,不過在開始寫程式之前,會先向各位介紹 Line Bot Designer

Line Bot Designer 前往下載

Line Bot Designer 是 Line 提供的一款應用程式,可以在上面設計所有訊息類型、設計rich menu、模擬聊天室畫面,製作的訊息與 rich menu 都會產生對應的 JSON。

這邊要使用到的是其設計 rich menu 的功能。

  • 選擇開始新專案

  • 進入後的專案設定頁面,輸入想要呈現的資訊

  • 進入後按下 + 號新增一個 rich menu

  • 新增 rich menu 後就依照屬性視窗內的資訊做設定,圖片我這邊選擇大張的 2500*1720-1 圖片,另外可以在預覽視窗中用滑鼠在區塊上拖曳,就可以創造出一個個長方形區域,並回到屬性視窗中設定其執行動作的內容。

  • 這邊簡單地設定各個區塊的點擊回應動作 - 回傳每個區塊對應編號的文字內容。

  • 此時在右下角視窗的 JSON 內容就是這張 rich menu 的 JSON,等等就會用到。

RichMenuService 實作

  • 在 RichMenuService 中宣告 uri 變數
private readonly string validateRichMenuUri = "https://api.line.me/v2/bot/richmenu/validate";
private readonly string createRichMenuUri = "https://api.line.me/v2/bot/richmenu";
private readonly string getRichMenuListUri = "https://api.line.me/v2/bot/richmenu/list";
// {0} 的位置要帶入 richMenuId
private readonly string uploadRichMenuImageUri = "https://api-data.line.me/v2/bot/richmenu/{0}/content";
// {0} 的位置要帶入 richMenuId
private readonly string setDefaultRichMenuUri = "https://api.line.me/v2/bot/user/all/richmenu/{0}";

ValidateRichMenu 文件連結

這個 function 會將傳入的 rich menu 物件送到 Line 去驗證其格式是否正確。

  • 修改 ValidateRichMenu function
public async Task<string> ValidateRichMenu(RichMenuDto richMenu)
{
    var jsonBody = new StringContent(_jsonProvider.Serialize(richMenu), Encoding.UTF8, "application/json");
    var request = new HttpRequestMessage
    {
        Method = HttpMethod.Post,
        RequestUri = new Uri(validateRichMenuUri),
        Content = jsonBody,
    };
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", channelAccessToken);
    var response = await client.SendAsync(request);

    return await response.Content.ReadAsStringAsync();
}

CreateRichMenu 文件連結

這個 function,會將傳入的格式送到 Line 然後建立 rich menu,並且其格式內容會儲存在 Line 平台中,一支 Line Bot 最多可以儲存 1000 張 rich menu,建立成功後會收到建立好的 richmenuId,。

  • 修改 CreateRichMenu function
public async Task<string> CreateRichMenu(RichMenuDto richMenu)
{
    var jsonBody = new StringContent(_jsonProvider.Serialize(richMenu), Encoding.UTF8, "application/json");
    var request = new HttpRequestMessage
    {
        Method = HttpMethod.Post,
        RequestUri = new Uri(createRichMenuUri),
        Content = jsonBody,
    };
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", channelAccessToken);
    var response = await client.SendAsync(request);

    return await response.Content.ReadAsStringAsync();
}

GetRichMenuList 文件連結


這個 function 會回傳目前儲存在 Line 上的所有 richmenu 格式。

  • 按照文件中下方的 Response 在 Dtos/RichMenu 資料夾中新增 RichMenuListDto.cs
namespace LineBotMessage.Dtos
{
    public class RichMenuListDto
    {
        public List<RichMenuDto> Richmenus { get; set; }
    }
}
  • 修改 GetRichMenuList function
public async Task<RichMenuListDto> GetRichMenuList()
{
    var request = new HttpRequestMessage
    {
        Method = HttpMethod.Get,
        RequestUri = new Uri(getRichMenuListUri),
    };
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", channelAccessToken);
    var response = await client.SendAsync(request);

    Console.WriteLine(await response.Content.ReadAsStringAsync());
    var list = _jsonProvider.Deserialize<RichMenuListDto>(await response.Content.ReadAsStringAsync());
    // 依照名稱排序
    list.Richmenus = list.Richmenus.OrderBy((rm) => rm.Name).ToList();
    return list;
}

UploadRichMenuImage 文件連結

這個 function 是使用剛剛 create rich menu 成功收到的 rich menu id 去上傳圖片,這裡傳送訊息時圖片是採用 URL 的方式不同,rich menu 上傳圖片是將整格檔案內容傳給 Line

  • 修改 UploadRichMenuImage function
public async Task<string> UploadRichMenuImage(string richMenuId, IFormFile imageFile)
{
    //判斷檔案格式 需為 png or jpeg
    if (!(Path.GetExtension(imageFile.FileName).Equals(".png", StringComparison.OrdinalIgnoreCase) || Path.GetExtension(imageFile.FileName).Equals(".jpeg", StringComparison.OrdinalIgnoreCase)))
    {
        return "圖片格式錯誤,須為 png or jpeg";
    }
    using (var stream = new MemoryStream())
    {
        //建立檔案內容
        imageFile.CopyTo(stream);
        var fileBytes = stream.ToArray();
        var content = new ByteArrayContent(fileBytes);
        content.Headers.ContentType = new MediaTypeHeaderValue("image/png");
        var request = new HttpRequestMessage(HttpMethod.Post, String.Format(uploadRichMenuImageUri, richMenuId))
        {
            Content = content
        };
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", channelAccessToken);
        var response = await client.SendAsync(request);

        return await response.Content.ReadAsStringAsync();
    }
}

SetDefaultRichMenu 文件連結

這個 function 是將指定的 rich menu 設為預設顯示的 rich menu,沒有被特別設定的使用者就會看到預設的 rich menu。

  • 修改 SetDefaultRichMenu function
public async Task<string> SetDefaultRichMenu(string richMenuId)
{
    var request = new HttpRequestMessage(HttpMethod.Post, String.Format(setDefaultRichMenuUri,richMenuId));
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", channelAccessToken);

    var response = await client.SendAsync(request);

    return await response.Content.ReadAsStringAsync();
}

修正 LineBotController api

將 function 搬進 return Ok() 中。

//rich menu api
[HttpPost("RichMenu/Validate")]
public async Task<IActionResult> ValidateRichMenu(RichMenuDto richMenu)
{
    return Ok(await _richMenuService.ValidateRichMenu(richMenu));
}

[HttpPost("RichMenu/Create")]
public async Task<IActionResult> CreateRichMenu(RichMenuDto richMenu)
{
    return Ok(await _richMenuService.CreateRichMenu(richMenu));
}

[HttpGet("RichMenu/GetList")]
public async Task<IActionResult> GetRichMenuList()
{
    return Ok(await _richMenuService.GetRichMenuList());
}

[HttpPost("RichMenu/UploadImage/{richMenuId}")]
public async Task<IActionResult> UploadRichMenuImage(IFormFile imageFile, string richMenuId)
{
    return Ok(await _richMenuService.UploadRichMenuImage(richMenuId, imageFile));
}

[HttpGet("RichMenu/SetDefault/{richMenuId}")]
public async Task<IActionResult> SetDefaultRichMenu(string richMenuId)
{
    return Ok(await _richMenuService.SetDefaultRichMenu(richMenuId));
}

基本建立流程所需的 api 都已經實作完成了,現在開始在 Line Bot 上建立 rich menu。

測試

1. 從 Line Bot Designer 取得 rich menu JSON 內容

{
  "size": {
    "width": 2500,
    "height": 1686
  },
  "selected": true,
  "name": "richmenu_big_1",
  "chatBarText": "點擊開啟 richMenu",
  "areas": [
    {
      "bounds": {
        "x": 17,
        "y": 289,
        "width": 581,
        "height": 688
      },
      "action": {
        "type": "message",
        "text": "A"
      }
    },
    {
      "bounds": {
        "x": 641,
        "y": 290,
        "width": 598,
        "height": 697
      },
      "action": {
        "type": "message",
        "text": "B"
      }
    },
    {
      "bounds": {
        "x": 1266,
        "y": 284,
        "width": 598,
        "height": 696
      },
      "action": {
        "type": "message",
        "text": "C"
      }
    },
    {
      "bounds": {
        "x": 1882,
        "y": 290,
        "width": 598,
        "height": 697
      },
      "action": {
        "type": "message",
        "text": "D"
      }
    },
    {
      "bounds": {
        "x": 23,
        "y": 1014,
        "width": 581,
        "height": 656
      },
      "action": {
        "type": "message",
        "text": "E"
      }
    },
    {
      "bounds": {
        "x": 639,
        "y": 1008,
        "width": 581,
        "height": 672
      },
      "action": {
        "type": "message",
        "text": "F"
      }
    },
    
      "bounds": {
        "x": 1269,
        "y": 1014,
        "width": 581,
        "height": 672
      },
      "action": {
        "type": "message",
        "text": "G"
      }
    },
    {
      "bounds": {
        "x": 1897,
        "y": 1005,
        "width": 581,
        "height": 672
      },
      "action": {
        "type": "message",
        "text": "H"
      }
    }
  ]
}
  1. 驗證其格式正確性

    • 使用 validateRichMenu api,帶入 rich menu JSON
    • Response
  2. 建立 rich menu

    • 使用 createRichMenu api,帶入 rich menu JSON
    • 建立成功,收到 richMenuId
  3. 上傳 rich menu image

    • 使用 uploadRichMenuImage api,帶入 richMenuId 與圖片檔案
    • 圖片上傳成功。
  4. 將剛建立的 rich menu 設為預設 rich menu

    • 使用 SetDefaultRichMenu api,帶入 richMenuId

** 若忘記了 richMenuId 是什麼,可以使用 GetList 取得所有 Line 上已建立的 richMenu 格式內容,再找尋該 richMenu 的名稱並取得其對應的 richMenuId**

結果

剛剛設定好的 rich menu 就會顯示在 Line Bot 聊天室下方了。

結語

不知道有沒有人注意到,準備的圖片上方為什麼有個 1 和 2 的按鈕區塊,不過看到兩張相同大小但樣式不同的圖片應該就知道這是換頁用的按鈕,下一篇主要內容會是實作這個換頁的功能,並且補充一些其他常用的 api給大家參考。

腦筋急轉彎

  • 如果有個需求,希望使用者點擊過的區塊 要能改變顏色,有什麼可行的辦法嗎

範例程式碼

如果想要參考今天範例程式碼的部份,下面是 Git Repo 連結,方便大家參考。

Day17_Rich Menu Create


上一篇
[Day 16] .NET 6 C# 與 Line Services API 開發 - Rich Menu 製作(一) 起手式
下一篇
[Day 18] .NET 6 C# 與 Line Services API 開發 - Rich Menu 製作(三) 建立 rich menu alias
系列文
讓 C# 也可以很 Social - 在 .NET 6 用 C# 串接 LINE Services API 的取經之路30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中
0
WT
iT邦新手 5 級 ‧ 2022-11-28 17:44:49

您好,請問我按照了您的程式範例,出現了如下錯誤
https://ithelp.ithome.com.tw/upload/images/20221128/20112863zGUqXqRG18.jpg

WT iT邦新手 5 級 ‧ 2022-11-28 17:57:15 檢舉

我有找到原因了,謝謝

APPX Jim iT邦新手 5 級 ‧ 2022-11-29 17:35:10 檢舉

/images/emoticon/emoticon12.gif

0
WT
iT邦新手 5 級 ‧ 2022-11-29 13:31:09

您好,這篇我照著做,查詢GetRichMenuList,可以看到列表,但是line bot裡面並沒有產生那個圖文選單,到LINE的後台也沒有看到圖文選單的列表,請問可能是什麼原因呢?

APPX Jim iT邦新手 5 級 ‧ 2022-11-29 17:23:49 檢舉

如果GetRichMenuList有取回的話就表示有成功新增了~那沒有顯示出來的原因我估計是後面的兩個步驟沒有做好~

成功新增 richmenu 後,應該會拿到 LINE 回傳的 richmenuId,要拿著這個 Id 做 “上傳圖片”&“設為預設 richmenu” 這兩個步驟後才會顯示在 Line Bot 的畫面中~

APPX Jim iT邦新手 5 級 ‧ 2022-11-29 17:29:31 檢舉

另外,使用 Line bot 後台新增 richmenu 跟使用 messaging api 新增的 richmenu 是分開的~不能互通,也不能互相編輯。

所以如果要使用 line bot 後台新增 richmenu,就只能使用 line bot 後台管理這張 richmenu

如果使用 messaging api 新增 richmenu,就只能使用 messaging api 管理這張 richmenu

希望有成功解答你的疑問/images/emoticon/emoticon37.gif

WT iT邦新手 5 級 ‧ 2022-11-30 09:06:29 檢舉

好的,謝謝大大的解答,我本來以為是互通的!!

0
applefi87
iT邦新手 5 級 ‧ 2023-03-01 14:36:32

1.回覆問題(如果有個需求,希望使用者點擊過的區塊 要能改變顏色,有什麼可行的辦法嗎):
是每個按鈕加上觸發"Link rich menu to user" 來更換那位使用者的rich menu嗎?
--我看了明天的,原來Alias自己設定就好

2.回報一下我自己卡錯的經驗
出現:
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware: Error: An unhandled exception has occurred while executing the request.
原因是我在controller 少加上await 或 async
導致即使我除錯,在真正跑到要await的地方就會報類似錯誤,因為根本沒東西回傳

3.另外,範例少了個"{" (但依舊是超棒的Line bot教學文章)

  "bounds": {
    "x": 1269,
    "y": 1014,
    "width": 581,
    "height": 672
  },
  "action": {
    "type": "message",
    "text": "G"
  }
},

我要留言

立即登入留言