はつねの日記

Kinect, Windows 10 UWP, Windows Azure, IoT, 電子工作

たかが子爵嫡男に高貴な人たちがグイグイきて困る@COMIC

Noble people are coming on to a mere Viscount Heir to the throne and it's troubling @COMIC

I would like to introduce a comic adaptation of a novel about a different world (Isekai Tensei or Isekai Tani) that has not yet been made into an anime (as of the time of the blog post).

The term "Isekai Tensei" here refers to cases in which the main character died in Japan and was born as a child in another world, or in a body born as a child in which the memories of the time when he/she lived in Japan were revived. There are cases in which a so-called god intervenes and bestows a benefit (cheat), and there are also cases in which the current knowledge itself is a cheat. Therefore, the original status in another world is a characteristic of Isekai Tensei.

"Isekai Teni" refers to cases where a person is transferred from Japan to another world. In this case, there is no otherworldly status, and the name is usually the same as before birth.

Another world transfer" is when a person is transferred from Japan to another world. In this case, there is no otherworldly status, and the name is usually the same as before birth (?). In this case, the person has no otherworldly status, and his/her name is often the same as his/her name before birth (?).

The following is an example.
amzn.to

The main character is a mob character, not a reincarnated person.
The main character is a mob character and not a reincarnated person.
This is a work in which the protagonist leads a quiet student life, unaware of the existence of otherworldly reincarnationists who dream of a successful route because they know the game scenario, which is a typical game world reincarnation scenario.

たかが子爵嫡男に高貴な人たちがグイグイきて困る@COMIC

異世界もの(異世界転生や異世界転移)のラノベをコミカライズしたもので、(blog投稿時点で)まだアニメ化されていないものを紹介していきたいと思います。

ここでいう「異世界転生」とは、日本で死んだ主人公が異世界で子供として生まれて、もしくは、子供として生まれた体に、日本で生活していたころの記憶がよみがえったケースを指します。いわゆる神様が介在して恩恵(チート)をさずける場合もあるし、現在の知識そのものがチートの場合もあります。なので異世界での身分というのがもともとあるのが異世界転生の特徴です。

また、「異世界転移」は、日本から異世界に転移させられた場合をいいます。このときは異世界の身分はなく、名前も生前(?)の名前の場合がおおいですね。

今回ご紹介するのは次の作品です。
amzn.to

典型的なゲーム世界への異世界転生ものかと思ったら、主人公はいわゆるモブキャラで異世界転生者ではありません。
では、異世界転生者はいないのかといえば、ちゃんと登場します。
異世界転生テンプレなゲームシナリオをしっているからこその成功ルートを夢見る異世界転生者の存在を知らずに、主人公がまったり学生生活をおくる、そんな作品です。

ツンデレ悪役令嬢リーゼロッテと実況の遠藤くんと解説の小林さん

Lieselotte, the tsundere villainess, Endo-kun, the play-by-play commentator, and Kobayashi-san, the commentator.

I would like to introduce a comic adaptation of a novel about a different world (Isekai Tensei or Isekai Tani) that has not yet been made into an anime (as of the time of the blog post).

The term "Isekai Tensei" here refers to cases in which the main character died in Japan and was born as a child in another world, or in a body born as a child in which the memories of the time when he/she lived in Japan were revived. There are cases in which a so-called god intervenes and bestows a benefit (cheat), and there are also cases in which the current knowledge itself is a cheat. Therefore, the original status in another world is a characteristic of Isekai Tensei.

"Isekai Teni" refers to cases where a person is transferred from Japan to another world. In this case, there is no otherworldly status, and the name is usually the same as before birth.

Another world transfer" is when a person is transferred from Japan to another world. In this case, there is no otherworldly status, and the name is usually the same as before birth (?). In this case, the person has no otherworldly status, and his/her name is often the same as his/her name before birth (?).

The following is an example.
amzn.to

In fact, it is not a story about a reincarnation into another world, but about a game player named Endo who is not a reincarnation into another world.
It's a slightly eccentric otherworldly story about game players Endo-kun and Kobayashi-san, who get involved with the characters in the game world in the form of a trust.
Anyway, you can read this work while enjoying the tsundere behavior of the main character, Lieselotte (Rizetan).

ツンデレ悪役令嬢リーゼロッテと実況の遠藤くんと解説の小林さん

異世界もの(異世界転生や異世界転移)のラノベをコミカライズしたもので、(blog投稿時点で)まだアニメ化されていないものを紹介していきたいと思います。

ここでいう「異世界転生」とは、日本で死んだ主人公が異世界で子供として生まれて、もしくは、子供として生まれた体に、日本で生活していたころの記憶がよみがえったケースを指します。いわゆる神様が介在して恩恵(チート)をさずける場合もあるし、現在の知識そのものがチートの場合もあります。なので異世界での身分というのがもともとあるのが異世界転生の特徴です。

また、「異世界転移」は、日本から異世界に転移させられた場合をいいます。このときは異世界の身分はなく、名前も生前(?)の名前の場合がおおいですね。

今回ご紹介するのは次の作品です。

amzn.to

実は、異世界転生で異世界転移でもなくて(おい!!)、ゲームプレイヤーである遠藤くんと小林さんがゲーム世界の登場人物たちに信託という形でかかわっていくちょっと風変わりな異世界ものです。
とにかく、主人公のリーゼロッテ(りぜたん)のツンデレぶりを「うんうん」と楽しみながら読める作品です。

.NET Frameworkから.NET 6への移植は別ソリューションで!

.NET Frameworkで作成していたWPFアプリを.NET 6化しています。
.NET 6用の空のプロジェクトを.NET Frameworkのプロジェクトファイルのあるフォルダに新規に作成して、あとは、プロジェクトに既存のソースコードを追加してビルドが通れば、.NET 6化が完了します。

もちろん、動作時の一部非互換もありますので、ビルドしただけじゃなくて、そのあとにいわゆるシステムテスト的なテストで動作が変わっていないかの検証は必要です。
例えば有名なところだと、.NET 5以降についてはNLSじゃなくてICUが使われるようになった点などがあります。文字列のソートなどでカルチャー指定していないコードだとちょっと注意して動作を確認したほうがいいかもしれません。
グローバリゼーションと ICU | Microsoft Docs

ただし、ほぼ、非互換はないのでいくつかの注意点はありますが、プロジェクトファイルを.NET Framework版と.NET 6版に分けておけば、同じソースコードでそれぞれのビルドが通るようにできますので、移行期間のようなときも別々のソースコードを書いてなどは大筋では不要です。
それでも.NET 6のときのみに必要なコードなどが書きたくなったら

#if NETCOREAPP
#endif

のように「NETCOREAPP」のときのみを指定してあげれば実現できます。

### 問題点
こんな感じですごく順調に移行ができていたのですが、.NET Frameworkのプロジェクトファイルと.NET 6のプロジェクトファイルを同一ソリューションにいれてあげたときに問題が発生しました。
別々のソリューションだったときには問題なかったのですが、同一ソリューションにしてあげるとobjフォルダの中に自動生成される「project.assets.json」ファイルの内容がビルドするプロジェクトに応じた内容に変更されず、後からビルドした方のプロジェクトでビルドエラーが発生するようになるのです。
理由としては、project.assets.jsonの中のtargesに動作フレームワークごとにnugetするバージョンなどが記載されるのですが、これが.NET Frameworkのみか.NET 6のみかのどちらかだけしか生成されず両方を指定したものにならないために、すでにproject.assets.jsonが存在した状態でビルドが正しく行えなくなっているのです。

### 解決方法
現状の解決方法は、ソリューションを分けることです。
project.assets.jsonのtargetに手動で両方とも書いてあげても解決するとは思いますが、なにせ自動生成されるファイルなので、書き換えを防止できないことを考えるとお勧めできません。

「クライアントサイドBlazor」改め「Blazor WebAssembly」を試してみる

以前は「Client-Side Blazor」と呼ばれていた技術が「Blazor WebAssembly」と呼び方が変わっていました。
https://docs.microsoft.com/ja-jp/aspnet/core/blazor/hosting-models?view=aspnetcore-6.0#blazor-webassembly

Blazor WebAssemblyを使えば、WebサーバーなしでWebブラウザ上でBlazorアプリを動作することができます。
f:id:hatsune_a:20220316134740p:plain
そしてなんといっても「C#」で作成できる点です。

Blazorとは

ここで「Blazor」という言葉を初めて聞いた人向けに、ちょっとだけBlazorとはなに?というお話をしたいと思います。
Blazorは、.NET環境で使用することができるWebブラウザ上で実行可能なアプリを開発するためのフレームワークです。
Blazorで利用する主な言語は「C#」となります。
Blazor Server(ASP.NET Core Blazor)を採用すれば、サーバーサイドも(従来はJavaScriptで記述していたような)クライアントサイドもC#で記述することができます。

2つのBlazor WebAssembly

Blazor WebAssemblyには、次の2つの種類があります。

  1. 単体で動作する「Standalone Blazor WebAssembly」
  2. バックエンドのASP.NET Coreと協調して動作する「Hosted Blazor WebAssembly」

Hosted Blazor WebAssemblyの方がBlazor Serverで動作しているBlazorアプリと同じことができるフル機能を有しています。

フル機能なので想像はしやすいと思いますが、どうせだったらバックエンドとかを用意しなくてもいい完全スタンドアロンなStandalone Blazor WebAssemblyについて、もう少し見ていきたいと思います。
なぜ、こっちを中心にかといえば、最終的な目的は、Blazor WebAssemblyでChrome拡張を作ってみたいというゴールがあるからです。そのときに、ASP.NET Coreなどのクラウド環境を別途用意しなくても動作する形にしてみたいからですね。

Visual Studioで新規プロジェクトを作成する

Visual Studio 2022を起動して[新しいプロジェクトの作成]画面で「Blazor WebAssemblyアプリ」のテンプレートを選択します。
f:id:hatsune_a:20220316140827p:plain
なお、このテンプレートは、Visual Studioのインストール時に「ASP.NETとWeb開発」のワークロードのインストールを行っていないと表示されません。
クライアントアプリしか作らないわーと(比較的大きい)「ASP.NETとWeb開発」のワークロードを行っていなかったときは、良い機会なのでサクッといれてしまいましょう。
f:id:hatsune_a:20220316141126p:plain

プロジェクト名を指定する

f:id:hatsune_a:20220316141308p:plain

追加情報を指定する

追加情報では次のように指定しました。
f:id:hatsune_a:20220316141519p:plain
[ASP.NET Coreでホストされた]チェックボックスにチェックすると「Hosted Blazor WebAssembly」になるので、今回のStandaloneではかならずチェックを外したままにしておきます。

新規プロジェクトの初期状態を確認する

初期状態では次のようなソリューション構成になっています。
f:id:hatsune_a:20220316141900p:plain

初期状態でデバッグ実行してみる

まずはこのままF5でデバッグ実行してみましょう。

証明書を信頼する/しない

するとhttpsを使うとしてプロジェクトをつくったので証明書を信頼するかのダイアログが表示されます。
f:id:hatsune_a:20220316142113p:plain
「はい」でも「いいえ」でもどちらでもよいのでクリックして先に進みます。今回は「いいえ」で進んでみましょう。

初期表示を確認する

Visual Studioの良いところは、テンプレートから作成した新規プロジェクトをそのまま起動しても、ある程度形になったアプリとして動いてくれるところですね。1行も書いてなくても下記のようなStandalone Blazor WebAssemblyアプリが動きます。
f:id:hatsune_a:20220316142805p:plain

テンプレートから作成したアプリの構成を確認する

Blazor WebAssemblyアプリの画面は、プロジェクトの中のPagesフォルダに入っています。
テンプレートから作成した場合は「index.razor」「Counter.razor」「FetchData.razor」の3つの画面が作成されます。

この他に画面共通部品としてSharedフォルダに「MainLayout.razor」「NavMenu.razor」「SurveyPrompt.razor」があります。

index.razor

ホーム画面であるindex.razorの内容は非常にシンプルです。
f:id:hatsune_a:20220316145808p:plain

この定義にSharedフォルダの共通部品を組み合わせると下記のような表示になります。
f:id:hatsune_a:20220316142805p:plain

Counter.razor

画面上のボタンをクリックすると数値がカウントアップしていく画面です。
f:id:hatsune_a:20220316151946p:plain

こちらも定義はシンプルです。
f:id:hatsune_a:20220316151417p:plain
ここで注目してほしいのは、@codeで囲まれた部分(画面ハードコピーでは判定している部分)です。
すごくC#っぽいコードですねというか、いわゆるcsファイルに書くようなC#のコードそのものです。
その直前の@onclickでC#のIncrementCountを呼び出しているのがUI部分からのイベント呼び出し部分ですね。

この表示にhtmlはどうなっているかといえば、これまたシンプル
f:id:hatsune_a:20220316160123p:plain
ロジックコードなどはhtmlなどからは隠ぺいされていて、ブラウザでコードが見られるし書き換えられて実行されるというような心配もありません。
これこそがBlazorですね!

FetchData.razor

3つめの画面は他の2つに比べるとちょっと複雑です。まずは実行結果を見てみましょう。
f:id:hatsune_a:20220316155355p:plain
このように一覧表が表示されますが、表の中の値は直接FetchData.razorには書かれていません。
f:id:hatsune_a:20220316154320p:plain

OnInitializedAsncメソッドは自動的に呼び出されてforecasts変数に表示データを格納しています。

html部分では、forecasts変数がnull以外になったら、else節にあるテーブル表示に移行します。
forecasts変数の状態をポーリングするとかも書かなくていいのがすごいですね。
そして、tbodyのところではC#なforeach構文を使ってデータを1行づつ表示しています。

まとめ

  1. Blazor WebAssemblyはC#でクライアントサイドが書ける優れもの
  2. WebAPIの呼び出しなどもできそう
  3. 画面定義はRazor構文でわかりやすい

.NET 6からWindows Runtime APIを呼ぶのが劇的に楽な件

## .NET 6以前
Windows 10の固有APIにアクセスする方法としては、Windows Runtime API (WinRT API) があります。
Windows Runtime APIはUWPアプリからはすごく使いやすかったのですが、.NET Frameworkから使おうとすると参照設定をしたり、デスクトップブリッジを使ったりと、ひと手間といわず数手間かかるような感じした。

## .NET 6以降
正確には、.NET 5でも同様のようですが、.NET 6では、Windows Runtime APIを使うための準備をほぼ意識しないレベルになっています。

### 準備
f:id:hatsune_a:20220125165818p:plain
Visual Studioでプロジェクトのプロパティで「ターゲットOS」を指定するところでWindows 10のバージョンを指定します。この指定によってcsprojファイルには次のようにWindows 10のランタイムバージョンが指定されます。
f:id:hatsune_a:20220125170057p:plain

### 使い方(コード編)
f:id:hatsune_a:20220125190835p:plain
普通に「Windows.」で始まる名前空間Windows Runtime APIのクラスが使えますね。

### 使い方(xaml編)
f:id:hatsune_a:20220125191342p:plain
Windows.UI.Xaml名前空間がないようです。
これは、Windows App SDK(旧名称は WinUI 3)に含まれているので、nugetでMicrosoft.WindowsAppSDKを追加すれば使えるようになるはずです。
どうして「はず」なのかといえば、確認するために使った.NET 6なWPFアプリがx86/x64/ARM/ARM64対応のものだったので、Windows App SDKがARMに対応していないというビルドエラーがでて動作確認までに至らなかったからです。
また、時間を見つけて確認してみたいと思います。

なにはともあれ、すごく楽にWindows Runtime APIが使えるようになったので、例えば、Bluetooth関連だとか、カメラデバイス一覧だとかは簡単に取得できますね。

Azure Speech to Textにコミットメントレベル料金プランが登場

docs.microsoft.com

### コミットメントプランとは
コミットメント料金プランって、聞きなれないプラン名ですが、要するに利用時間にかかわらず毎月定額払いの料金プランです。
かといって定額使いたい放題ではなく、定額費用に応じて利用できる時間数がきまっています。

### コミットメントプランの利用時間上限と月額固定費用
Speech to Textの場合、
2,000時間|$1,600
10,000時間|$6,500
50,000時間|$25,000
という金額になります。

### 上限時間を超えたなら
では、上限時間を超えたらどうなるかといえば、コミットメントプランの時間単価での従量課金に移行します。
2,000時間|2,001時間以降は、$0.80/時間
10,000時間|10,001時間以降は、$0.65/時間
50,000時間|50,001時間以降は、$0.50/時間
ある意味安心な料金プランですね。

### Standardな従量課金プランよりお得
Standardプランだと1時間1$なのだいぶお安くなりますね。月何時間使うのかがみえてきたらコミットメントプランへの移行も検討してみるとコストが抑えられるかも。