みなさん、こんにちは。砂漠の果ての狼です。
Dotnet9サイトがBlazorで再構築され、アクセス速度が格段に速くなりました。同時にBlazorのインタラクション機能を活用し、サイト管理者もいくつかのオンラインツールを追加しました。この記事ではBlazorの再構築プロセスを共有し、皆さんのWebサイト開発における技術選定の参考になれば幸いです。

1. まずRazor Pagesについて
前バージョンのサイトフロントエンドはRazor Pagesで開発されていました。当時この技術スタックを選んだのは、主に検索エンジンのSEO最適化のためです。
MVCとRazor Pagesのどちらが優れているかについては、ここではRazor Pagesの相対的な利点のみを述べます。
まず、Razor PagesはMVCに比べてよりシンプルで直感的です。Razor Pagesはビューと処理ロジックを同じページにカプセル化するため、開発者はコードをより容易に理解し保守できます。小規模なプロジェクトやページ数が少ないアプリケーションでは、Razor Pagesはより速い開発速度とより簡潔なコード構造を提供します。これが、サイト管理者が以前MVCからRazor Pagesに再構築した主な理由です。
次に、Razor PagesはSEO(検索エンジン最適化)の面で一定の利点があります。Razor Pagesはビューと処理ロジックを同じページにカプセル化するため、検索エンジンはページのコンテンツをより容易に理解しインデックスできます。これは、より良い検索エンジンランキングを必要とするアプリケーションにとって重要な考慮事項です。
Razor Pagesの利点を述べましたが、ではなぜ今Blazorに切り替えたのでしょうか?それはBlazorがさらに良い選択肢だからです。続けて説明します。
2. 重要なポイント:Blazorについて
Blazorは新しいWeb開発フレームワークで、開発者はC#言語を使用してWebアプリケーションを記述でき、JavaScriptを使う必要がありません。もちろん、できるだけ使わないようにするという意味で、完全に使わないのは現実的ではありません。Razor PagesやMVCと比較して、Blazorは全く新しい開発モデルを提供し、多くの独自の利点と適用シナリオを持っています。
まず、Blazorは真のフロントエンド開発体験を提供します。従来のWeb開発では、フロントエンド開発者はJavaScriptを使ってページのインタラクションや動的効果を処理し、バックエンド開発者はビジネスロジックやデータ操作を担当します。この分離された開発モデルは、開発者間のコミュニケーションや協力の問題を引き起こす可能性があります。一方、BlazorはC#言語を使ってフロントエンドコードを記述するため、フロントエンドとバックエンドの開発者が同じ言語とツールを使い、より効率的に協力して開発できます。
次に、Blazorはより優れたパフォーマンスとユーザーエクスペリエンスを提供します。Blazorはクライアントモードとサーバーモードの2つのモードを提供します(Blazorハイブリッドモードについてはまた別の機会に):
- クライアントモード:BlazorはWebAssembly技術を使用し、ブラウザ内でコンパイル済みのバイナリコードを直接実行するため、ネイティブアプリケーションに近いパフォーマンスを実現できます。
- サーバーモード:従来のHTTPリクエストベースのページリフレッシュと比較して、BlazorはSignalR接続を使用してリアルタイムデータ更新と双方向バインディングを実現し、より高速でスムーズなユーザーエクスペリエンスを提供します。
さらに、Blazorはより優れた再利用性とコンポーネント指向開発を備えています。Blazorは豊富なコンポーネントライブラリとツールを提供し、開発者は美しく強力なインターフェースをより迅速に構築できます。開発者はよく使うUIコンポーネントを再利用可能なコンポーネントとしてカプセル化し、開発効率とコード品質を向上させることができます。
また、Blazorはモダンなフロントエンド開発技術とツールもサポートしています。開発者はBlazorを既存のJavaScriptライブラリやフレームワーク(React、Vue.jsなど)と統合できます。
まとめると、BlazorはRazor PagesやMVCよりも優れた選択肢です。特に、より良いフロントエンド開発体験、より良いパフォーマンスとユーザーエクスペリエンス、より優れた再利用性とコンポーネント指向開発が必要なプロジェクトに適しています。ただし、どの開発モデルを選ぶかは、プロジェクトの具体的な要件と開発チームの選好に基づいて決定する必要があります。どのモデルを選んでも、プロジェクトの実情に応じて合理的な選択をし、開発プロセスでは優れた設計原則とベストプラクティスに従うことが重要です。
3. なぜまたBlazorを使うことにしたのか?
サイト管理者は昨年、サイトフロントエンドをBlazor Serverで開発したバージョンをリリースしましたが、その時は再接続の体験に関する問題から、Razor Pagesで再構築することを選びました。
今回、管理者がBlazorに回帰した転機は6月13日、.NET 8 Preview 5のリリースでした。VS2022プレビュー版にもBlazor Web Appプロジェクトテンプレートが登場し、各技術グループで話題になりました。管理者はRazor PagesにRazorコンポーネントを追加して試してみたところ、Microsoftは本当にすごい。Blazorコンポーネントがクライアントとサーバーの両方のすべてのWeb UIニーズを満たすことを目指しているのです。
しかし、現時点ではこのモードのRazorコンポーネントはインタラクションができず、ページには再接続のグレーアウトUIが表示されました。そこで、思い切ってBlazor Serverで再構築することにしました。数日間の奮闘の末、サイトフロントエンドはBlazor ServerでRazor Pagesを完全に置き換え、厄介な再接続問題も解決しました。今ではサイトへのアクセスが非常に速くなり、錯覚かもしれませんが、個人的にはとても良い感触です。(再接続の問題については、Microsoft Docs「ASP.NET Core BlazorSignalR ガイド」とTokenさんの記事「如何取消Blazor Server烦人的重新连接?」を参照してください。)
Razor Pages(MVC)とBlazorはどちらもRazor構文を使用しているため、理論上の切り替えはシームレスで、コアコードの変更はほとんどありません。プロジェクトコードのファイル構造の比較は以下のスクリーンショットを参照してください。詳細は省略しますが、興味があればソースコードをご覧ください。両方のバージョンのコードが含まれています。
| Razor Pages版のプロジェクト構造 | Blazor Server版のプロジェクト構造 |
![]() |
![]() |
4. Blazorのインタラクションの便利さ:いくつかのオンラインツール
ページのイベント処理に関しては、Blazorを使うと便利です。以下は昨夜追加した4つの小さなツールです:

興味のある方はこちらから体験してください:https://dotnet9.com/tools。 4つのツールのコードを直接掲載します。Blazorのコードスタイルを気に入っていただけるかもしれません。
4.1. JSONフォーマッター
アクセスURL:https://dotnet9.com/tools/jsonformatter

ページコード:
@page "/tools/jsonformatter"
@using System.Text.Json
<PageTitle>@_title</PageTitle>
<MApp>
<h2 style="margin-bottom: 30px; margin-top: 10px; text-align: center;">@_title</h2>
<div>
<MTextarea BackgroundColor="grey lighten-2" Solo
Color="orange orange-darken-4" TValue="string" @bind-Value="_inputJson"
Label="入力JSON" Rows="8" style="font-size:12px;" RowHeight="15" AutoGrow/>
</div>
<div>
<MButton Color="success" class="ma-2" OnClick="() => FormatJson(true)">フォーマット</MButton>
<MButton Color="lime" OnClick="() => FormatJson(false)">圧縮</MButton>
</div>
<div>
<MTextarea BackgroundColor="amber lighten-4" Solo
Color="orange orange-darken-4" TValue="string" @bind-Value="_formattedJson"
Label="フォーマットまたは圧縮後のJSON" Rows="8" style="font-size:12px;" RowHeight="15" AutoGrow/>
</div>
</MApp>
@code
{
private const string? _title = "ツールボックス-JSONフォーマッター";
private string? _inputJson;
private string? _formattedJson;
private void FormatJson(bool writeIndented)
{
try
{
var jsonObject = JsonDocument.Parse(_inputJson).RootElement;
_formattedJson = JsonSerializer.Serialize(jsonObject, new JsonSerializerOptions { WriteIndented = writeIndented });
}
catch (JsonException)
{
_formattedJson = "無効なJSON形式";
}
}
}
4.2. オンライン文字列エンコーダーツール
アクセスURL:https://dotnet9.com/tools/string-encoder

ページコード:
@page "/tools/string-encoder"
<PageTitle>@Title</PageTitle>
<MApp>
<h2 style="margin-bottom: 30px; margin-top: 10px; text-align: center;">@Title</h2>
<p>
<MTextarea BackgroundColor="grey lighten-2"
Color="cyan" Solo TValue="string" @bind-Value="_inputString"
Label="入力文字列"/>
</p>
<p>
<MTextarea BackgroundColor="amber lighten-4" Solo
Color="orange orange-darken-4" TValue="string" @bind-Value="_encodedOrDecodeString"
Label="エンコード/デコード結果"/>
</p>
<p>
<MButton OnClick="@Encode">エンコード</MButton>
<MButton OnClick="@Decode">デコード</MButton>
<MButton OnClick="@Clear">クリア</MButton>
</p>
</MApp>
@code {
private const string Title = "ツールボックス-オンライン文字列エンコーダーツール";
private string? _inputString;
private string? _encodedOrDecodeString;
private void Encode()
{
_encodedOrDecodeString = System.Web.HttpUtility.UrlEncode(_inputString);
}
private void Decode()
{
_encodedOrDecodeString = System.Web.HttpUtility.UrlDecode(_inputString);
}
private void Clear()
{
_inputString = string.Empty;
_encodedOrDecodeString = string.Empty;
}
}
4.3. カウントダウン
アクセスURL:https://dotnet9.com/tools/countdown

ページコード:
@page "/tools/countdown"
<PageTitle>@Title</PageTitle>
<MApp>
<h2 style="margin-bottom: 30px; margin-top: 10px; text-align: center;">@Title</h2>
<p>
<MTextField Label="持続時間(秒)" Type="number" TValue="int" @bind-Value="@_duration"/>
</p>
<p>
<MButton Color="success" class="ma-2" OnClick="@StartCountdown" Disabled="@_isCountingDown">開始</MButton>
<MButton Color="pink" class="ma-2 white--text" OnClick="@PauseCountdown" Disabled="!_isCountingDown">一時停止</MButton>
<MButton Color="deep-orange" class="ma-2 white--text" OnClick="@ResetCountdown" Disabled="!_isCountingDown">リセット</MButton>
残り時間(秒):@_remainingTime
</p>
<div class="text-center">
<MProgressCircular Value="@_remainingTimePercent" Size="100" Width="15" Rotate="360" Color="teal">@_remainingTime</MProgressCircular>
</div>
</MApp>
@code {
private const string Title = "ツールボックス-カウントダウン";
private int _duration = 20;
private int _remainingTime;
private int _remainingTimePercent;
private bool _isCountingDown;
private bool _isPause;
private CancellationTokenSource? _countdownTokenSource;
private async Task StartCountdown()
{
if (_duration < 0)
{
_duration = 10;
}
if (_isCountingDown)
{
return;
}
_isCountingDown = true;
if (!_isPause || _remainingTime <= 0)
{
_remainingTime = _duration;
ChangeRemainingTimePercent();
}
_countdownTokenSource = new CancellationTokenSource();
await Countdown(_countdownTokenSource.Token);
}
private void PauseCountdown()
{
if (!_isCountingDown)
{
return;
}
_isCountingDown = false;
_isPause = true;
_countdownTokenSource?.Cancel();
}
private async void ResetCountdown()
{
_isPause = false;
if (_isCountingDown && _countdownTokenSource != null)
{
await _countdownTokenSource.CancelAsync();
}
_remainingTime = _duration;
_isCountingDown = false;
ChangeRemainingTimePercent();
}
private async Task Countdown(CancellationToken cancellationToken)
{
while (_remainingTime > 0)
{
await Task.Delay(1000, cancellationToken);
_remainingTime--;
ChangeRemainingTimePercent();
if (cancellationToken.IsCancellationRequested)
{
return;
}
}
_isCountingDown = false;
}
private async void ChangeRemainingTimePercent()
{
_remainingTimePercent = (int)(_remainingTime * 100.0 / _duration);
await InvokeAsync(StateHasChanged);
}
}
4.4. タイムスタンプ変換
アクセスURL:https://dotnet9.com/tools/timestamp
サイト管理者が以前記事を書いています。こちらをご覧ください:使用Blazor做个简单的时间戳在线转换工具。
5. まとめ
サイトにはバグが存在する可能性があります。いや、必ずバグがあります。サイト管理者はこれからも再構築と反復を続けていきます。
サイトフロントエンドを再構築した喜びを皆さんと共有できて嬉しいです。端午節(端午の節句)をお元気でお過ごしください。
- サイトURL:https://dotnet9.com/
- サイトソースコード:https://github.com/dotnet9/Dotnet9
- .NETバージョン: .NET 8.0.0-preview.5.23280.8

