.NET MAUI Blazor App - モバイル、デスクトップ、Web ハイブリッドアプリを開発

##既存の Web 開発コードとスキルでクロスプラットフォームネイティブクライアントを簡単に作る
皆様、こんにちは！
Elastic テクニカルプロダクトマーケティングマネージャー/エバンジェリストの鈴木章太郎です。
[.NET 6 Advent Calendar](https://qiita.com/advent-calendar/2021/microsoft) 12/11分です。
本稿では、何を書こうか悩んだ末、シンプルな内容ですが Preview でもある MAUI Blazor について書こうと思います。これ、.NET Conf 2021 でも紹介されていましたよね？既存の Web 開発コードとスキルを使ってクロスプラットフォームのネイティブクライアントを簡単に作ることができます。

##.NET MAUI と Blazor
ASP.NET Core と Blazor には、.NET で最新のインタラクティブな Web アプリケーションを構築するために必要なものがすべて揃っています。しかし、時には、Web アプリケーションでできること以上のことが必要になることがあります。つまり、ネイティブなクライアントアプリを構築する必要があるわけです。
そのとき、.NET MAUI と Blazor があれば、既存の Web 開発スキルを使って、モバイルやデスクトップ向けのクロスプラットフォームのネイティブクライアントアプリを構築することができます。実際にやってみましょう。

##Visual Studio 2022 Preview（17.1.0 Preview 1.1)インストール
最初の .NET MAUI の Blazor アプリを作りましょう。Visual Studio 2022 の .NET MAUI 機能を使ってみます。MAUI 機能が有効になっていれば、問題ありません。
しかし、MAUI はプレビューですので、Visual Studio 2022 Preview（17.1.0 Preview 1.1)をインストールする必要があります。[このリンク](https://visualstudio.microsoft.com/ja/vs/preview/#download-preview)（下記のページに遷移します）からインストーラーをダウンロードしてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33599/5f2dacdf-0c88-490d-d65b-a4028ec064d5.png)
インストーラーのみダウンロードしたら、[このページ](https://docs.microsoft.com/ja-jp/dotnet/maui/get-started/installation)に従いインストールします。インストール時は **.NET によるモバイル開発**セクションを選択し **.NET MAUI(プレビュー)**にチェックを入れてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33599/edfc0c6a-3a84-10df-0493-3e4f3210661f.png)

##新しいプロジェクトの作成
それでは、新しいプロジェクトを作成して、**.NET MAUI Blazor App(Preview)** を探して選択し、新しいプロジェクトを作成しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33599/45841e26-3dac-0bca-c802-2bfbbc178820.png)
**MauiApp1**は、プロジェクトの名前としては他と被らなそうなので、このままプロジェクトを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33599/83ffaa9a-c7b4-5eb4-e142-c210aa826ece.png)
デスクトップでもモバイルでも、Windows、Mac、Mac Catalyst、iOS、Android でも動作するアプリが用意されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33599/12caf38b-e573-3471-c8d2-c4754f30ba35.png)

##Android 用のアプリの実行
それでは、Android で実行してみましょう。1分ほどで起動します。
※　Android Emulator をまだダウンロード、インストールしていない場合は、"[初めての .NET MAUI アプリを作成する - .NET MAUI](https://docs.microsoft.com/ja-jp/dotnet/maui/get-started/first-app)" を参考にセットアップしてください。Android で初めての .NET MAUI アプリを作成して実行する方法について説明されています。

ここでは、通常の Blazor アプリがネイティブとして動作しているように見えます。Android アプリです。Android エミュレータで実行すると、通常の Blazor テンプレートの機能をすべて備えているのがわかります。
Counter があり、Button でカウントアップすることができます。FetchData ページでは、簡単な天気予報が表示されます。これらはすべて、通常の Blazor コンポーネントを使って実装されています。Web UI コンポーネントを使用しています。
![スクリーンショット 2021-12-11 19.16.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33599/a6779ef6-0451-c057-587d-92a47bc16849.png)
##コードを探検
それでは、コードを見てみましょう。Blazor アプリのメインページの XAML ファイルです。コントロールが1つだけなのがわかると思います。

```Mainpage.xaml
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:b="clr-namespace:Microsoft.AspNetCore.Components.WebView.Maui;assembly=Microsoft.AspNetCore.Components.WebView.Maui"
             xmlns:local="clr-namespace:MauiApp1"
             x:Class="MauiApp1.MainPage"
             BackgroundColor="{DynamicResource PageBackgroundColor}">

    <b:BlazorWebView HostPage="wwwroot/index.html">
        <b:BlazorWebView.RootComponents>
            <b:RootComponent Selector="#app" ComponentType="{x:Type local:Main}" />
        </b:BlazorWebView.RootComponents>
    </b:BlazorWebView>

</ContentPage>
```
これは Blazor Web UI コントロールで、基本的にはブラウザに埋め込まれたコントロールです。これはBlazor コンポーネントをレンダリングするためのものです。この場合、メインのコンポーネントをレンダリングします。Main.razor です。

```Main.razor
<Router AppAssembly="@GetType().Assembly">
	<Found Context="routeData">
		<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
	</Found>
	<NotFound>
		<LayoutView Layout="@typeof(MainLayout)">
			<p>Sorry, there's nothing at this address.</p>
		</LayoutView>
	</NotFound>
</Router>
```
これは、通常の Blazor ルーターで、ここにある場所やコンポーネントページにルーティングされます。例えば、カウンターコンポーネントは全く同じです。

```Counter.razor
@page "/counter"
<h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code
	private int currentCount = 0;
	private void IncrementCount()
	{
		currentCount++;
	}
}
```
Blazor の Web アプリケーションでも、デスクトップでも同じように動作します。

##Windows 用のアプリの実行
試しに Windows で動かしてみましょう。
![スクリーンショット 2021-12-11 19.23.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33599/435a129d-f61e-b96d-36ac-5f737eb31b28.png)
これで Blazor アプリが Windows のデスクトップアプリとして動作するようになりました。
![スクリーンショット 2021-12-11 19.24.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33599/6dd813f5-1534-8e96-cd03-970a6f86dbdb.png)
すべての同じ機能がこの中で働き、適用されます。モバイルやデスクトップ、さらにはクロスプラットフォームでも、Mac Catalyst や iOS でも動作します。これは素晴らしいですね。
![スクリーンショット 2021-12-11 19.25.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33599/fe0fee21-a3a6-eab8-4d81-5bc0a3b7966f.png)
僕は、最近は、React/React Native や Flutter などを、Elastic 連携 demo アプリ開発に使用しています。ただ僕自身、Microsoft エバンジェリスト時代の最初の頃、2006年の WPF から始まり、Silverlight、UWP、Xamarin...と一貫して XAML のエバンジェリストの一人だったので、まさにこういう後継の最新テクノロジーの登場は感慨無量です。
※　もっとも、Dart / Flutter を作った一人の Tim Sneath は、もともと WPF の Engineering Team にいた人です。だから Android Studio / Dart / Flutter での実行とデバッグは割と似たエクスペリエンスではないかと(笑)

##ネイティブな UI を追加する
さて、これは .NET MAUI アプリケーションなので、ネイティブプラットフォームの機能を利用することができます。例えば、ネイティブなUI を追加することもできます。
メインページに戻りましょう。XAML です。このアプリにちょっとしたネイティブ機能を追加するために、ここにコードを追加して変更してみましょう。ネイティブのラベルが付いたグリップコントロールと、Blazor Web View Control を用意しました。

```Mainpage.xaml
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:b="clr-namespace:Microsoft.AspNetCore.Components.WebView.Maui;assembly=Microsoft.AspNetCore.Components.WebView.Maui"
             xmlns:local="clr-namespace:MauiApp1"
             x:Class="MauiApp1.MainPage"
             BackgroundColor="{DynamicResource PageBackgroundColor}">
　　<Grid RowDifinitions="Auto, *"> 
        <Label Text="This is soooo native" GridLayout.Row="0"></label>
        <b:BlazorWebView HostPage="wwwroot/index.html">
            <b:BlazorWebView.RootComponents>
                <b:RootComponent Selector="#app" ComponentType="{x:Type local:Main}" />
            </b:BlazorWebView.RootComponents>
        </b:BlazorWebView>
　　</Grid>

</ContentPage>
```
では、もう一度実行してみましょう。できました！一番上にネイティブラベルがありますね。
![スクリーンショット 2021-12-11 19.28.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33599/34b7caa3-e635-f27f-c3d4-ce802a162939.png)

##コードからネイティブプラットフォームの機能を使う
そして、コードの中でもネイティブプラットフォームの機能を使うことができます。では、index.razor に戻ってみましょう。ここにちょっとしたコードを追加してみましょう。
ボタンに OnClick Handler を追加しましょう。これにより表示したいメッセージを取得します。
後ほど、Button を作成して確認します。ここでメッセージを定義して、GetMessage( )メソッドのコードを書きます。この中に、コードを追加していきます。
このコードで実現できるのは、ネイティブのテキストエディタを開いて、そこで文字列を編集し、保存することです。これはプラットフォーム付属のテキストエディタ（メモ帳、notepad.exe）です。

```Index.razor 
@page "/"
@using System.IO

<h1>Hello, Blazor MAUI!</h1>
Welcome to your new app.
<SurveyPrompt Title="How is Blazor working for you?" />

<button @onClick="GetMessage">Edit</button>
<p>@message</p>

@code {
    string message ="Hello!";
    
    void GetMessage()
    {
        var file = Path.GetTempFileName();
        File.WriteAllText(file, "Enter Message Here");
        var p = System.Diagnostics.Process.Start("notepad", file);
        p.WaitForExit():
        message = File.ReadAllText(file);
    }
}
```
##高度なテキストエディタの完成
この実現のために Razor エディタを使います。これで準備完了です。もう一度実行してみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33599/c8c5bb47-00e4-411f-076b-cae93cf0f48d.png)
メモ帳が表示されるので、"Updated! "と入力して保存して閉じます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33599/c9ccf3c5-82a5-ecdc-3b32-3dd0a26165e5.png)
これで、メモ帳から取得したテキストが、ネイティブクライアントアプリケーションのファイルシステムに格納されました。これは単なる Web アプリケーションだけではできないことです。.NET MAUI と Blazor を組み合わせることでそれが可能になります。
既存の Web 開発コードとスキルを使って、クロスプラットフォームのネイティブクライアントを簡単に構築することができます。ぜひ、試してみてください。

ということで、それではまた！

鈴木章太郎
Elastic テクニカルプロダクトマーケティングマネージャー/エバンジェリスト