.NET Core Blazor + MicroCMSでブログサイト作成③
今回はMicroCMSにブログ記事やメタデータのスキーマを登録し、お試しデータを追加します。
その後Controllerを介してAPIリクエスト/レスポンスのやり取りをし、画面に反映させる実装を行います。
MicroCMSの設定
サイトデータ(オブジェクト形式)
タグ(リスト形式)
記事(リスト形式)
データ受け取り用のクラス作成
MicroCMSから取得したデータをデシリアライズ(JSON⇒オブジェクトの変換)してクライアントに渡すためのクラスを作成します。
作成場所はBlazorBlog.Shared/MicroCMS
です。
MicroCMSフォルダをBlazorBlog.Shared下に作成して、クラスの追加をします。
各クラスのメンバー名をMicroCMSで設定したフィールドIDと同じにすることでデシリアライズが可能です。別名にする場合はクラスのメンバーに[JsonPropertyName("JSONプロパティ名")]
アノテーションを付けます。
また大文字/小文字の違いは区別されますが、これはデシリアライズの設定で無視するようにできます。
SiteData.cs
using System;
using System.Text.Json.Serialization;
namespace BlazorBlog.Shared
{
public class SiteData
{
[JsonPropertyName("title")]
public string BlogTitle { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
public DateTime PublishedAt { get; set; }
public DateTime RevisedAt { get; set; }
}
}
Tags.cs
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace BlazorBlog.Shared
{
public class Tags
{
[JsonPropertyName("contents")]
public List<TagContents> TagList { get; set; }
public int TotalCount { get; set; }
public int Offset { get; set; }
public int Limit { get; set; }
}
public class TagContents
{
public string Id { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
public DateTime PublishedAt { get; set; }
public DateTime ReviesdAt { get; set; }
public string Name { get; set; }
}
}
記事
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace BlazorBlog.Shared
{
public class Blogs
{
[JsonPropertyName("contents")]
public List<BlogContents> BlogList { get; set; }
public int TotalCount { get; set; }
public int Offset { get; set; }
public int Limit { get; set; }
}
public class BlogContents
{
public string Id { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
public DateTime PublishedAt { get; set; }
public DateTime RevisedAt { get; set; }
public string Title { get; set; }
public TagContents Tag { get; set; }
public string Body { get; set; }
}
}
appsettings.json
MicroCMSへリクエストを送るURLを記述します。
{
"AllowedHosts": "*",
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
// 以下追記
"MicroCMS": {
"BaseUrl": "https://[サービスID].microcms.io/api/v1/",
"X-API-KEY": "MicroCMSの管理画面から確認します",
"Endpoints": {
"SiteData": "sitedata",
"Tags": "tags",
"Blogs": "blogs"
}
}
}
Controller
MicroCMSにHTTPSリクエストを送り、デシリアライズして、クライアントに渡すためのコントローラーを作成します。
デフォルトで作成されているWeatherForecastController.cs
をパクって作ります。
using BlazorBlog.Shared;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;
namespace BlazorBlog.Server.Controllers
{
[ApiController]
[Route("[controller]")]
public class MicroCMSController : ControllerBase
{
// EntityFrameworkを使うときのロガー。今回は使わないけどとりあえず置いとく。
private readonly ILogger<MicroCMSController> _logger;
// appsettings.jsonのDI。後述。
private readonly IConfiguration _configuration;
public MicroCMSController(ILogger<MicroCMSController> logger, IConfiguration configuration)
{
_logger = logger;
_configuration = configuration;
}
/// <summary>
/// サイトデータ取得
/// </summary>
/// <returns>サイトデータ</returns>
[HttpGet]
public async Task<SiteData> Get()
{
// APIコールのベースURL
var baseUrl = _configuration.GetSection("MicroCMS").GetValue<string>("BaseUrl");
// エンドポイント
var endpoint = _configuration.GetSection("MicroCMS").GetSection("Endpoints").GetValue<string>("SiteData");
// X-API-KEY
var apikey = _configuration.GetSection("MicroCMS").GetValue<string>("X-API-KEY");
// URL全体
string url = baseUrl + endpoint;
using (var client = new HttpClient())
{
// ヘッダーに認証キーを登録
var request = new HttpRequestMessage(HttpMethod.Get, url);
request.Headers.Add("X-API-KEY", apikey);
// リクエスト送信
var response = await client.SendAsync(request);
// レスポンスから結果を取り出しデシリアライズ
var result = await response.Content.ReadAsStringAsync();
// デシリアライズ時の属性名の大文字/小文字の差異を無視する設定
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
SiteData deserialisedResult = JsonSerializer.Deserialize<SiteData>(result, options);
return deserialisedResult;
}
}
}
}
appsettings.jsonのDI
上記ではprivate readonly IConfiguration _configuration
をメンバーに置き、コンストラクタで初期化しています。
本来はこのやり方はよろしくないです。DIはプロジェクトの起動時にまとめて行われるべきもので、各クラスで個別に行われるものではないからです(多分)。
「通常はコントローラーに IConfiguration を直接挿入しないでください」と公式に言われています。👇
テンプレート
@page "/fetchdata"
@using BlazorBlog.Shared
@inject HttpClient Http
<h1>Blog</h1>
<p>This component demonstrates fetching data from the server.</p>
@if (sitedata == null)
{
<p><em>Loading...</em></p>
}
else
{
<p>@sitedata.Title</p>
}
@code {
private SiteData sitedata;
protected override async Task OnInitializedAsync()
{
try
{
sitedata = await Http.GetFromJsonAsync<SiteData>("MicroCMS");
}
catch (Exception ex)
{
// エラー処理もホントはちゃんとやらないと...
Console.WriteLine(ex.ToString());
}
}
}
デバッグ
コントローラー内のusing
内にブレークポイントを置いて、デバッグしてみます。
👇
(Bootstrap5を使うためにちょっとデザイン変えてます)
👇
リクエストするURLもきちんと構築されています。
少しステップ実行してみて、レスポンスを受け取ってみます。
ステータス200で正常に返ってきたようです。
少しデバッグを進めてデシリアライズさせてみると、きちんとSiteDataクラスにデータを格納して受け取れています。
これをテンプレートに返すことで、画面に表示することができます。
ここまでの実装をTags
とBlogs
でも行えば、データを取得することができます。
JsonPropertyNaneアノテーションを外すと...?
試しにSiteData.cs
の[JsonPropertyName("title")]
を外してみます。
ブレークポイントなしでデバッグ実行すると、Fetch Dataページにアクセスしてもタイトルが出てきません。
MicroCMSController.cs
のreturn deserialisedResult;
にブレークポイントをおいてもう1回アクセスしてみます。
残念ながら、BlogTitle
にはnull
が入っています。NullPointerException的な例外は出ないんですね。
他にもJSONシリアライズ/デシリアライズに関するおもしろいトピックスがあるので、見てみてください。👇
次回
- タグ一覧取得、ブログ記事一覧取得のアクションを定義するために、エンドポイントの設定を変えます。
- appsettings.jsonのDI問題を解決します。
Discussion