{"id":23727832,"url":"https://github.com/thrzn41/webexteamsapiclient","last_synced_at":"2025-09-04T05:30:33.039Z","repository":{"id":33784750,"uuid":"135546373","full_name":"thrzn41/WebexTeamsAPIClient","owner":"thrzn41","description":"Webex Teams API Client for .NET","archived":false,"fork":false,"pushed_at":"2022-12-08T03:50:13.000Z","size":584,"stargazers_count":6,"open_issues_count":17,"forks_count":4,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-08-21T22:51:40.955Z","etag":null,"topics":["csharp","dotnet","dotnet-core","dotnet-framework","dotnetcore","dotnetframework","teams","webex","webex-teams","webexteams"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thrzn41.png","metadata":{"files":{"readme":"README.ja-JP.md","changelog":"CHANGELOG.ja-JP.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-05-31T07:11:37.000Z","updated_at":"2025-01-18T00:10:36.000Z","dependencies_parsed_at":"2023-01-15T02:30:32.105Z","dependency_job_id":null,"html_url":"https://github.com/thrzn41/WebexTeamsAPIClient","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/thrzn41/WebexTeamsAPIClient","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thrzn41%2FWebexTeamsAPIClient","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thrzn41%2FWebexTeamsAPIClient/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thrzn41%2FWebexTeamsAPIClient/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thrzn41%2FWebexTeamsAPIClient/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thrzn41","download_url":"https://codeload.github.com/thrzn41/WebexTeamsAPIClient/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thrzn41%2FWebexTeamsAPIClient/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273555592,"owners_count":25126345,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-04T02:00:08.968Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csharp","dotnet","dotnet-core","dotnet-framework","dotnetcore","dotnetframework","teams","webex","webex-teams","webexteams"],"created_at":"2024-12-31T01:45:39.745Z","updated_at":"2025-09-04T05:30:32.644Z","avatar_url":"https://github.com/thrzn41.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Webex Teams API Client for .NET\n\n[![nuget](https://img.shields.io/nuget/v/Thrzn41.WebexTeams.svg)](https://www.nuget.org/packages/Thrzn41.WebexTeams) [![MIT license](https://img.shields.io/github/license/thrzn41/WebexTeamsAPIClient.svg)](https://github.com/thrzn41/WebexTeamsAPIClient/blob/master/LICENSE)\n\n`Webex Teams API Client`は、`Cisco Webex Teams REST API`を利用しやすくしたライブラリです。  \n基本的な機能のほかに、Cisco Webex TeamsのAPIを使いやすくするための機能を実装しています。\n\n#### ほかの言語のREADME\n* [English README is here](https://github.com/thrzn41/WebexTeamsAPIClient/blob/master/README.md) ([英語のREADMEはこちら](https://github.com/thrzn41/WebexTeamsAPIClient/blob/master/README.md))\n\n---\n`Webex Teams API Client`を使って、`Cisco Webex Teams REST API`を簡単に実行できます。  \n\n* Markdownでメッセージを投稿する簡単な例\n\n``` csharp\n// 暗号化されたトークンをストレージから読み込む。\nProtectedString token = LoadEncryptedBotToken();\n\n// TeamsAPIClientのインスタンスを作成する(リトライ機能付き)。\nvar teams = TeamsAPI.CreateVersion1Client(token, new TeamsRetryHandler(4));\n\n// Markdownを構成します。\nvar markdown = new MarkdownBuilder();\nmarkdown.Append(\"こんにちは、\").AppendBold(\"Webex Teams\").Append(\"！！\");\n\n// メッセージを投稿します。\nvar message = (await teams.CreateDirectMessageAsync(\"your_webex_teams_account@example.com\", markdown.ToString())).GetData();\n\nConsole.WriteLine(\"メッセージが投稿されました: ID = {0}\", message.Id);\n```\n\n* AdaptiveCardをJson文字列やobjectから生成して投稿する簡単な例\n\n``` csharp\n// Json文字列から生成。\nvar card = AdaptiveCardAttachment.FromJsonString(\n@\"\n    {\n        \"\"type\"\": \"\"AdaptiveCard\"\",\n        \"\"version\"\": \"\"1.0\"\",\n        \"\"body\"\": [\n        {\n            \"\"type\"\": \"\"TextBlock\"\",\n            \"\"text\"\": \"\"Adaptive Cards\"\",\n            \"\"size\"\": \"\"large\"\"\n        }\n        ],\n        \"\"actions\"\": [\n        {\n            \"\"type\"\": \"\"Action.OpenUrl\"\",\n            \"\"url\"\": \"\"http://adaptivecards.io\"\",\n            \"\"title\"\": \"\"Learn More\"\"\n        }\n        ]\n    }\n\");\n\n// カード付きでメッセージを投稿。\nvar message = (await teams.CreateDirectMessageAsync(\"your_webex_teams_account@example.com\",\n    \"[Learn More](http://adaptivecards.io) about Adaptive Card.\",\n    card)).GetData();\n\nConsole.WriteLine(\"Message was posted: ID = {0}\", message.Id);\n\n\n// 匿名型やクラスのインスタンスからも生成できます。\nvar cardObj = new\n{\n    type    = \"AdaptiveCard\",\n    version = \"1.0\",\n    body    = new []\n    {\n        new\n        {\n            type = \"TextBlock\",\n            text = \"Adaptive Cards\",\n            size = \"large\",\n        }\n    },\n    actions = new []\n    {\n        new\n        {\n            type  = \"Action.OpenUrl\",\n            url   = \"http://adaptivecards.io\",\n            title = \"Learn More\"\n        }\n    },\n};\n\n// objectから生成。\ncard = AdaptiveCardAttachment.FromObject(cardObj);\n\n// カード付きでメッセージを投稿。\nmessage = (await teams.CreateDirectMessageAsync(\"your_webex_teams_account@example.com\",\n    \"[Learn More](http://adaptivecards.io) about Adaptive Card.\",\n    card)).GetData();\n\nConsole.WriteLine(\"Message was posted: ID = {0}\", message.Id);\n\n// teams.GetAttachmentActionAsync()でユーザからの入力を受け取れます。\n// 本APIClientのWebhook listner, event handlerには、これらの入力を受け取る機能があります。\n```\n\n* ゲストユーザ用のアカウントを発行して投稿する例\n\nWebex Teamsの[Guest Issuer機能](https://developer.webex.com/guest-issuer.html)を利用する例です。\n\n``` csharp\n// 暗号化されたGuest Issuer secretをストレージから読み込む。\nProtectedString secret = LoadEncryptedGuestIssuerSecret();\n\n// GuestIssuerClientのインスタンスを作成する。\nvar guestIssuer = TeamsAPI.CreateVersion1GuestIssuerClient(secret, \"your_guest_issuer_id\");\n\n\n// Guest Userを作成する。\nvar guest = (await guestIssuer.CreateGuestUserAsync(\"my-guest-id\", \"ゲストユーザ名\")).GetData();\n\n// ゲストユーザ用のTeamsAPIClientインスタンスを作成する(リトライ機能付き)。\nvar teams = TeamsAPI.CreateVersion1Client(guest, new TeamsRetryHandler(4));\n\n// ゲストユーザからメッセージを投稿する。\nvar message = (await teams.CreateDirectMessageAsync(\"your_webex_teams_account@example.com\", \"こんにちは、私はゲストユーザです！！\")).GetData();\n\nConsole.WriteLine(\"メッセージが投稿されました: ID = {0}\", message.Id);\n```\n\n\n* Pagination機能を利用する例\n\nWebex Temas REST APIの[Pagination機能](https://developer.webex.com/pagination.html)の例が以下になります。  \nスペースを50個ずつ取得していって、特定の名前のスペースへ「こんにちは」を投稿します。\n\n``` csharp\n// すべてのGroupスペースを取得するためにEnumeratorを取得します。\nvar e = (await teams.ListSpacesAsync(\n                       type: SpaceType.Group,\n                       max: 50)\n        ).GetListResultEnumerator();\n\n// すべてのスペースを取得するまで繰り返します。\nwhile (await e.MoveNextAsync())\n{\n  var r = e.CurrentResult;\n\n  if (r.IsSuccessStatus \u0026\u0026 r.Data.HasItems)\n  {\n    // それぞれの結果にスペースのリストが含まれます。\n    foreach (var space in r.Data.Items)\n    {\n      // 特定の名前のスペースに、「こんにちは」と投稿します。\n      if (space.Title == \"Webex Teams API Client(Thrzn41.WebexTeams)のデモ用スペース\")\n      {\n        await teams.CreateMessageAsync(space, \"こんにちは、Webex Teams！！\");\n      }\n    }\n\n  }\n}\n```\n\nほかのサンプルは、 [こちら](https://github.com/thrzn41/WebexTeamsAPIClientSamples)。\n\n\n---\n## 利用可能なプラットフォーム\n* .NET Standard 1.3以降\n* .NET Core 1.0以降\n* .NET Framework 4.5.2以降\n\n\u003e 注記: 簡易Webhookサーバ機能を利用する場合は、  \n\u003e .NET Standard 2.0+, .NET Core 2.0+, .NET Framework 4.5.2+が必要です。\n\n---\n## サンプル\n\nWebex Teams API Clientのサンプルは、 [こちらをクリック](https://github.com/thrzn41/WebexTeamsAPIClientSamples)。\n\n---\n## 利用可能な機能\n\n* Webex Teamsの基本的なAPI(List/Get/Create Message, Spaceなど)。\n* Webex TeamsのAdmin API(List/Get Event, Licenseなど)。\n* ストレージに保存するTokenの暗号化と復号。\n* AdaptiveCardsの添付(カードの作成やユーザ入力の取得)。\n* List API用のPagination機能。Paginationを簡単にするためのEnumerator。\n* Retry-after値の処理とRetry handler。\n* Markdown builder。\n* エラーコードや詳細の取得。\n* Webhook secretの検証とWebhook notification manager、Webhook event handler。\n* Guest Issuer helper。\n* OAuth2 helper。\n* 簡易Webhookサーバ機能(.NET Standard 2.0+, .NET Core 2.0+, .NET Framework 4.5.2+)。\n\n### 基本機能\n\n| Teamsのリソース名                  | 利用可能な機能                 | 説明                                 |\n| :-------------------------------- | :---------------------------- | :---------------------------------- |\n| Person/People                     | List/Get                      | v1.2.2から利用可能。Get Meも利用可能                     |\n| Space(Room)                       | List/Create/Get/Update/Delete | v1.2.2から利用可能。Roomは、API Clientでは、Spaceと呼ばれる。                                  |\n| Space(Room) Meeting Info    | Get                           | v1.7.1から利用可能。   |\n| SpaceMembership(Membership)       | List/Create/Get/Update/Delete | v1.2.2から利用可能。Membershipは、API Clientでは、SpaceMembershipと呼ばれる。        |\n| Message                           | List/Create/Get/Delete        | v1.2.2から利用可能。ローカルのstreamからファイル添付も可能 |\n| AdaptiveCards               | List/Create/Get/Delete        | v1.7.1から利用可能。 |\n| AttachmentActions           | Create/Get                    | v1.7.1から利用可能。 |\n| Team                              | List/Create/Get/Update/Delete | v1.2.2から利用可能。                                   |\n| TeamMembership                    | List/Create/Get/Update/Delete | v1.2.2から利用可能。                                   |\n| Webhook                           | List/Create/Get/Update/Delete | v1.2.2から利用可能。                                   |\n| File                              | GetInfo/GetData/Upload        | v1.2.2から利用可能。                                   |\n| Place/Device/xAPI           | -                             | v1.8.1で計画中。                                      |\n\n\n### Admin機能\n| Teamsのリソース名 | 利用可能な機能                | 説明 |\n| :-------------- | :---------------------------- | :---------------------------------------------- |\n| Person/People   | Create/Update/Delete          | v1.2.2から利用可能。                                       |\n| Event           | List/Get                      | v1.2.2から利用可能。                                       |\n| Organization    | List/Get                      | v1.2.2から利用可能。                                       |\n| License         | List/Get                      | v1.2.2から利用可能。                                       |\n| Role            | List/Get                      | v1.2.2から利用可能。                                       |\n| GroupResource            | List/Get                      | v1.2.2から利用可能。                                      |\n| GroupResourceMembership  | List/Get/Update                      | v1.2.2から利用可能。                                      |\n\n### ストレージのTokenの暗号化と復号\n\n`ProtectedString`が、Token保存時の暗号化と、読み込み時の復号の機能を提供します。  \n詳細は後述。\n\n### Pagination機能\n\nCisco Webex Teams APIのpaginationに関しては、[ここ](https://developer.webex.com/pagination.html)を参照。\n\n`result.HasNext`と`result.ListNextAsync()`が、Webex Teams API Clientで利用可能です。  \n詳細は後述。\n\n### Retry-Afterの取得\n\n`result.HasRetryAfter`と `result.RetryAfter`が、Webex Teams API Clientで利用可能です。  \nまた、 `TeamsRetryHandler`と`TeamsRetryOnErrorHandler`が利用可能です。  \n詳細は後述。\n\n### HTTP Statusコードの取得\n\n`result.HttpStatusCode`が、Webex Teams API Clientで利用可能です。  \n詳細は後述。\n\n### エラーコードと詳細の取得\n\nCisco Webex Teams APIは、エラーコードと詳細を返す場合があります。  \n`result.Data.HasErrors`と`result.Data.GetErrors()`が、Webex Teams API Clientで利用可能です。\n\n### 部分エラーの取得\n\nCisco Webex Teams APIは、部分的なエラーを返す場合があります。  \n部分エラーの詳細に関しては、[ここ](https://developer.webex.com/errors.html)を参照。  \n`Item.HasErrors`と`Item.GetPartialErrors()`が、Webex Teams API Clientで利用可能です。\n\n### trackingIdの取得\n\ntrackingIdは、Cisco Webex Teams APIのテクニカルサポートで利用される可能性があります。\n\n`result.TrackingId`が、Webex Teams API Clientで利用可能です。  \n詳細は後述。\n\n### Validates webhook secret\n\n`Webhook.CreateEventValidator()`が、Webex Teams API Clientで利用可能です。   \n詳細は後述。\n\nWebex Teams API Clientの`CreateWebhookAsync()`メソッドはデフォルトでは、webhook secretを動的に生成します。\n\n### Webhook listener(.NET Standard 2.0+, .NET Core 2.0+, .NET Framework 4.5.2+)\n\nWebhook listener機能は、簡易的なWebhookのサーバ機能を提供します。  \n\u003e **注記: この機能は、簡単なテスト時の利用を想定しています。  \n\u003e 運用環境等では、より信頼性のあるサーバをご利用ください。**\n\n`WebhookListener`が、Webex Teams API Clientで利用可能です。   \n詳細は後述。\n\n---\n## 基本的な使い方\n\n### Webex Teams API Clientのインストール\n\n`Webex Teams API Client`は、以下のいずれかの方法で、`NuGet` package manager経由で入手できます。\n\n* NuGet Package ManagerのGUI  \n\"`Thrzn41.WebexTeams`\"を検索してインストール。\n\n* NuGet Package ManagerのCLI  \n```\nPM\u003e Install-Package Thrzn41.WebexTeams\n```\n\n* .NET Client  \n```\n\u003e dotnet add package Thrzn41.WebexTeams\n```\n\n### Webex Teams API Client関連のusingディレクティブ\n\nusingディレクティブを利用する場合は、以下の名前空間を指定します。\n\n``` csharp\nusing Thrzn41.Util\nusing Thrzn41.WebexTeams\nusing Thrzn41.WebexTeams.Version1\n```\n\n必要に応じて、以下も利用可能です。\n* Guest Issuer helper利用時、`Thrzn41.WebexTeams.Version1.GuestIssuer`\n* OAuth2 helper利用時、`Thrzn41.WebexTeams.Version1.OAuth2`\n* Admin API利用時、`Thrzn41.WebexTeams.Version1.Admin`\n\n\n### Webex Teams API Clientインスタンスの作成\n\nWebex Teams API Clientのインスタンスは可能な限り長い期間使いまわすようにします。\n\n``` csharp\n/// 基本API利用時。\nTeamsAPIClient teams = TeamsAPI.CreateVersion1Client(token);\n```\n\nAdmin APIを利用する場合は、Admin API用のインスタンスを作成する必要があります。  \n`TeamsAdminAPIClient`は、`TeamsAPIClient`の全機能に加えて、Adminの機能が利用できます。  \n``` csharp\n/// Admin API利用時。\nTeamsAdminAPIClient teams = TeamsAPI.CreateVersion1AdminClient(token);\n```\n\n\u003e **注記: 'token'は、Cisco Webex Teams APIでは、非常にセンシティブな情報です。  \n\u003e 'token'は、慎重に保護する必要があります。  \n\u003e ソースコード中に直接記載したり、安全ではない方法で保存しないようにします。  \n\u003e `Webex Teams API Client`では、トークンを暗号化したり復号する方法を、いくつか提供しています。  \n\u003e 独自の方法で暗号化や復号、保護を実装する場合は、インスタンス作成時に、復号されたトークン文字列を利用することができます。**\n\n### 暗号化したTokenをストレージに保存する\n\n``` csharp\nchar[] tokens = GetBotTokenFromBotOwner();\n\nvar protectedToken = LocalProtectedString.FromChars(tokens);\nLocalProtectedString.ClearChars(tokens);\n\nSave(\"token.dat\",   protectedToken.EncryptedData);\nSave(\"entropy.dat\", protectedToken.Entropy);\n```\n\n**注記: LocalProtectedStringはメモリ内での保護は提供していません。  \nTokenを保存する際の、暗号化と復号での利用を想定しています。**\n\n\n### 暗号化したTokenをストレージから読み込んで、Webex Teams API Clientのインスタンスを作成する\n\n``` csharp\nbyte[] encryptedData = Load(\"token.dat\");\nbyte[] entropy       = Load(\"entropy.dat\");\n\nvar protectedToken = LocalProtectedString.FromEncryptedData(encryptedData, entropy);\n\n/// 基本API利用時。\nTeamsAPIClient teams = TeamsAPI.CreateVersion1Client(protectedToken);\n```\n\n\u003e **注記: オプションに応じて、暗号化されたデータは、暗号化したときと同じローカルユーザまたはローカルマシン上でのみ復号できます。**\n\n### Cisco Webex Teamsのスペースにメッセージを投稿する\n\n``` csharp\nvar result = await teams.CreateMessageAsync(\"xyz_space_id\", \"こんにちは, Teams!\");\n\nif(result.IsSuccessStatus)\n{\n   Console.WriteLine(\"メッセージが投稿されました: id = {0}\", result.Data.Id);\n}\n```\n\n### 成功, 失敗, エラーのハンドリング\n\n`result.IsSuccessStatus`を使って成功したかどうか確認できます。  \n`result.Data.HasErrors`や`result.Data.GetErrorMessage()`を使ってCisco Webex Teams APIサービスからエラーコード、エラーメッセージを受け取ることができます。\n\n``` csharp\nvar result = await teams.CreateMessageAsync(\"xyz_space_id\", \"こんにちは, Teams!\");\n\nif(result.IsSuccessStatus)\n{\n   Console.WriteLine(\"メッセージが投稿されました: id = {0}\", result.Data.Id);\n}\nelse\n{\n  Console.WriteLine(\"メッセージの投稿に失敗しました: status = {0}, trackingId = {1}\", result.HttpStatusCode, result.TrackingId);\n\n  if(result.Data.HasErrors)\n  {\n    Console.WriteLine( result.Data.GetErrorMessage() );\n  }\n}\n```\n\n例外を捕捉したい場合は、データ取得時に、`result.GetData()`を利用することができます。  \n`result.GetData()`は、リクエスト失敗時に`TeamsResultException`をスローします。  \n(一方、`result.Data`は、`TeamsResultException`を送出しません。)\n\n``` csharp\ntry\n{\n  var result = await teams.CreateMessageAsync(\"xyz_space_id\", \"こんにちは, Teams!\");\n\n  var message = result.GetData();\n\n  Console.WriteLine(\"メッセージが投稿されました: id = {0}\", message.Id);\n}\ncatch(TeamsResultException tre)\n{\n  Console.WriteLine(\"メッセージの投稿に失敗しました: status = {0}, trackingId = {1}, description = {2}\",\n                      tre.HttpStatusCode, tre.TrackingId, tre.Message);\n}\n```\n\n### Cisco Webex Teamsのスペースに添付ファイル付きでメッセージを投稿する\n\n``` csharp\nusing (var fs   = new FileStream(\"path/myfile.png\", FileMode.Open, FileAccess.Read, FileShare.Read))\nusing (var data = new TeamsFileData(fs, \"imagefile.png\", TeamsMediaType.ImagePNG))\n{\n    var result = await teams.CreateMessageAsync(\"xyz_space_id\", \"添付ファイル付き\", data);\n\n    if(result.IsSuccessStatus)\n    {\n       Console.WriteLine(\"添付ファイル付きでメッセージが投稿されました: id = {0}\", result.Data.Id);\n    }\n}\n```\n\n### Cisco Webex Teamsの1:1スペースにメッセージを投稿する\n\n``` csharp\nvar result = await teams.CreateDirectMessageAsync(\"targetuser@example.com\", \"こんにちは, Teams!\");\n\nif(result.IsSuccessStatus)\n{\n   Console.WriteLine(\"メッセージが投稿されました: id = {0}\", result.Data.Id);\n}\n```\n\n### スペースの一覧を取得する\n\n``` csharp\nvar result = await teams.ListSpacesAsync();\n\nif(result.IsSuccessStatus \u0026\u0026 result.Data.HasItems)\n{\n  foreach (var item in result.Data.Items) {\n    Console.WriteLine(\"Space: title = {0}\", item.Title);\n  }  \n}\n```\n\n### ファイルの情報やデータを取得する\n\nダウンロードせずにファイルの情報だけ入手する。\n\n``` csharp\nvar result = await teams.GetFileInfoAsync(new Uri(\"https://api.example.com/path/to/file.png\"));\n\nif(result.IsSuccessStatus)\n{\n  var file = result.Data;\n\n  Console.WriteLine(\"File: Name = {0}, Size = {1}, Type = {2}\", file.Name, file.Size?.Value, file.MediaType?.Name);\n}\n```\n\nファイルをダウンロードする。  \nこの例では、ファイルのデータがMemoryStreamにコピーされます。\n``` csharp\nusing(var stream = new MemoryStream())\n{\n  var result = await teams.CopyFileDataToStreamAsync(new Uri(\"https://api.example.com/path/to/file.png\"), stream);\n\n  if(result.IsSuccessStatus)\n  {\n    var file = result.Data;\n\n    Console.WriteLine(\"File: Name = {0}, Size = {1}, Type = {2}\", file.Name, file.Size?.Value, file.MediaType?.Name);\n  }\n}\n```\n\n### Pagination機能を利用する\n\n``` csharp\nvar result = await teams.ListSpacesAsync();\n\nif(result.IsSuccessStatus)\n{\n  //\n  // ここで何か処理する...\n  //\n\n  if(result.HasNext)\n  {\n    // 続きのリストがあれば取得する。\n    result = await result.ListNextAsync();\n\n    if(result.IsSuccessStatus)\n    {\n      // ...\n    }\n  }\n}\n```\n\n### Enumeratorを使ってPaginaionを利用する\n\n``` csharp\n// すべてのGroupスペースを取得するためにEnumeratorを取得します。\nvar e = (await teams.ListSpacesAsync(\n                       type: SpaceType.Group,\n                       max: 50)\n        ).GetListResultEnumerator();\n\n// すべてのスペースを取得するまで繰り返します。\nwhile (await e.MoveNextAsync())\n{\n  var r = e.CurrentResult;\n\n  if (r.IsSuccessStatus \u0026\u0026 r.Data.HasItems)\n  {\n    // それぞれの結果にスペースのリストが含まれます。\n    foreach (var space in r.Data.Items)\n    {\n      Console.WriteliLine(\"Title = {0}\", space.Title);\n    }\n\n  }\n}\n```\n\n### Http status codeを取得する\n\n``` csharp\nvar result = await teams.ListSpacesAsync();\n\nConsole.WriteLine(\"Status is {0}\", result.HttpStatusCode);\n```\n\n### Retry afterを取得する.\n\n``` csharp\nvar result = await teams.ListSpacesAsync();\n\nif(result.IsSuccessStatus)\n{\n  //\n  // ここで何かする...\n  //\n}\nelse if(result.HasRetryAfter)\n{\n  Console.WriteLine(\"{0}後にリトライしなきゃ!!\", result.RetryAfter.Delta);  \n}\n```\n\n### Retry Handler\n\n`TeamsRetryHandler`と`TeamsRetryOnErrorHandler`を利用してリトライ処理を容易にします。\n\n``` csharp\n// リトライ機能付きでインスタンスを作成(この場合は、最大4回のリトライ)。\nvar teams = TeamsAPI.CreateVersion1Client(token, new TeamsRetryHandler(4));\n\n// リクエスト時に、HTTP 429のレスポンスがあると、リトライが行われます。\nvar result = await teams.GetMeAsync();\n\n\n//HTTP 500, 502, 503, 504レスポンス時にもリトライしたい場合は、TeamsRetryOnErrorHandlerを利用します。\n// Retry-Afterヘッダがない場合は、この例の場合は、15秒後にリトライが行われます。\nvar teams = TeamsAPI.CreateVersion1Client(token, new TeamsRetryOnErrorHandler(4, TimeSpan.FromSeconds(15.0f)));\n```\n\n### TrackingIdを取得する\n\n``` csharp\nvar result = await teams.ListSpacesAsync();\n\nConsole.WriteLine(\"Tracking id: {0}\", result.TrackingId);  \n```\n\n### Markdown Builder.\n\n``` csharp\nvar md = new MarkdownBuilder();\n\n// メンションと番号付きリストでMarkdownを作成。\nmd.Append(\"こんにちは、\").AppendMentionToPerson(\"xyz_person_id\", \"〇〇さん\").AppendLine();\nmd.AppendOrderedList(\"Item1\");\nmd.AppendOrderedList(\"Item2\");\nmd.AppendOrderedList(\"Item3\");\n\nvar result = await teams.CreateMessageAsync(\"xyz_space_id\", md.ToString());\n```\n\n### Webhookに通知されたデータを検証する\n\n``` csharp\nvar webhook = await teams.GetWebhookAsync(\"xyz_webhook_id\");\n\nvar validator = webhook.CreateEventValidator();\n```\n\nイベントがWebhookのURIに通知された際には、\nX-Spark-Signatureがハッシュ値を持っています。\n\nvalidatorを利用して、データの整合性を確認できます。\n\n``` csharp\nbyte[] webhookEventData = GetWebhookEventData();\n\nif( validator.Validate(webhookEventData, \"xyz_x_teams_signature_value\") )\n{\n  Console.WriteLine(\"通知されたイベントデータの検証に成功!\");\n}\n```\n\n### Webhookの通知管理\n\nWebhook notification managerを使ってWebhookへの通知を管理します。\n\n\n* インスタンスを作成する。\n\n``` csharp\nvar notificationManager = new WebhookNotificationManager();\n```\n\n* 通知用のfunctionを登録します。\n\n``` csharp\nvar webhook = await teams.GetWebhookAsync(\"xyz_webhook_id\");\n\nnotificationManager.AddNotification(\n  webhook,\n  (eventData) =\u003e\n  {\n    Console.WriteLine(\"イベントを受信, id = {0}\", eventData.Id);\n  }\n);\n```\n\n* イベントの受信時。\n\n``` csharp\nbyte[] webhookEventData = GetWebhookEventData();\n\n// Signatureが確認され登録したfunctionにイベントデータが通知されます。\nnotificationManager.ValidateAndNotify(webhookEventData, \"xyz_x_teams_signature_value\", encodingOfData);\n```\n\n### Webhook Listener\n\n* Webhook listenerのインスタンスの作成。\n\n``` csharp\nvar listener = new WebhookListener();\n```\n\n* 待ち受けする、ホストとポートを登録する。\n\n待ち受けには、TLS/httpsを利用すべきです。  \nそのためには、まず、実行環境側で`netsh`ツールなどを利用して、有効な証明書をバインドしておく必要があります。\n\nバインドされたアドレスとポート番号で、エンドポイントを追加します。\n\n``` csharp\nvar endpointUri = listener.AddListenerEndpoint(\"yourwebhookserver.example.com\", 8443);\n```\n\n* Webhook listener用のWebhookを作成します。\n\n`listener.AddListenerEndpoint()`が返す`endpointUri`がWebhookの通知先Uriになります。  \n\n``` csharp\nvar result = await teams.CreateWebhookAsync(\n  \"my webhook for test\",\n  endpointUri,\n  EventResource.Message,\n  EventType.Created);\n```\n\n* Webhook listenerにWebhookと通知先funcを登録します。\n\n``` csharp\nvar webhook = result.Data;\n\nlistener.AddNotification(\n  webhook,\n  async (eventData) =\u003e\n  {\n    Console.WriteLine(\"Eventが通知されました, id = {0}\", eventData.Id);\n\n    if(eventData.Resource == EventResource.Message)\n    {\n      Console.WriteLine(\"Message, id = {0}\", eventData.MessageData.Id);\n    }\n  }\n);\n```\n\n* Listenerの開始。\n\nListenerを開始すると、イベント発生時に登録したfunctionに通知されます。\n\n``` csharp\nlistener.Start();\n```\n\n### Webhook listenerをngrokと共に利用する\n\nグローバルIPアドレスが利用できない場合、\n[ngrok](https://ngrok.com/)などのトンネリングサービスが便利な場合があります。\n\n* ngrokの入手と起動。\n\nngrokのコマンドラインツールは、[ここから入手](https://ngrok.com/)できます。\n\n以下のコマンドで、トンネリングサービスを起動して、localhostの8080ポートにフォワードされます。\n\n```\nprompt\u003e ngrok http 8080 --bind-tls=true\n```\n\n* Webhook listenerのインスタンスの作成。\n\n``` csharp\nvar listener = new WebhookListener();\n```\n\n* 待ち受けする、ホストとポートを登録する。\n\nngrokは、`localhost`へフォワードします。\n\n``` csharp\nvar endpointUri = listener.AddListenerEndpoint(\"localhost\", 8080, false);\n```\n\n* Webhook listener用のWebhookを作成します。\n\nこの例では、ngronのトンネリングサービスを利用しています。  \n`listener.AddListenerEndpoint()`が返したUriは、フォワード先のUriです。\n\nWebhookには、ngrok側のUriを指定する必要があります。\n\nngrokが、`https://ngrok-xyz.example.com`を割り当てた場合、  \n`String.Format(\"https://ngrok-xyz.example.com{0}\", endpointUri.AbsolutePath)`をWebhookの宛先として指定します。\n\n``` csharp\nvar result = await teams.CreateWebhookAsync(\n  \"テスト用のWebhook\",\n  new Uri(String.Format(\"https://ngrok-xyz.example.com{0}\", endpointUri.AbsolutePath)),\n  EventResource.Message,\n  EventType.Created);\n```\n\n* Webhook listenerにWebhookと通知先funcを登録します。\n\n``` csharp\nvar webhook = result.Data;\n\nlistener.AddNotification(\n  webhook,\n  async (eventData) =\u003e\n  {\n    Console.WriteLine(\"Eventが通知されました, id = {0}\", eventData.Id);\n\n    if(eventData.Resource == EventResource.Message)\n    {\n      Console.WriteLine(\"Message, id = {0}\", eventData.MessageData.Id);\n    }\n  }\n);\n```\n\n* Listenerの開始。\n\nListenerを開始すると、イベント発生時に登録したfunctionに通知されます。\n\n``` csharp\nlistener.Start();\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthrzn41%2Fwebexteamsapiclient","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthrzn41%2Fwebexteamsapiclient","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthrzn41%2Fwebexteamsapiclient/lists"}