nuits.jp blog

C#, Xamarin, WPFを中心に書いています。Microsoft MVP for Development Technologies。

Visual Studio 2019で始める「WPF on .NET Core 3.0」開発 というタイトルで登壇してきました

「Visual Studio 2019 Launch Event in Tokyo.」で、Visual Studio 2019で始める「WPF on .NET Core 3.0」開発 というタイトルで登壇してきました。 資料はこちら

www.slideshare.net

今回はコードの公開ができないので、部分的にですが資料とその解説をこちらにアップしておきます。もしよかったらご覧ください。

f:id:nuitsjp:20190421155017j:plain

本セッションでは、主に次の二つについてお話ししました。

まず初めに、そもそもデスクトップアプリをなぜ.NET Coreで実装するのか?したいのか? そのモチベーションについて再確認したいと思います。

その後、実際に.NET Frameworkで作られたWPFのアプリケーションを.NET Coreに移行しつつ移行の「感覚」をとらえて貰えたらと思います。

「感覚」と表現したのは意図があります。

移行の詳細をもれなく理解するには公式のドキュメントを読んでいただくのが最良でしょう。

本セッションではモチベーションから具体的な計画につながるそのハザマの「現実的な感覚」を理解してもらいたいと思っています。

f:id:nuitsjp:20190421155158j:plain

デスクトップアプリケーションを.NET Coreで開発したい、その本質的な理由はどこにあるのか?まずそこからお話ししたいと思います。

私は主に次の3点から、Coreを利用したいと考えています。

  1. まず第一に、.NET Core 3.0から、WPFやWinFormsがサポートされたということ。
  2. つぎに、すでに開発の中心が.NET Frameworkから.NET Coreにシフトしているということ
  3. 最後に.NET Coreが非常に魅力的な特徴を持っているということ

この3点です。

2番以降をもう少し掘り下げましょう。

f:id:nuitsjp:20190421155356j:plain

ご存知の方も多いかと思いますが、.NETの開発の中心は.NET FrameworkからCoreが中心にシフトしています。.NET Frameworkへのポーティングされているそうですが、後方互換性を重視して行われています。したがって、最先端の技術はCoreでだけ利用できるということが実際に起こり始めています。

Announcing .NET Standard 2.1 | .NET Blog

実際、つい先日リリースされた.NET Framework4.8は.NET Standard 2.0までのサポートですが、近くリリースされる.NET Coreは.NET Standard2.1までのサポートになります。

またクラウドファーストが推進されている現在、クラウドでの利用は.NET Core一択だという現実もあります。

f:id:nuitsjp:20190421155506j:plain

私が特に魅力を感じるところは、次の3点にあります。

  1. ひとつはSide by Sideが復活し、異なるバージョンを共存して利用できるということ
  2. 二つ目はRuntimeを事前にインストールしておかなくても、アプリに含めて配布できるということ
  3. そして軽快な動作速度を含む、先進的な機能の採用

です。

特に1. 2. は他社アプリケーションとの競合でFrameworkがあげられないという話がよくあるので、個人的にはものすごく期待しています。

技術的な投資を効率化する上で、Frameworkに絞って投資する意味はあまりなく、Coreに集中したいというのが私の本音です。

f:id:nuitsjp:20190421155632j:plain

とはいえ、.NET Coreってクロスプラットフォーム用でしょ?WPF動かすなんて現実的にどうなの?という疑問はあるかと思います。

と、ここからはライブマイグレーションと交互に進めたため、文章だけでは内容が飛び飛びになることをご了承ください。

f:id:nuitsjp:20190421155928j:plain

さて、実際にマイグレーションを行うにあたり、ひとつ注意していただきたい点があります。

f:id:nuitsjp:20190421160002j:plain

このマイグレーションはあくまで移行における「感覚」を理解していただくことを主眼においています。

実際に移行する際には、こちらの公式のドキュメントを参照して進めてください。

f:id:nuitsjp:20190421162653j:plain

さて、マイグレーション対象のアプリケーションは実際に弊社で開発している業務アプリでかれこれ8年くらい熟成された全体としてはそこそこ大きなアプリの一部です。

アプリは(弊社的に).NET Framework 4.5.2という最新のフレームワークで開発されており、比較的大きな.NET Framework製のサードパーティライブラリを利用しています。

また、トラブりそうな要素として静的コード生成を利用したDLLの書き換えや、COM経由でのスキャナードライバの呼び出し、System.Drawing.Bitmapに代表されるようなWindowsに強く依存するコードが含まれています。

実際に移行デモをするのにそこそこ良い題材だと思います。

f:id:nuitsjp:20190421162909j:plain

というわけで、移行における一つ目のポイントです。

.NET Frameworkでは標準で参照できたパッケージが.NET Coreでは標準では参照できない可能性があります。次のいずれかで、概ね解消できます。

とはいえ、無いものもあります。

f:id:nuitsjp:20190421163241j:plain

.NET Coreには.NET Frameworkにはあったけど、正式に対応しないことが明言されているものが存在します。AppDomainや.NET Remotingなどで、詳細はこちらのリンクに記載があります。

このため、そういったものを利用している場合、自分のコードであれば.NET Portability Analyzerでチェックして別の実現手段によって解決する必要があります。

またサードパーティライブラリの場合は.NET Coreもしくは.NET Standard対応のライブラリに移行していただく必要があります。

ところで.NET Core可したプロジェクトから.NET Frameworkのプロジェクトへ参照が設定できて、ビルドもできてしまいます。クロスプラットフォームプロジェクトから、プラットフォーム依存のコードが参照できては拙いのでは?という疑問が当然生まれますよね?

このことは、私的にはXamarinの例をとって考えると非常にわかりやすいです。

f:id:nuitsjp:20190421163606j:plain

Xamarinでは共通コードは.NET Standardで記載します。

.NET Standardで実装された共通のUIライブラリは、.NET Standardで実装されたクラスライブラリを利用しているとします。そのクラスの中でファイルIOを実装していたとしましょう。

そうした場合、実際にはどのように動作するでしょうか?例えばAndroidの場合は左のようになります。

ビルド時には.NET StandardのFileクラスを参照してビルドしていましたが、実行時にはMono.Androidで実装されたFileクラスが呼び出されます。そしてその中では、Androidのネイティブであるjava.io.Fileが呼び出されることによってファイル操作が実現されます。

iOSであっても同様です。

これは一般的に「Bait and Switch」と呼ばれる手法です。

元々は「おとり商法」の意味で、例えば不動産屋なんかで、ネットで有料広告を売っておいて店頭に言ったら

「いやお客さんその物件さっき契約されちゃいまして。ちょっと高いですけどこんな物件どうですか?」

といった最初から存在しないBaitつまり餌でつっておいて、Switchここでは小枝でむち打ちという意味だそうですが、Switchすることが語源だそうです。

.NET StandardのFileというBaitで釣っておいて、ビルドしておいて、実行時は各プラットフォームにSwitchするわけです。この場合別に鞭打たれていませんけどね。

f:id:nuitsjp:20190421163756j:plain

では.NET FrrameworkとCoreに置き換えて考えてみましょう。

最初、すべてのモジュールは.NET Frameworkでビルドされていました。

そしてアプリケーションを.NET Coreに置き換えました。しかしライブラリは依然Frameworkのままです。したがってライブラリが参照するのもFrameworkのFileクラスです。

これを実行するランタイムはWindows用のCoreランタイムです。従って実行時のFileクラスは.NET CoreのWindows用のランタイムになります。

実行環境がLinuxならランタイムもFileクラスもLinux用のものになります。

つまりここでBait and Switchが発生しているわけです。

f:id:nuitsjp:20190421164006j:plain

この状況で動作する特に重要なポイントは次の二つです。

  • ひとつは、中間言語は共通仕様であってFrameworkでもCoreでも変わりない事
  • そして別にWPFとは関係なく、もともと.NETからネイティブのAPIを呼び出す仕組みは.NET Frameworkにも.NET Coreにも備わっているからになります。

従って、条件を満たせば実のところ.NET Framework向けにビルドされたモジュールは.NET Coreでも動作します。そしてこの前提があったからこそ、.NET CoreにWPFやWinFormsが比較的簡単に、そして安全に移行できているのだと思います。多分。

f:id:nuitsjp:20190421164038j:plain

ただもちろん注意は必要です。この二つのFileクラスは完全に別物になります。

例えばライブラリから利用しているメソッドが、Frameworkには存在しても、Coreには存在しないということは起こりえます。

この場合、ビルドは通って実行時エラーになります。

f:id:nuitsjp:20190421164132j:plain

というわけで三つ目のポイントです。

まずFrameworkでビルドされたモジュールも、Core環境で動作する可能性があります。

ただし、直接・間接的に.NET Coreでサポートされていない物に依存している可能性があります。

既にFrameworkビルド済みのサードパーティライブラリが、Coreで動作するかどうかは、.NET Portability Analyzerでは分からないと思います。多分。また一時的に動作しても、内部分岐次第では、非常に低い確率で突如実行時エラーになるということがあり得ます。

このため、特別な理由があってFrameworkのライブラリを利用せざるを得ず、かつ利用しても問題がないという何らかの確証がないかぎり、基本的には.NET CoreやStandard対応のライブラリを利用したほうが安全だと思います。

f:id:nuitsjp:20190421164253j:plain

というわけで、一通り動作が確認できました。

今回、上のような技術要素について、不安視していましたが実際には問題なく動作してしまいました。個人的には静的コード生成はFramework 4.5.2を対象にしていたことから、エラーになるつもりだったのですが、思った以上に素直に移行できてしまい驚いています。

f:id:nuitsjp:20190421164410j:plain

さて、最後にまとめましょう。

f:id:nuitsjp:20190421164432j:plain

  • .NET CoreがWPFをサポートすることは、少なくとも私にとっては非常に魅力的です。
  • また移行自体は、もちろんなんでも移行できるわけではありませんが、条件が整えば比較的簡単に移行できそうです。 特にASP.NETからASP.NET MVCへのツール(ありましたよね?)での移行などとは違い、フレームワーク自体は基本的に変更がないため、ツールが信用できるかどうかを心配したり、ツールで移行した後の構成管理で悩む必要がないのが大きなメリットです。
  • 移行する際には、すでに公式のドキュメントが用意されていますので、まずはそちらを確認しましょう。
  • 公式ドキュメントにも、Frameworkのライブラリが利用できる旨記述がありますがやはり危険なケースもありますから、可能であればCoreもしくはStandardに統一したほうがよいのではと私は考えています。

以上です。なにか疑問があれば気軽にTwitterにでもお問い合わせください。