More Related Content Similar to OptonsPatternDotNet.pptx (20) More from Takao Tetsuro (20) OptonsPatternDotNet.pptx2. .NET Core Options Patternの構築手順
App.xaml.cs
•コンストラクタ
•Options Patternを定義したコンフィ
ギュレーションサービスを構築
•Options Pattern適用済みコンフィ
ギュレーションサービスを登録
App.xaml
•StartupUriを削除
•Startupメソッドを定義
•App.xaml.cs
•MainWindowをサービス登録
•StartupメソッドでMainWindowを呼
び出す
MainWindow.xaml.cs
•コンストラクタ
•クラススコープの変数にコンフィ
ギュレーションサービスを格納
•コンフィギュレーションサービスの
言語を指定してデータコンテキスト
に設定
•サービスの設定値を利用
設定サービス登録 スタートアップ方法変更 各画面で利用
4. ASP.NET Core Options Pattern recap
xxController.cs
コンストラクタ
(サービス取
得)
(クラス・ス
コープの変数に
格納)
xxController.cs
各メソッド
(変数を利用)
JSONファイル
Program.cs
サービス登録
5. ASP.NET Core Options Pattern recap
xxController.cs
コンストラクタ
(サービス取
得)
(クラス・ス
コープの変数に
格納)
xxController.cs
各メソッド
(変数を利用)
JSONファイル
Program.cs
サービス登録
6. ASP.NET Core Options Pattern recap
xxController.cs
コンストラクタ
(サービス取
得)
(クラス・ス
コープの変数に
格納)
xxController.cs
各メソッド
(変数を利用)
JSONファイル
Program.cs
サービス登録
7. ASP.NET Core Options Pattern recap
xxController.cs
コンストラクタ
(サービス取
得)
(クラス・ス
コープの変数に
格納)
xxController.cs
各メソッド
(変数を利用)
JSONファイル
Program.cs
サービス登録
8. ASP.NET Core Options Pattern recap
xxController.cs
コンストラクタ
(サービス取
得)
(クラス・ス
コープの変数に
格納)
xxController.cs
各メソッド
(変数を利用)
JSONファイル
Program.cs
サービス登録
9. ASP.NET Core Options Pattern recap
xxController.cs
コンストラクタ
(サービス取
得)
(クラス・ス
コープの変数に
格納)
xxController.cs
各メソッド
(変数を利用)
JSONファイル
Program.cs
サービス登録
11. .NET Core Options Pattern for WPF
Program.cs
サービス登録
xxController.cs
コンストラクタ
(サービス取
得)
(クラス・ス
コープの変数に
格納)
xxController.cs
各メソッド
(変数を利用)
JSONファイル
12. .NET Core Options Pattern for WPF
Program.cs
サービス登録
xxController.cs
コンストラクタ
(サービス取
得)
(クラス・ス
コープの変数に
格納)
xxController.cs
各メソッド
(変数を利用)
JSONファイル
App.xaml.cs
コンストラクタ
(サービス構築)
(サービス登録)
MainWindow.xaml.cs
コンストラクタ
(サービス取得)
(クラス・スコープ
の変数に格納)
MainWindow.xaml.cs
各メソッド
(変数を利用)
JSONファイル
13. .NET Core Options Pattern for WPF
Program.cs
サービス登録
xxController.cs
コンストラクタ
(サービス取
得)
(クラス・ス
コープの変数に
格納)
xxController.cs
各メソッド
(変数を利用)
JSONファイル
App.xaml.cs
コンストラクタ
(サービス構築)
(サービス登録)
MainWindow.xaml.cs
コンストラクタ
(サービス取得)
(クラス・スコープ
の変数に格納)
MainWindow.xaml.cs
各メソッド
(変数を利用)
JSONファイル
25. Conclusion
Options Patternは、ASP.NET Coreでも.NET Coreでも同じように設定値のカプセル化と業務の関心ご
との分離を行う
汎用ホストはWebアプリケーション、デスクトップネイティブアプリケーションの両方で使える
.NETのOptions Patternでは構成プロバイダーとしてXMLファイル、INIファイルの選択も可能
.NETのOptions Patternでは、汎用ホストを使う際に、アプリケーション構成の設定、アプリケー
ション構成のサービス設定、画面のサービス構成を行うことで画面に階層化された設計値を送り込
むことができる
汎用ホストはDependency Injectionを使って、アプリケーションホストのサービス構成をカスタマ
イズすることができる
汎用ホストのサービスコレクションは構成サービスを定義する際にTOptions型を指定できるので、
自作の任意のクラスを使った構成ファイルの階層設計が可能(汎用ホストのDI拡張メソッドが自作
クラスをIOptionでラップしてくれる)
利用側(MainWindow)のコンストラクタでは、構成ファイルのセクションごとに自作クラスに
マップしてくれるので、業務の関心ごとで分離されたセクションは、他のセクションに影響なしに
変更を加えることができる
利用側で自作クラスにマップするセクションを選べるので、UI側で設定値の変更を動的に反映しや
27. Reference
Microsoft Docs: .NET での依存関係の挿入 - サービス登録メソッド
https://docs.microsoft.com/ja-jp/dotnet/core/extensions/dependency-injection#service-registration-methods
Microsoft Docs: ASP.NET Core での依存関係の挿入- 有効期間と登録のオプション
https://docs.microsoft.com/ja-jp/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-6.0#lifetime-and-registration-options
Microsoft Docs: .NET の構成プロバイダー
https://docs.microsoft.com/ja-jp/dotnet/core/extensions/configuration-providers
Editor's Notes Options Patternは階層的な設定値構造を構築できます。前回のASP .NET Core Options Patternでは、ホストビルダーで設定値を登録してUI層で利用していましたが、WPFの場合はApp.xamlでの起動のカスタマイズになりますので、App.xamlがMainWindow.xamlを呼び出すより前でASP .NET Core Options Patternのホストビルダーの時と同じように、コンフィギュレーションにOptions Patternを適用する作業を行う必要があります。 ホストビルダーで構築する汎用ホストはWebアプリケーションにもデスクトップネイティブアプリケーションにも使えますので、App.xaml.csのコンストラクタで汎用ホストにOptions Patternを適用したコンフィギュレーションをサービス設定して、各画面で利用できるようにします。
【クリック】各画面では、画面のコンストラクタでOptions Patternを適用したコンフィギュレーションをサービスとして利用できます。この仕組みはASP.NET Core Options PatternでのコントローラーのコンストラクタにOptions Patternを適用したコンフィギュレーションを渡した時と同じ仕組みですので、ASP.NET Core Options Patternのおさらいにもなります。
App.xamlがMainWindow.xamlを呼び出す前にOptions Patternを適用したコンフィギュレーションをサービスするので、App.xamlのMainWindow.xaml呼び出しを止めてから、App.xaml.csのサービス構築後にMainWindowの呼び出しを行うようにします。
【クリック】App.xamlにStartupメソッドを定義、App.xaml.csにStartupメソッド作成して、MainWindowを構築します。MainWindowはサービスとしてホスト構築時に登録しておき、StartupメソッドでMainWindowサービスを表示します。この流れを解説していきます。 まずはASP.NET Core Options Patternのおさらいをしますが、前回はカプセル化と関心ごとの分離についてフォーカスしたお話をしたので、今回は汎用ホストによるビジネスロジックとシステムロジックの分離について注目した話を進めていきます。 まずはASP.NET Core Options Patternのおさらいとして、簡単に流れを説明します。【クリック】 最初にJSONファイルに設定値を設定します。前回のソースは私のGitHubで公開していますので詳細はGitHubを参照してみてください。 次にProgram.csでホストビルダーにコンフィギュレーションサービスを設定します。WebApplication.CreateBuilderで作成されたホストにはすでにappsettings.jsonが読み込まれており、同じ構造を持つクラスで型指定されたサービスとして公開できます。
このホストビルダーで作成されたホストは汎用ホストと呼ばれるもので、ログや設定値をインジェクションするためのDIコンテナとして機能します。合わせてアプリケーションのライフサイクル管理を行い、アプリケーションのビジネスロジックからシステムのロジックを切り離すのに有効です。 利用する側では、コンストラクタで受け取ったコンフィギュレーションサービスをクラスのグローバルスコープの変数に格納して、POSTやGETの各ファンクションで利用することができます。 各メソッドでの利用時にはJSONと同じ構造のクラスにマップされている各プロパティを利用することができます。 この際にJSONに設定された「English」と「Japanese」を動的に変更できます。画面はIndexになっていますが、POSTで言語指定を受け取れば画面をユーザーが動的に変更することができるようになります。【クリック】
ここで使用している設定値の構造は「English」と「Japanese」という名前で「Brand」と「Pages」というプロパティを持つ型になります。これがOptions Patternのひとつの特長です。同じ構造を持つ型をひとつの定義で指定することができます。 ASP.NET Core Options Patternでは、WebApplication.CreateBuilderによってappsettings.jsonが自動的に読み込まれておりコンフィグレーションサービスをそのまま登録していましたが、WPFで利用するHost.CreateDefaultBuilderはコンフィグレーションサービスを構築するところから始めます。コーディングは次のセクションでお話ししますので、ここではWPFの例を使って.NET CoreでのOptions Patternの仕組みを解説します。 ASP.NET Coreの場合のProgram.csでは汎用ホストのコンフィギュレーションを直接サービス登録していました。
【クリック】WPFの場合はこのホストビルダーの部分が少々手間がかかります。ひとつは、ASP.NET Coreの時に自動的に汎用ホストが読み込んでいたJSONは、明示的に読み込む必要があります。換言するとJSONの物理的な位置を指定できるということです。
【クリック】JSON以外のファイルも扱えるのでこの資料の巻末のリンク「.NET の構成プロバイダー」を参照してください。【クリック:消す】
【クリック】もう一つはアプリケーションの開始フローをカスタムしてMainWindowの前にサービス登録の処理を差し込む必要があります。少し細かく見ていきましょう。【クリック】 ASP.NET Coreでの汎用ホストはProgram.csで定義しました。.NET Coreでの汎用ホストはApp.xaml.csで定義します。
明示的にJSONファイルを読み込むように定義したホストのコンフィギュレーションをサービスに登録するステップは2つです。汎用ホストの「ConfigureAppConfiguration」を使ったアプリケーション設定へのJSONファイルの読み込みと、同じく汎用ホストの「ConfigureServices」を使ったサービスの登録です。
【クリック】そのため、まずMicrosoft.Extensions.Hosting名前空間が必要になります。
【クリック】処理の流れとしては、汎用ホスト「ConfigureAppConfiguration」で取得した「configuration」のソースをクリアしてappsettings.jsonを読み込みます。optionalはappsettings.jsonを省略可能フラグで、「true」を指定するとファイルが無くとも動きます。「reloadOnChange」は、「true」でappsettings.jsonが変更されると再読込します。ここでMicrosoft.Extensions.Configuration名前空間が必要になります。 こうして構築された「configuration」は「ConfigureServices」で「context.Configuration」で取得できますので、同じく取得した「service」にコンフィギュレーションサービスとして登録します。
【クリック】この際にJSONファイルと同じ構造のApplicationContextクラスを型指定してあげることでOptions Patternを利用することができるようになります。このConfigureメソッドの型指定は、TOptions型のIOptionsとしてコンフィギュレーションサービスが受け取ることができますので、Dependency Injectionとしてコンフィギュレーションサービスに後から差し込むことができるわけです。ここではMicrosoft.Extensions.DependencyInjection名前空間が必要になります。 起動のフローを変更するので、ここからはコーディングを始めます。 まず、任意のフォルダでVisual Studio Codeを起動してCTRL+@でターミナルを表示します。
「dotnet new wpf」でプロジェクトを作成します。 Microsoft.Extensionsの各拡張機能のインストールは、それぞれ「Microsoft.Extensions.Hosting」「Microsoft.Extensions.Configuration」「Microsoft.Extensions.DependencyInjection」をNugetから.NET CLIをコピーしてコマンドをターミナルに貼り付けてインストールします。【クリック】【クリック】 MainWindow表示までの流れはApp.xamlとApp.xaml.csの定義でカスタマイズすることができます。
【クリック】App.xamlでは、StartupUriを削除してStartup時に動作するメソッドを指定します。この例では「Application_Startup」としていますので、後程App.xaml.csにApplication_Startupメソッドを実装します。あわせて終了時のExitメソッドとして「Application_Exit」を指定して、Application_Exitメソッドも後程実装します。
【クリック】次にApp.xaml.csのApplication_StartupメソッドでMainWindowを表示するために、あらかじめ汎用ホストのサービスとしてMainWindowを登録しておきます。【クリック】 汎用ホストにサービスとして登録されたMainWindowは、App.xaml.csのAppクラスのグローバルスコープとして定義された「_host」のサービスのひとつとして取得できます。「GetRequiredService」は例外時nullを返す「GetService」と異なりInvalidOperationException(サービスが無い場合)やObjectDisposedException(サービスが破棄されている場合)を返すので、後続処理で対応を追加することができます。そのようなオペレーションが想定される場合に使用します。その際、考慮しなければいけないのがサービスのスコープになりますので、後程サービスのスコープに触れます。
【クリック】GetRequiredServiceで取得したサービスの「Show」メソッドでMainWindowが表示されます。 では、このサービスのスコープについて少々触れたいと思います。
【クリック】Microsoft DocsのASP.NET Core での依存関係の挿入、有効期間と登録のオプションのセクションでは、「AddTransient」「AddScoped」「AddSingleton」についてサービスインスタンスにオペレーションIDを付けた検証の方法を紹介しています。「AddTransient」はセッションごとに一意なインスタンスで、「AddScoped」はリクエストごとのインスタンス、「AddSingleton」はアプリケーション一意のサービスインスタンスをアプリケーションホストに追加します。今回のMainWindowサービスではアプリケーション一意のインスタンスを使っていますが、後述するデータコンテキストとコンフィギュレーションサービスがMainWindowで強い依存関係を持ちますので、複数のユーザーにサービスする場合はAddTransientを使ってください。 appsettings.jsonに定義した設定値をMainWindowで使用します。 MainWindow.xaml.csで設定値を使うのですが解説の都合上、コンストラクタですべてを完結します。この解説ではコンストラクタでMainWindowクラスのグローバルスコープの変数に汎用ホストのコンフィギュレーションサービスで受け取ったコンフィギュレーションを格納するので、後々クリックやマウスオーバー、セレクトリストの選択などで利用することもできるようになります。この解説ではコンストラクタですべてを完結させたいので、INotifyPropertyChangedを利用したバインディングを行いますが、そのViewModelの説明の前に構造を先に解説します。
【クリック】MainWindow.xamlではデータコンテキストを設定しておきます。ここでは「MainWindowViewModel」という名前のクラスを使っています。
【クリック】これをMainWindow.xaml.csのコンストラクタでクラスのグローバルスコープ変数「datacontext」に格納して、このビューモデルのプロパティに設定値を投入します。
【クリック】 設定値は、コンストラクタで受け取った「config」の日本語セクションをグローバルスコープ変数「applicationContext」にバインドしておいて、他のメソッドで使えるようにしておきます。
【クリック】これで、各プロパティ「Brand」や「Page」オブジェクトの「Title」プロパティを使った指定が行えるようになります。
【クリック】【クリック】 ここでは本題から外れますが、動作確認のためのINotifyPropertyChangeを実装したViewModelを作成します。
【クリック】xaml側のデータコンテキスト指定は、Windowに設定してあるのでそのままプロパティをバインドしています。「UpdateSourceTrigger=PropertyChanged」は特になくとも動きます。データコンテキストがINotifyPropertyChangedを継承している場合、既定でPropertyChangedEventHandlerのデリゲートが実行されます。 ViewModel側では、INotifyPropertyChangedを継承してPropertyChangedEventHandlerのデリゲートを宣言して、デリゲートのメソッドを定義します。メソッドでは「CallerMemberName」を使っているので「System.Runtime.CompilerServices」をusingしています。
【クリック】各プロパティはそれぞれプライベート変数に値を格納し出し入れしています。値が同じなら何もせず変更がある場合、デリゲートのメソッドを呼び出します。