先日、当ブログの.NET Core 3.1への移行という記事を書きました。

今回はF#でブログ管理用Webアプリ開発という一連の記事で作成した管理用アプリを.NET Core 3.xに移行しました。

前回の当ブログシステムと違い、今回の対象アプリはSAFE StackというSPA作成フレームワークを使っています。言語はF#になります。

SAFE Stackについてはこの記事で簡単にご紹介しています。併せてお読み頂けるとうれしいです。

まずは情報収集から

当ブログの移行と同様、やっぱり情報収集からの開始です。

SAFE StackのQuick Startによると、対応している.NET Coreのバージョンは3.0のようです。

「えー。3.1じゃないのん? 3.1LTS版がリリースされてもう結構立つのに...。3.1対応が成されてから移行しようかしらん...」

と、思ったのですが、サーバーとして使用しているSaturnのリポジトリを覗いてみると、正式サポートは3.0のままみたいですが、UnitTestプロジェクトは3.1へ移行している模様。
ということは、3.1のランタイムで問題無く動作するのだろうと予想して、新しくプロジェクトを構築してみました。

.NET Core 3.1 SDKがインストールされている状態でQuick Startの通り、dotnet new -i SAFE.Template のコマンドでテンプレートを取得し、dotnet new SAFE コマンドで作成するのですが、管理用アプリ の時に用いた

dotnet new SAFE --layout fulma-admin --communication remoting --deploy docker

というオプションで作成します。

あとは作成されたディレクトリにあるREADME.mdファイルに従い、dotnet tool restore を実行してFAKEとpaketをインストール後、dotnet fake build -t run を実行して起動します。

初回は私のマシンではビルド時間が結構かかるせいか、ビルド中にブラウザ(Chrome)が起動してしまいエラーが表示されていますが、放っておくとビルド完了後に画面が表示されました。

dockerでasp.net core 3.1で動作することを確認

Dockerfile を修正してランタイムを3.1に変更します。

# FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-alpine
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1
COPY /deploy /
WORKDIR /Server
EXPOSE 8085
ENTRYPOINT [ "dotnet", "Server.dll" ]

あとはSAFE StackのDeploy to DockerTesting docker image locally に従い、起動テストしてみます。

やっぱり3.1のランタイムでも問題無く動作しました。

移植開始

移植元のソースはF#でブログ管理用Webアプリ開発シリーズの最後の記事で作成したものから行ないます。GitHubのこちら

で、最終的に出来上がったものはSAFE Stackのマスタ保守サンプルとして挙げてあります。

大きく変わった部分を以下に。

SQLite 関連

以前は System.Data.SQLite に依存していたのですが、System.Data.SQLite.Core に変更しました。
System.Data.SQLite はEntityFramework関連、Link To DB関連とか色々含まれているんですよね。
本サンプルではDapper経由で生のSQLでアクセスするため不要でした。

実際の変更点は paket.dependenciesファイルのgroup Serverの部分です。

Fableの変更点

F#でブログ管理用Webアプリ開発 シリーズを書いていた頃に比べて、Fableは大きく様変わりしています。

Fable2.2で既存の名前空間が整理されました。詳細についてはFableのBlogのここに記載されています。

既存ソースを取り込んだ直後のClientプロジェクトは真っ赤っ赤で少々焦りましたが、なんとか修正できました。

名前空間以外ではイベントの扱いが変わっていて、React.MouseEventのように定義されていたものから生のブラウザイベントに変更になっています。

さらにFontAwesomeのバージョンが4から5に変わって記述が若干変わっています。Fulmaの一部だったものがFable.FontAwesomeと、Fable自体で管理されるようになったみたいです。

Elmishの変更点

Elmish関連はObsoleteになった部分を警告メッセージに従って書き換えていくだけでした。
こちらはスムーズに変更できました。

Client.fsで日本語入力用に指定していたProgram.withReactUnoptimizedProgram.withReactSynchronousになりました。これも警告メッセージに出ていたのでそれほど苦労しませんでした。

Hot Module Replacementの指定の仕方が大きく変更になっていますが、Elmishのサイトに書かれている通りです。

ちょっと混乱したのはCmd.ofAsyncCmd.OfAsync.eitherになった部分で、ofAsyncのoが大文字になっていることに気づかず小一時間悩みました。

まぁ、気づいてしまえばね...。

Saturnの変更点

これはSaturnの変更点と言っていいのかわかりませんが...。

以前のソースではソリューションファイルがsrcディレクトリの下に有ったのですが、現在はルートディレクトリに配置されています。
このせいなのかわかりませんが、appsettings.jsonを読み込む位置がルートディレクトリになってました。
SaturnのApplication.fsのソースを見て、単純にカレントディレクトリで処理しようとしているっぽいなというのはわかったのですが、
気づくまで3時間以上費やしました。

配布時はdockerに指定するWorkディレクトリを参照するので、開発時だけの問題だと思います。

追記(2020/10/04)

デバッグ時はVSCodeの機能を使用する前提で、launch.jsonにカレントディレクトリとASPNETCORE_ENVIRONMENTの設定をすればいいことに気が付きました。

{
    "version": "0.2.0",
    "configurations": [

        {
            "name": "Debug Server",
            "type": "coreclr",
            "request": "launch",
            "preLaunchTask": "Build Server",
            "program": "${workspaceFolder}/src/Server/bin/Debug/netcoreapp3.0/Server.dll",
            "args": [],
            "logging": {
                "moduleLoad": false
            },
            "cwd": "${workspaceFolder}/src/Server/bin/Debug/netcoreapp3.0/",
            "env": {
                "ASPNETCORE_ENVIRONMENT": "Development"
            },
            "stopAtEntry": false,
            "console": "internalConsole",
        },
  :
  :
  :

Debug Serverの設定にcwdenvの設定を追加してます。
これでappsettings.*.jsonはsrc\Server下にのみ有れば、問題無くなります。


まとめ

マイグレーションって大変ですよね...。

今後、.NET 5 以降でまた移行作業が発生すると思うので、記事毎にリポジトリを作成するのではなく、SAFE Stackのマスタ保守サンプルという名前のリポジトリにしました。

次のマイグレーション発生時には今回の内容はブランチにして、masterを変更していくつもりです。