しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

.NET Core 3.0 Preview 7 で Go Live が付いたので WPF アプリケーションを更に対応させた

タイトルの通り .NET Core 3.0 Preview 7 がリリースされ、このバージョンから Go Live が付くようになりました。プロダクション環境で使うことが出来るようになったということです。

ちなみに GA は .NET Conf 2019 のタイミングという話です。つまり 9 月末を予定しています。

ぼちぼち .NET Core 3.0 に移行した WPF アプリのリリース準備を行おうかと思いましたが、Preview 7 ではビルドが通らなくなっていたので修正をいろいろと行いました。

移行した WPF アプリは前に手順と一緒に紹介したやつです。

ビルドエラー自体は Preview 6 ぐらいから出てたのではないかと思いますが、多少 WPF のプロジェクト周りが変わっていたので、それの対応を行う必要がありました。

'An item with the same key has already been added' エラーが出る

エラーメッセージがざっくりとしてる割に致命的なのがこのエラーでした。スタイルを定義した XAML で発生していたので、リソースを削除したり試してもダメでしたが、以下の Issue を見つけて解決出来ました。

どこかのバージョンで WPF 向け SDK の定義がアップデートされて、XAML も自動でプロジェクトに含まれるように変わったようです。

移行作業を行った時は XAML だけは csproj に追加されていたので、そのままにしていたのが原因でした。結果として同じファイルが 2 回ビルドされて、リソース名が衝突してしまったようです。

バッサリと XAML 系の定義を csproj から削除することで解消しました。

Self-contained 周りの設定を削除

16.2 まではプロパティから Self-contained 周りの設定を弄れましたが、16.3 Preview から消えていました。

f:id:shiba-yan:20190725165140p:plain

そして RuntimeIdentifier 周りのエラーが出るようになってしまったので、設定をバッサリと削除しました。

.NET Core 3.0 の WPF をターゲットしていると、自動で Self-contained App としてパッケージングしてくれるようです。Any CPU だと恐らくエラーになるのではないかと思います。

未解決:project.assets.json が見つからないエラーが出る

Windows Store 向けに x86 と x64 のパッケージを作成しようとすると、どちらかのプラットフォームで project.assets.json が見つからないというエラーが出ました。

原因は良くわかっていないですが失敗した方だけビルドしてから、もう一度両方のプラットフォーム向けにビルドするとキャッシュが残るのでビルドは通るようになりました。

ReadyToRun (R2R) を有効にする

Self-contained にするとターゲットプラットフォームがパッケージング時に確定するので、ReadyToRun を有効にすれば起動時のパフォーマンスを改善することが出来ます。

手順は Scott Hanselman のブログを読むのが手っ取り早いと思います。設定はとても簡単です。

ReadyToRun を使ったビルドは当然ながら通常よりも時間がかかります。普段なら 10-20 秒ぐらいで終わってたビルドが 5-6 分はかかっていたので、思ったより重い処理だという印象です。*1

ビルド出力ではアセンブリが R2R イメージにコンパイルされていくのが確認できます。

f:id:shiba-yan:20190725165312p:plain

ReadyToRun に対応していないアセンブリがあってもデフォルトでは警告が出ないので、確認したい場合は PublishReadyToRunShowWarnings を true にすれば全ての警告が出力されるようになります。

今回は ReadyToRun と一緒に Trimmed も有効にしておきました。

これまでの諸々対応したコードを使ってパッケージを作成すると、x86 と x64 合わせて 130MB 近くになりました。あまり Trimmed が効いていない気もしますが、WPF ならこんなものなのかも知れません。

f:id:shiba-yan:20190725170151p:plain

勿論 .NET Core 3.0 がインストールされていない PC にインストールしても、問題なく動作しました。起動パフォーマンスは改善しているように感じますが、計測したわけではないので感覚的なものです。

ASP.NET Core の場合は ReadyToRun の効果を確認することは出来ると思いますが、Self-contained のみの対応なのでランタイムがインストールされている場合でも使えるようになれば試したいですね。Docker Image の場合は Self-contained + R2R にするというのはアリだと思います。

実際に Bing は ReadyToRun 済みの Docker Image を使って起動パフォーマンスを大幅に改善したという話もあるので、ReadyToRun には割と期待しています。

おまけ : Azure Pipelines でビルドする

.NET Core 3.0 Preview 7 SDK は Azure Pipelines に入っていないので、Use .NET という怪しいタスクを使って手動でインストールする必要があります。

Runtime と違い SDK の場合は、長いバージョンを指定しないといけないので少し注意。

trigger:
- master

variables:
  buildConfiguration: Release

pool:
  vmImage: 'windows-2019'

steps:
- task: UseDotNet@2
  inputs:
    packageType: 'sdk'
    version: '3.0.100-preview7-012821'

- task: DotNetCoreCLI@2
  inputs:
    command: 'build'
    projects: '**/*.csproj'
    arguments: '-c $(buildConfiguration)'

これで .NET Core 3.0 Preview 7 を使ってビルドが行えるようになります。ASP.NET Core / WPF で同じコマンドを使ってビルドが出来るのはシンプルでよい感じです。

*1:UWP のネイティブコード生成よりも時間がかかった気がする