はじめに
- 前回の「Blazor WebAssemblyでRestSharpを使ってみる(その1)」の続き
- RestSharpを使って、ユカイ工学さんが提供している「BOCCO emo」のAPIを使用してみます。
RestSharp
注意!!
v107以降で記述方法が大分変更となっています。
現在は、V108です。
BOCCO emo
- ユカイ工学さんが提供しているコミュニケーションロボットです。
- とってもかわいいロボットなんですが、法人向けにAPIが用意されています。
- 使用するには、法人アカウントを取得する必要があります。
- APIには、メッセージをおくるとBoccoがしゃべったり、モーションをさせたり、センサーの情報を取得できたりします。
BOCCO emo API
BOCCO emo
開発環境
- Visual Studio 2022 (C#)
- MudBlazor 6.0.9
- MudBlazor/Template
- RestSharp v108
RestSharpの適用
-
.Serverを右クリックして、Nugetパッケージの管理 を選択
- RestSharpと入力、その際、プレリリースを含めるのチェックボックスはオフにする。
前回は、Clientで追加していますが、今回は、ServerにRestSharpを適用しています。
Newton.Jsonの適用
-
.Serverを右クリックして、Nugetパッケージの管理 を選択
- Newtonsoft.jsonと入力、その際、プレリリースを含めるのチェックボックスはオフにする。
別にNewtonsoft.jsonじゃなくてもよいのですが、使い慣れているので、適用しています。
実装
- ClientのPagesに新しいRazorコンポ―ネットを追加します。
- BoccoSensor.razorを作成
アクセストークンの取得処理
モデルの作成
データモデルの作成
- *.Sharedのプロジェクトを右クリックして、追加 > クラスで「ApiTokenModel」を作成
- データモデル
- internalをpublicへ変更
ApiTokenModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ApexChartsSample.Shared
{
- internal class ApiTokenModel
+ public class ApiTokenModel
{
+ public string access_token { get; set; }
+ public string refresh_token { get; set; }
}
}
レスポンスモデルの作成
- *.Sharedのプロジェクトを右クリックして、追加 > クラスで「BoccoApiTokenResponse」を作成
- レスポンスモデル
- internalをpublicへ変更
BoccoApiTokenResponse.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ApexChartsSample.Shared
{
- internal class BoccoApiTokenResponse
+ public class BoccoApiTokenResponse
{
+ /// <summary>
+ /// 処理結果
+ /// </summary>
+ public bool IsSucceed { get; set; }
+
+ /// <summary>
+ /// メッセージ
+ /// </summary>
+ public string? ResponseMessage { get; set; }
+
+ /// <summary>
+ /// APIトークン
+ /// </summary>
+ public ApiTokenModel? ApiToken { get; set; }
}
}
リポジトリの作成
もしかしたら、この手順は不要かもしれませんが、いままでWPFで作ってたやり方をBlazorでそのまま使用しているので、インターフェース等を作っちゃってます。
- *.Serverのプロジェクトを右クリックして、追加 > 新しいフォルダ―で「Repositories」を作成
- 「Repositories」を右クリックして、追加 > 新しいフォルダ―で「Interface」を作成
- 「Interface」を右クリックして、追加 > 新規項目 > インターフェースで「IBoccoServiceRepository」を作成
- IBoccoServiceRepositoryの記述
IBoccoServiceRepository.cs
using ApexChartsSample.Shared;
namespace ApexChartsSample.Server.Repositories.Interface
{
public interface IBoccoServiceRepository
{
+ /// <summary>
+ /// アクセストークンの取得
+ /// </summary>
+ /// <returns></returns>
+ public Task<BoccoApiTokenResponse> GetAccessToken();
}
}
- 「Repositories」を右クリックして、追加 > クラスで、「BoccoServiceRepository」を作成
- BoccoServiceRepositoryの記述
- IBoccoServiceRepositoryを継承
BoccoServiceRepository.cs
+ using ApexChartsSample.Shared;
+ using ApexChartsSample.Server.Repositories.Interface;
+ using RestSharp;
+ using Newtonsoft.Json;
namespace ApexChartsSample.Server.Repositories
{
- public class BoccoServiceRepository
+ public class BoccoServiceRepository : IBoccoServiceRepository
{
+ // Bocco API リフレッシュトークン
+ private readonly string _refreshToken = "{法人アカウントで割り振られたリフレッシュトークン}";
+ /// <summary>
+ /// Boccoアクセストークンの取得
+ /// </summary>
+ /// <returns>トークンモデル</returns>
+ public async Task<BoccoApiTokenResponse> GetAccessToken()
+ {
+ var restClient = new RestClient();
+ var url = "https://platform-api.bocco.me/oauth/token/refresh";
+ var request = new RestRequest(url, Method.Post);
+ request.AddHeader("Content-Type", "application/json");
+
+ var body = new { refresh_token = _refreshToken };
+ var bodyJson = JsonConvert.SerializeObject(body);
+ request.AddBody(bodyJson, "application/json");
+ RestResponse response = await restClient.ExecuteAsync(request);
+
+ var model = new ApiTokenModel();
+ var returnModel = new BoccoApiTokenResponse();
+ if (response.IsSuccessful)
+ {
+ model = JsonConvert.DeserializeObject<ApiTokenModel>(response.Content);
+ returnModel.IsSucceed = true;
+ returnModel.ResponseMessage = response.StatusDescription;
+ returnModel.ApiToken = model;
+ }
+ else
+ {
+ model = null;
+
+ returnModel.IsSucceed = false;
+ returnModel.ResponseMessage = response.ErrorMessage;
+ returnModel.ApiToken = model;
+ }
+
+ return returnModel;
+ }
}
}
補足:Postmanの場合
- PostmanでRestsharp変換を見ると
- AddParameterの記述の仕方等が異なることがわかるかと思います。
- なので、Postmanでテストしてそのままコードが流用できないのが残念。。。。
Postmanのコード変換機能の場合
var client = new RestClient("https://platform-api.bocco.me/oauth/token/refresh");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "application/json");
var body = @"{""refresh_token"": ""{法人アカウントで割り振られたリフレッシュトークン}""}";
request.AddParameter("application/json", body, ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
コントローラーの作成
- *.Serverのプロジェクトを右クリックして、追加 > 新しい項目で「BoccoServiceController」を作成
- ちょっと変則な処理ですが、コントローラー側では、GetでRepositoryでは、Postになっているのは、Repository側でPostパラメータを処理しているため、そのような形にしました。
BoccoServiceController.cs
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
+ using ApexChartsSample.Server.Repositories;
+ using ApexChartsSample.Server.Repositories.Interface;
+ using ApexChartsSample.Shared;
namespace ApexChartsSample.Server.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class BoccoServiceController : ControllerBase
{
+ private readonly ILogger<BoccoServiceController> _logger;
+
+ private IBoccoServiceRepository boccoServiceRepository;
+
+ public BoccoServiceController(ILogger<BoccoServiceController> logger)
+ {
+ _logger = logger;
+ this.boccoServiceRepository = new BoccoServiceRepository();
+ }
+
+ /// <summary>
+ /// アクセストークン取得
+ /// </summary>
+ /// <returns></returns>
+ [HttpGet("/GetAccessToken")]
+ public async Task<BoccoApiTokenResponse> GetAccessToken()
+ {
+ var returnModel = new BoccoApiTokenResponse();
+ returnModel = await boccoServiceRepository.GetAccessToken();
+ return returnModel;
+ }
}
}
ページデザイン
- デザインを作成
- MudOverlayは、MudBlazorのページ読み込み時等に使用できるモーダルパーツでLoadingを表示したいときに使用してます。
BoccoSensor.razor(デザイン部分)
@page "/BoccoSensor"
@using ApexChartsSample.Shared
@using RestSharp
@inject RestClient _restClient;
@inject NavigationManager _navigationManager
@inject ISnackbar Snackbar;
<PageTitle>部屋センサー ログ</PageTitle>
<MudText Typo="Typo.h4" GutterBottom="true">部屋センサー ログ</MudText>
<div class="d-flex flex-grow-1 flex-row">
<MudGrid>
<MudItem xs="12" >
<MudPaper Class="d-flex">
<MudTextField @bind-Value="_accessToken" Label="Read Only" ReadOnly="true" Variant="Variant.Text" />
<MudButton OnClick="@(() => GetToken())" Variant="Variant.Outlined" Color="MudBlazor.Color.Secondary" Size="Size.Small" >トークン取得</MudButton>
</MudPaper>
</MudItem>
</MudGrid>
</div>
<MudOverlay @bind-Visible="_loading" DarkBackground="true" ZIndex="9999" AutoClose="false">
<center><MudProgressCircular Color="MudBlazor.Color.Primary" Size="Size.Large" Indeterminate="true"/></center>
<MudText Typo="Typo.h1" Color="MudBlazor.Color.Dark">Loading...</MudText>
</MudOverlay>
- 処理部分
BoccoSensor.razor(処理部分)
@code {
+ /// <summary>
+ /// 画面抑止用
+ /// </summary>
+ private bool _loading;
+
+ /// <summary>
+ /// アクセストークン
+ /// </summary>
+ public string _accessToken { get; set; } = String.Empty;
+
+ /// <summary>
+ /// 初期処理
+ /// </summary>
+ /// <returns></returns>
+ protected override async Task OnInitializedAsync()
+ {
+ _loading = true;
+
+ try
+ {
+ await Task.Delay(2000);
+ }
+ catch (Exception ex)
+ {
+ Snackbar.Add(ex.Message, Severity.Error);
+ }
+ finally
+ {
+ _loading = false;
+ }
+ }
+
+ /// <summary>
+ /// アクセストークンの取得
+ /// </summary>
+ /// <returns></returns>
+ private async Task GetToken()
+ {
+ _loading = true;
+ try
+ {
+ var returnModel = new BoccoApiTokenResponse();
+ var url = _navigationManager.BaseUri + "GetAccessToken";
+ returnModel = await _restClient.GetJsonAsync<BoccoApiTokenResponse>(url);
+
+ if(returnModel.IsSucceed == true)
+ {
+ _accessToken = returnModel.ApiToken.access_token;
+ StateHasChanged();
+ }
+ }
+ catch (Exception ex)
+ {
+ Snackbar.Add(ex.Message, Severity.Error);
+ }
+ finally
+ {
+ _loading = false;
+ }
+ }
}
- ナビゲーションの追加
- 先ほど作成したページへ遷移できるようにナビゲーションメニューに項目を追加
NavMenu.razor
<MudNavMenu>
<MudNavLink Href="" Match="NavLinkMatch.All" Icon="@Icons.Material.Filled.Home">Home</MudNavLink>
<MudNavLink Href="counter" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.Add">Counter</MudNavLink>
<MudNavLink Href="fetchdata" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.List">Fetch data</MudNavLink>
+ <MudNavLink Href="BoccoSensor" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.Sensors">部屋センサー</MudNavLink>
</MudNavMenu>
デバッグ実行
- デバッグを実行し、ナビゲーションからトークン取得ボタンを押下すると、InputBoxにトークンが無事表示されていることが確認できました。
補足
- タイトルの部屋センサーの取得までやろうと思ったのですが、一旦トークンの取得までで投稿しました。