Blazor Server のプロジェクトに WebAPI を追加する方法

Blazor Server のプロジェクトで以下の作業を行う

  • ControllersフォルダにWeb APIコントローラーを作成
  • [Route("api/[controller]")]といったAttributeでルーティングを設定
  • HttpGetやHttpPostといったAttributeでメソッドごとにエンドポイントを指定
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
    [HttpGet]
    public IActionResult Get()
    {
        return Ok(new[]
        {
            new { Title = "First item", IsDone = false },
            new { Title = "Second item", IsDone = true },
            new { Title = "Third item", IsDone = false }
        });
    }
}
  • Program.csで以下を追加
// Add services to the container.
builder.Services.AddRazorComponents();
builder.Services.AddControllers(); // 追加
...
app.MapRazorComponents<App>();
app.MapControllers(); // 追加

app.Run();
[
    {
        "title": "First item",
        "isDone": false
    },
    {
        "title": "Second item",
        "isDone": true
    },
    {
        "title": "Third item",
        "isDone": false
    }
]

Androidに Termux をインストールして .NET8の実行環境を作る

目的

Android に Termux をインストールして .NET8 を実行できる環境を作っていきます

準備

以下の記事に Termux の導入方法が分かりやすく記載されています。 こちらを参考に Ubuntu にログインできるまで作業します。 qiita.com

Termux インストール後、sshで接続したい場合は以下の記事を参照

hone-choko.com

.NET8 インストール

# apt update
# apt upgrade -y
# apt install -y libicu72 wget vim
# wget https://download.visualstudio.microsoft.com/download/pr/43e09d57-d0f5-4c92-a75a-b16cfd1983a4/cba02bd4f7c92fb59e22a25573d5a550/dotnet-sdk-8.0.100-linux-arm64.tar.gz
# mkdir -p $HOME/dotnet
# tar zxf dotnet-sdk-8.0.100-linux-arm64.tar.gz -C $HOME/dotnet
# export PATH=$PATH:$HOME/dotnet
# echo 'export DOTNET_ROOT=$HOME/dotnet' >> ~/.bashrc

上記はAndroidでASP.NET Coreを動かす #Android - Qiita に記載されているインストール方法を元に .NET8 用に変更しました。

最後の

# echo 'export DOTNET_ROOT=$HOME/dotnet' >> ~/.bashrc

これを実行しないと dotnet コマンド実行時にエラーが発生します。

root@localhost:~# dotnet --version
GC heap initialization failed with error 0x8007000E
Failed to create CoreCLR, HRESULT: 0x8007000E

よく理解していないのですが、GCヒープの初期化でクラッシュするらしい…?

github.com

動作確認

Blazor の公式チュートリアルに沿って作成します。 dotnet.microsoft.com

# dotnet new blazor -o BlazorApp
# cd BlazorApp
# dotnet run

コンソールに http://localhost:<ポート番号> が表示されるので Android側のブラウザでアクセスすると Blazorアプリが表示されます。

Unityでスプライト画像を分割する手順

確認したUnityバージョン:2022.3.7f1(日本語を導入)

プロジェクトから対象の画像をクリックして選択する

インスペクターで以下を設定する

  • スプライトタイプ:スプライト(2DとUI)

  • スプライトモード:複数

  • Sprite Editorボタンをクリック

    • Unapplied import settingsダイアログが表示されるので Applyをクリック

スプライトエディターが表示される

  • スライスが選択されているドロップダウンをクリック

    • タイプを Grid By Cell Sizeに変更
  • ピクセルタイプの X と Y を両方26に変更

  • 右上にある 適用する ボタンをクリック

  • スプライトエディターを閉じる

画像のインスペクターに移動

  • フィルターモードを ポイント(フィルターなし)に変更
  • 右下にある 適用する ボタンをクリック

以上の手順で対象の画像の横に三角ができて分割したスプライトを確認できる

Netcode for GameObjects のチュートリアル

公式チュートリアル

docs-multiplayer.unity3d.com

前の記事で ParrelSync をインストールしたのでRPCのテストのところで ParrelSync を使ってみる。

  • まずは元のプロジェクト側でNetworkManager を選択して再生ボタンを押す。
  • するとインスペクターに「Start Host」ボタンが出てくるので押す。
  • クローンした方のエディタ側でもNetworkManager を選択して再生ボタンを押す。
  • インスペクタで Start Client を押す。
  • これでRPCのテストができるようになる。(コンソールにログが表示されることが確認できる)

UnityでNetcode for Objectsをインストールする

概要

Unityでマルチプレイヤーゲームを開発するために Netcode for Objects と ParrelSyncという開発中のゲームを複数起動できるパッケージをインストールします。

github.com

確認したUnityのバージョン

2022.3.7f11

Unityのプロジェクトを作成する

Unity Hub から作成する

Netcode for Objectsをインストールする

UnityのPackage Managerを開きます。
左側のメニューから「Netcode for Objects」を選択します。
「Install」ボタンをクリックして、Netcode for Objectsをインストールします。

ParrelSyncのインストール

サーバーとクライアントを同時に立ち上げて動作確認するためエディタをクローンして起動が可能なパッケージを追加する

・ 「Git URLからパッケージを加える」を選択します.
・入力ボックスに https://github.com/VeriorPies/ParrelSync.git?path=/ParrelSync を入力して「追加」ボタンをクリック

プロジェクトのクローン

・インストール後、プロジェクトのクローンを行う
Unityのメニューから「Window」→「ParrelSync」を選択して、ParrelSyncウィンドウを開きます。

・「Add new clone」をクリックしてクローン実行
クローン完了後、「Open in New Editor」をクリックするとUnityがもう一つ立ち上がります

あとは元プロジェクトの変更がクローンに同期される

ここまで準備ができたら、サンプルを作成するステップに進みます。

NestJS導入から gRPC対応する

Express で環境構築しようと考えてたが、 調査しているうちに NestJS なら標準で TypeScript が使えるとのことだったので NestJS でサーバーサイドを実装してみる。

nestjs.com

セットアップは簡単で公式ドキュメントの通りに

$ npm i -g @nestjs/cli
$ nest new [任意プロジェクト名]

だけでプロジェクトが作成できる。 docs.nestjs.com

あとは

$ cd [作成したプロジェクト名]
$ npm install
$ npm run start

サーバーの起動後、http://localhost:3000/ に ブラウザからアクセスすると画面で確認できる。

gRPC 対応

https://kakkoyakakko2.hatenablog.com/entry/nestjs-grpc-server 既に素晴らしい記事があって上から順に写経するだけでNestJS を利用した gRPC のサーバーを作れる。
作成したgRPCサーバーの動作確認するツールの紹介もされている。

エコーサーバーを作ってみる

gRPC-Web のサンプルプロジェクトにあるエコーサーバーを 上記で作成した gRPCサーバーに実装してみる。

protoc から TypeScript のスタブを生成する方法が紹介されているのでこれを取り入れる。 qiita.com

protoc 作成

echo.protoc

syntax = "proto3";

package grpc.gateway.testing;

message EchoRequest {
  string message = 1;
}

message EchoResponse {
  string message = 1;
  int32 message_count = 2;
}

service EchoService {
  rpc Echo(EchoRequest) returns (EchoResponse);
}

スタブ生成。

$ protoc --plugin=./node_modules/.bin/protoc-gen-ts_proto \
  --ts_proto_out=src \
  --ts_proto_opt=nestJs=true \
  --ts_proto_opt=outputClientImple=false \
  --ts_proto_opt=addGrpcMetadata=true \
  echo.proto

NestJS の CLI でコントローラー作成。

$ nest g controller echo

コントローラーの実装。

src/echo/echo.controller.ts

import { Controller } from '@nestjs/common';
import { Observable } from 'rxjs';
import { EchoRequest, EchoResponse, EchoServiceController, EchoServiceControllerMethods } from '../echo';
import { Metadata } from "@grpc/grpc-js";

@EchoServiceControllerMethods()
@Controller('echo')
export class EchoController implements EchoServiceController {
    echo(request: EchoRequest, metadata?: Metadata): EchoResponse | Promise<EchoResponse> | Observable<EchoResponse> {
        return {
            message: "Nestjs<" + request.message
        } as EchoResponse;
    }
}

main.ts を修正。

...

const app = await NestFactory.createMicroservice<GrpcOptions>(AppModule, {
transport: Transport.GRPC,
  options: {
    url: 'localhost:9090',
    package: 'grpc.gateway.testing',
    protoPath: join(__dirname, '../echo.proto'),
  },
});
await app.listen();
  
...

Envoyの設定変更&起動

gRPC-Web のサンプルプロジェクトで起動した Envoy サーバーの設定を今回作ったサーバーに転送されるようにする。

VSCode にリモート開発拡張を導入していれば envoyのコンテナに入って直接修正できる。

Docker からホストの localhost を指定できないので addressを host.docker.internal に変更する。

envoy.yaml

- endpoint:
    address:
        socket_address:
        address: host.docker.internal
        port_value: 9090

修正できたら Docker Desktop で envoyコンテナを再起動する。

動作確認

BloomRPC を導入していれば protocファイルを読み込んで 127.0.0.1:9090 を指定すると動作確認できる。

前回の記事で作成した Svelteで gRPC-Web のクライアントを使っても動作確認できる。(エコーサーバーなので同じ動作だけど)

webdevnote.hatenablog.jp

Svelte で gRPC-Web を使う

はじめに

ここで紹介するクライアントアプリは grpc-web サンプルプロジェクトのサーバーサイドアプリ、プロキシサーバーを使用するため環境構築&実行確認できているが前提となります。

grpc.io 上記の手順を上から実行すると gRPC-Web のサーバー、プロキシサーバー、JavaScript で実装したクライアントのセットアップができます。

Svelte のセットアップ

$ npm create vite@latest svelte-grpc -- --template svelte
$ cd svelte-grpc
$ npm install
$ npm run dev -- --open # ブラウザで画面が正常に表示されることを確認

protocファイルを新規作成

$ code .
Visual Studio Code が起動して現在のフォルダを開いてくれるから便利

zenn.dev 現状では TypeScript のスタブを生成することができないので
ここで紹介されている 1, 2 を実行して @protobuf-ts/plugin と @protobuf-ts/grpcweb-transport のインストールとスタブを作成する。
3 に記載されているように gRPC-Web サンプルプロジェクトにある protocファイルから必要最低限のみ使う。

syntax = "proto3";

package grpc.gateway.testing;

message EchoRequest {
  string message = 1;
}

message EchoResponse {
  string message = 1;
  int32 message_count = 2;
}

service EchoService {
  rpc Echo(EchoRequest) returns (EchoResponse);
}

App.svelte にサーバーと接続、画面表示するコードを追加する

<script>
  import svelteLogo from './assets/svelte.svg'
  import Counter from './lib/Counter.svelte'

  // 追加
  import {EchoServiceClient} from "./echo.client";
  import {GrpcWebFetchTransport} from "@protobuf-ts/grpcweb-transport";
  
  const client = new EchoServiceClient(
  new GrpcWebFetchTransport({
      baseUrl: 'http://localhost:8080'
    })
  );

  let responseMessage = "";
  client.echo({message: 'Hello gRPC-web!'}).then((value) => {
    const {response} = value;
    responseMessage = response.message;
  });
  // ここまで
</script>

<main>
  <div>
    <a href="https://vitejs.dev" target="_blank"> 
      <img src="/vite.svg" class="logo" alt="Vite Logo" />
    </a>
    <a href="https://svelte.dev" target="_blank"> 
      <img src={svelteLogo} class="logo svelte" alt="Svelte Logo" />
    </a>
  </div>
  <h1>Vite + Svelte</h1>
  <!-- 追加 -->
  <h1>{responseMessage}</h1>
  <!-- ここまで -->
  <div class="card">
    <Counter />
  </div>

  <p>
    Check out <a href="https://github.com/sveltejs/kit#readme" target="_blank">SvelteKit</a>, the official Svelte app framework powered by Vite!
  </p>

  <p class="read-the-docs">
    Click on the Vite and Svelte logos to learn more
  </p>
</main>

<style>
  .logo {
    height: 6em;
    padding: 1.5em;
    will-change: filter;
  }
  .logo:hover {
    filter: drop-shadow(0 0 2em #646cffaa);
  }
  .logo.svelte:hover {
    filter: drop-shadow(0 0 2em #ff3e00aa);
  }
  .read-the-docs {
    color: #888;
  }
</style>

gRPC-Web サンプルプロジェクトのコンテナ起動

grpc-web-node-sever と grpc-web-envoy の STATUS 項目が Running になっていることを確認します。
Docker Desktop を使用しました。

$ npm run dev -- --open # ブラウザが開きます

エコーサーバーに送信した Hello gRPC-web! が画面に表示されれば成功です。