SlideShare a Scribd company logo
カプセル化や関心ごとの分離による継続的インテグレーション例と
グローバリゼーションへの応用
ASP.NET Core のグローバリゼーションおよびローカリゼー
https://docs.microsoft.com/ja-jp/aspnet/core/fundamentals/localization?view=aspnetcore-6.0
Profile
•ブログ : http://blog.processtune.com
•プロフィール : Facebook, Twitter or Microsoft MVP Website
•コミュニティ : .NETラボの運営スタッフ
•Microsoft MVP : July 2010 ~ Jun 2022
•Current expertise : MVP for Developer Technologies
Solutions Architect
システム構築のプロセス評価、改善、策定、開発フ
レームワークの設計、実装管理、プリセールスやプロ
ジェクトの立ち上げなど
オプションズ・パターンによるカプセル化
オプションズ・パターンによる関心ごとの分
オプションズ・パターンによるグローバリゼ
PoCと継続的インテグレーション
Agenda
ASP.NETCoreOptionsPattern.pptx
xxController.cs
コンストラクタ
(サービス取
得)
(クラス・ス
コープの変数に
格納)
xxController.cs
各メソッド
(変数を利用)
ASP.NET Core Options Patternの仕組み
JSONファイル
Project.cs
サービス登録
xxController.cs
コンストラクタ
(サービス取
得)
(クラス・ス
コープの変数に
格納)
xxController.cs
各メソッド
(変数を利用)
ASP.NET Core Options Patternの仕組み
JSONファイル
Project.cs
サービス登録
xxController.cs
コンストラクタ
(サービス取
得)
(クラス・ス
コープの変数に
格納)
xxController.cs
各メソッド
(変数を利用)
ASP.NET Core Options Patternの仕組み
JSONファイル
Project.cs
サービス登録
フィールド以外で構成されたインスタンスを生成
ASP.NETCoreOptionsPattern.pptx
resxファイルでのオブジェクト定義
WTI Converter
https://converter.webtranslateit.com/
Android .xml (xml)
Comma Separated Value (CSV) (csv)
Java .xml (xml)
jQuery-glob (as a hash) (js)
jQuery-glob (as a list) (js)
JSON (json, js, resjson)
MicroDVD .sub (sub)
Windows Installer .nsh (nsh)
PHP Array (php, inc)
PHP ArrayList (php, inc)
PHP Define (php, inc)
PHP .ini, PHP .conf (ini, conf)
PHP Laravel (php, inc)
Gettext .po/.pot (po, pot)
Java .properties, InnoSetup .isl (properties, isl)
Java .properties v2, InnoSetup .isl (properties, isl)
Microsoft Windows Resource File .rc (rc)
Microsoft .resx, .resw (resx, resw)
Microsoft .resx, .resw (resx, resw)
Blackberry .rrc (rrc)
Youtube Close Caption .sbv (sbv)
SubRip subtitles .srt (srt)
Apple .strings (strings)
Apple .stringsdict (stringsdict)
Subviewer .sub (sub)
Term Base Exchange .tbx (tbx)
Translation Memory Exchange .tmx (tmx)
Qt Linguist .ts (ts)
Typo3 L10N (xml)
Xliff (xlf, xml, xlif, xliff)
Xliff2 (xlf, xml, xlif, xliff)
XTB (xtb)
Yaml (yml, yaml)</select>
関心ごとの分離
バリュー・オブジェクト(Domain Driven
Design)
ドキュメント・スキーマDB
バリュー・オブジェ
クト
リレーショナル・データベース
エンティティ
設定値のサンプル(カプセル化と関心ごとの分離)
ページ属性
各ページ
アプリケーション名
言語
設定値のセクション
アプリケーショ
ン・コンテキス
ト
日本語
管理画面
ホーム 検索
上映日 上映開始 上映終了 題名 スクリーン番号
個人情報
英語
Management
Console
Home Search
Date SlotStart SlotEnd Title ScreenNumber
Privacy
ASP.NETCoreOptionsPattern.pptx
Dotnet new razor
Visual Studio
Code起動
Ctrl+@
→パネルサイズ
の最大化
Dotnet new –list
Razor Pagesを選
択
appsettings.json
日本語部分 英語部分
個人情報ペー
ジのダミー
データ
appsettings.json
日本語部分 英語部分
個人情報ペー
ジのダミー
データ
ApplicationContextモデルと設定読込
ApplicationContextモデ
ル
PrivacyContentsObject
やHomeContentsObject
のモデル(ページ実装
無し)
Program.csで設定読込
ApplicationContextモデルと設定読込
ApplicationContextモデ
ル
PrivacyContentsObject
やHomeContentsObject
のモデル(ページ実装
無し)
Program.csで設定読込
Layout.chtml
ページの取得
「ホーム」
「検索」「個
人情報」
ヘッダ部分の
描画
ボディとフッ
タ部分の描画
Search.chtmlとSearch.chtml.cs
cs側で設定値
をViewDataに
格納
chtml側で利
用
Index.chtml.csと実行
cs側で設定値を
ViewDataに格納
QueryStringから
設定値を逆引き
してページのタ
イトルを取得
Ctrl+@でターミ
ナル
→dotnet watch
runで実行
ひとまず英語と日本語の動作を確認
Razorのルーティ
ングによって
Indexが呼ばれる
QueryStringで
ページ・リダイレ
クト
SearchModelのコ
ンストラクタで読
み込みする設定値
を英語に変える
ASP.NETCoreOptionsPattern.pptx
オプションズ・パターンの特長を生かすCI
バウンダリー
コンテキスト
特長
Web App, API,
MVC
オプション
ズ・パター
ンの特長
関心ごとの
分離
コントロー
ルの画面描
画の定義
エリアごと
の画面描画
の定義
カプセル化
言語切替機
能(言語の
追加)
言語の追加
Spanishを1行追加
appsettings.json
にスペイン語を追
加
SearchModelのコ
ンストラクタで読
み込みする設定値
をスペイン語に変
える
言語の追加
設定の読込をセク
ションごとでなく全
体に変更する
ApplicationContext
にLanguagesを追加
SearchModelのコン
ストラクタで
Languagesを設定
→ViewDataに設定
言語の追加
ViewData経由で
Languagesを取
得
→選択肢を作成
選択リストを
作成
asp-itemsに設
定するだけ
言語の追加
ViewData経由で
Languagesを取
得
→選択肢を作成
選択リストを
作成
asp-itemsに設
定するだけ
 Optionsパターンはカプセル化と関心ごとの分離が可能
 階層構造の設定値定義ができるのでマイクロサービス、ポリグロット・パーシ
ステンス、ドメイン・ドリブン・デザインと親和性が高い
 グローバリゼーションはパターン・アンド・プラクティスがありますが、PoC
などのモックであればOptionsパターンで軽微に構築できる
 同じ構造のモデルならば「public const string Japanese = “Japanese”;」など
を複数指定することで別々の構造体として生成できる
 その仕組みを使うとセクションごとに読み込まなくとも自動的に別々の構造体
に別々の設定値が読み込まれる
 設定値のセクション定義、読込クラスの名前、利用時の指定が一貫したコー
ディングになるように設計されている
まとめ
レコード型 - C# によるプログラミング入門 | ++C++; // 未確認飛行 C
https://ufcpp.net/study/csharp/datatype/record/
非パブリック、パラメーターなしのコンストラクターが逆シリアル化に使用されない | Microsoft Docs
https://docs.microsoft.com/ja-jp/dotnet/core/compatibility/serialization/5.0/non-public-parameterless-constructors-not-used-for-deserialization
Parameterless struct constructors | Microsoft Docs
https://docs.microsoft.com/ja-jp/dotnet/csharp/language-reference/proposals/csharp-10.0/parameterless-struct-constructors
ASP.NET Core のオプション パターン | Microsoft Docs
https://docs.microsoft.com/ja-jp/aspnet/core/fundamentals/configuration/options?view=aspnetcore-6.0
DDD 指向マイクロサービスの設計 | Microsoft Docs
https://docs.microsoft.com/ja-jp/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/ddd-oriented-microservice
ControllerBase.ViewBag プロパティ (System.Web.Mvc) | Microsoft Docs
https://docs.microsoft.com/ja-jp/dotnet/api/system.web.mvc.controllerbase.viewbag?view=aspnet-mvc-5.2
ViewPage.ViewData プロパティ (System.Web.Mvc) | Microsoft Docs
https://docs.microsoft.com/ja-jp/dotnet/api/system.web.mvc.viewpage.viewdata?view=aspnet-mvc-5.2
"No parameterless constructor found" when trying to deserialize data from Google.Protobuf
https://github.com/protobuf-net/protobuf-net/issues/826
Links
Class ClientBase | .NET client library | Google Cloud
https://cloud.google.com/dotnet/docs/reference/Grpc.Core/latest/Grpc.Core.ClientBase
ASP.NET Core の構成 | Microsoft Docs
https://docs.microsoft.com/ja-jp/aspnet/core/fundamentals/configuration/?msclkid=d80e714bd0e011ecb654ad0245863624&view=aspnetcore-6.0
ASP.NET Core での依存関係の挿入 | Microsoft Docs
https://docs.microsoft.com/ja-jp/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-6.0
ASP.NET Core での Razor ファイルのコンパイル | Microsoft Docs
https://docs.microsoft.com/ja-jp/aspnet/core/mvc/views/view-compilation?view=aspnetcore-6.0&tabs=visual-studio
Links

More Related Content

More from Takao Tetsuro (20)

Polyglot Persistence and Graph Schema
Polyglot Persistence and Graph SchemaPolyglot Persistence and Graph Schema
Polyglot Persistence and Graph Schema
Takao Tetsuro
 
ServiceMeshEndpointWithMinimalAPIPublish.pptx
ServiceMeshEndpointWithMinimalAPIPublish.pptxServiceMeshEndpointWithMinimalAPIPublish.pptx
ServiceMeshEndpointWithMinimalAPIPublish.pptx
Takao Tetsuro
 
OptonsPatternDotNet.pptx
OptonsPatternDotNet.pptxOptonsPatternDotNet.pptx
OptonsPatternDotNet.pptx
Takao Tetsuro
 
gRPCurlDotNet.pptx
gRPCurlDotNet.pptxgRPCurlDotNet.pptx
gRPCurlDotNet.pptx
Takao Tetsuro
 
Layout isfirstprocessofatomicdesign
Layout isfirstprocessofatomicdesignLayout isfirstprocessofatomicdesign
Layout isfirstprocessofatomicdesign
Takao Tetsuro
 
Wasm blazor and wasi 2
Wasm blazor and wasi 2Wasm blazor and wasi 2
Wasm blazor and wasi 2
Takao Tetsuro
 
WebAssemblyとBlazor 、WebAssembly System Interfaceでコンテナライズの設計を解説
WebAssemblyとBlazor 、WebAssembly System Interfaceでコンテナライズの設計を解説WebAssemblyとBlazor 、WebAssembly System Interfaceでコンテナライズの設計を解説
WebAssemblyとBlazor 、WebAssembly System Interfaceでコンテナライズの設計を解説
Takao Tetsuro
 
Team development
Team developmentTeam development
Team development
Takao Tetsuro
 
Interoperability of webassembly with javascript
Interoperability of webassembly with javascriptInteroperability of webassembly with javascript
Interoperability of webassembly with javascript
Takao Tetsuro
 
Interactive connection2
Interactive connection2Interactive connection2
Interactive connection2
Takao Tetsuro
 
Relationship betweenddd and mvc
Relationship betweenddd and mvcRelationship betweenddd and mvc
Relationship betweenddd and mvc
Takao Tetsuro
 
M365VM_PowerFX_takao-matsumoto_matsui_kojima
M365VM_PowerFX_takao-matsumoto_matsui_kojimaM365VM_PowerFX_takao-matsumoto_matsui_kojima
M365VM_PowerFX_takao-matsumoto_matsui_kojima
Takao Tetsuro
 
OpenStreetMap and Mapbox
OpenStreetMap and MapboxOpenStreetMap and Mapbox
OpenStreetMap and Mapbox
Takao Tetsuro
 
Excel on OneDrive is not a file
Excel on OneDrive is not a fileExcel on OneDrive is not a file
Excel on OneDrive is not a file
Takao Tetsuro
 
Development toolsforteamdevelopment
Development toolsforteamdevelopmentDevelopment toolsforteamdevelopment
Development toolsforteamdevelopment
Takao Tetsuro
 
React Helmet navigates SPA
React Helmet navigates SPAReact Helmet navigates SPA
React Helmet navigates SPA
Takao Tetsuro
 
Reacthelmetcontrolesspa
ReacthelmetcontrolesspaReacthelmetcontrolesspa
Reacthelmetcontrolesspa
Takao Tetsuro
 
One drivesettings
One drivesettingsOne drivesettings
One drivesettings
Takao Tetsuro
 
Galapagosization environment
Galapagosization environmentGalapagosization environment
Galapagosization environment
Takao Tetsuro
 
Design mvc apps with spotify web api object model
Design mvc apps with spotify web api object modelDesign mvc apps with spotify web api object model
Design mvc apps with spotify web api object model
Takao Tetsuro
 
Polyglot Persistence and Graph Schema
Polyglot Persistence and Graph SchemaPolyglot Persistence and Graph Schema
Polyglot Persistence and Graph Schema
Takao Tetsuro
 
ServiceMeshEndpointWithMinimalAPIPublish.pptx
ServiceMeshEndpointWithMinimalAPIPublish.pptxServiceMeshEndpointWithMinimalAPIPublish.pptx
ServiceMeshEndpointWithMinimalAPIPublish.pptx
Takao Tetsuro
 
OptonsPatternDotNet.pptx
OptonsPatternDotNet.pptxOptonsPatternDotNet.pptx
OptonsPatternDotNet.pptx
Takao Tetsuro
 
Layout isfirstprocessofatomicdesign
Layout isfirstprocessofatomicdesignLayout isfirstprocessofatomicdesign
Layout isfirstprocessofatomicdesign
Takao Tetsuro
 
Wasm blazor and wasi 2
Wasm blazor and wasi 2Wasm blazor and wasi 2
Wasm blazor and wasi 2
Takao Tetsuro
 
WebAssemblyとBlazor 、WebAssembly System Interfaceでコンテナライズの設計を解説
WebAssemblyとBlazor 、WebAssembly System Interfaceでコンテナライズの設計を解説WebAssemblyとBlazor 、WebAssembly System Interfaceでコンテナライズの設計を解説
WebAssemblyとBlazor 、WebAssembly System Interfaceでコンテナライズの設計を解説
Takao Tetsuro
 
Interoperability of webassembly with javascript
Interoperability of webassembly with javascriptInteroperability of webassembly with javascript
Interoperability of webassembly with javascript
Takao Tetsuro
 
Interactive connection2
Interactive connection2Interactive connection2
Interactive connection2
Takao Tetsuro
 
Relationship betweenddd and mvc
Relationship betweenddd and mvcRelationship betweenddd and mvc
Relationship betweenddd and mvc
Takao Tetsuro
 
M365VM_PowerFX_takao-matsumoto_matsui_kojima
M365VM_PowerFX_takao-matsumoto_matsui_kojimaM365VM_PowerFX_takao-matsumoto_matsui_kojima
M365VM_PowerFX_takao-matsumoto_matsui_kojima
Takao Tetsuro
 
OpenStreetMap and Mapbox
OpenStreetMap and MapboxOpenStreetMap and Mapbox
OpenStreetMap and Mapbox
Takao Tetsuro
 
Excel on OneDrive is not a file
Excel on OneDrive is not a fileExcel on OneDrive is not a file
Excel on OneDrive is not a file
Takao Tetsuro
 
Development toolsforteamdevelopment
Development toolsforteamdevelopmentDevelopment toolsforteamdevelopment
Development toolsforteamdevelopment
Takao Tetsuro
 
React Helmet navigates SPA
React Helmet navigates SPAReact Helmet navigates SPA
React Helmet navigates SPA
Takao Tetsuro
 
Reacthelmetcontrolesspa
ReacthelmetcontrolesspaReacthelmetcontrolesspa
Reacthelmetcontrolesspa
Takao Tetsuro
 
Galapagosization environment
Galapagosization environmentGalapagosization environment
Galapagosization environment
Takao Tetsuro
 
Design mvc apps with spotify web api object model
Design mvc apps with spotify web api object modelDesign mvc apps with spotify web api object model
Design mvc apps with spotify web api object model
Takao Tetsuro
 

ASP.NETCoreOptionsPattern.pptx

Editor's Notes

  • #2: ASP.NETの設定値の分離の仕方は以前から変わりません。JSONファイルに設定値を定義し、アプリケーションのホストでサービスを登録することで各メソッドが利用できるという仕組みです。ASP.NET MVCの場合はCreateBuilderで作成したホストに設定値のサービスを登録しておけば、コントローラーのコンストラクタで受け取ったサービスをコントローラーのスコープでグローバル定義された変数に格納することで、POSTやGETリクエストでの処理でその変数を利用することができます。 その際に、オプションズ・パターンを使った設定値の分離を行っておくと、保守性の良いカプセル化を行うことができます。設定値をメソッドごとやコントローラーごとにカプセル化できます。また、ログやIPホワイトリストといった「システム」と「業務」の情報のレベルでカプセル化することもできます。 さらに、関心ごとの分離も可能です。本セッションで言うところの「関心ごと」というのは、同じことを指しているがそれを使うシーンによって呼び方が異なるとも換言できます。ドメインドリブンデザインで表現すると、いくつかの同じ属性を持つそれぞれのバウンダリーコンテキストで扱う設定値が異なるといえます。最も簡単な例では、売上と支払です。ある商品を購入した際に、会員アプリで「お支払額」と表示されるのは、販売管理システムでは「売上」と表示されます。商品というオブジェクトの「価格」が会員アプリの購入履歴では「お支払額」と表示され、販売管理システムの集計表では「売上」と表示されます。関心ごとで分離する場合、販売管理システムの「売上」に付随する情報である原価や販売数、商品の色やサイズを関心ごととしてまとめられます。会員アプリの「お支払額」には、付随する情報として決済方法やポイント、履歴などを関心ごととしてまとめておくと管理しやすいと思います。 本セッションでは、オプションズパターンの特長を表現するため、グローバリゼーションの実装例を使って「同じ属性を持ちながら別々の設定値を読込むアプリケーションの継続的インテグレーション」を解説していきます。
  • #3: 実案件の製品環境でグローバリゼーションを行う場合は、Microsoft Docsを参照してください。こちらのページではサービスサイドでレンダリングするページで「IHtmlLocalizer」を使ったresxファイル・リソースの呼び出しを行える実装方法を紹介しています。そのためコントローラーでページレンダリングのためのローカライズ文字列をViewDataやViewBagに入れる必要がなく、ページレンダリングのロジックがViewとControllerに分散しません。どちらがいいということではなく、継続的インテグレーションの視点で設定値をresxファイルで管理したくないとかresxファイルで管理するスキームがすでに完成している等、プロジェクトによってさまざまなケースがあるので適材適所で使い分けてください。
  • #4: 自己紹介を読む
  • #5: 本日のアジェンダを読む
  • #7: 設定値の読込の流れは今までと変わりません。JSONファイルからbuilderにサービスを登録する際にJSONファイルの構造と同じ構造のクラスを使った読み込みを行います。 【クリック】たとえば、JapaneseとEnglishに同じ構造で日本語と英語のアクション名やページタイトルを設定しています。 【クリック】サービス登録で使うJSONファイルと同じ構造のクラスを用意します 【クリック】この例のApplicationContextクラスを奇妙に思う人は正解です。オプションズパターンのひとつの特長ですから後で解説します。これをホストにサービスとして登録します。【クリック】 【クリック】
  • #8: サービスとして登録された設定値はコンストラクタで受け取れますので、クラスのグローバルレベルの変数に格納しておきます。 【クリック】そうすることでメソッドで画面のような感じで利用することができます。 【クリック】ViewDataを使っているのは、オプションズパターンの分離の際に、オブジェクトを階層化する必要があったからです。単なるカプセル化としてオプションズパターンを使う場合は、グルーピングされた階層の無い並列なキーと値の組合せのセットになりますので、ViewBagで十分なケースもあります。 【クリック】
  • #9: 先ほど、ApplicationContextクラスを奇妙に思ったのはこの部分のはずです。ConfigurationサービスのEnglish定数をApplicationContextクラスにバインドするのですが、ここをJapaneseに変更することができます。 【クリック】そのため、ここはサービス登録時のように文字列リテラルを直接指定することもできます。もちろんお勧めしません。つまり、オプションズパターンでは、定数で定義された部分以外のこの部分について、定数を使ってセクションごとに特定のクラスにバインドすることができます。 そして、そのクラスが同じ属性を持つオブジェクトを表現する場合は、利用時に定数で指定しますので「JSONのセクションの定義」、「JSON定義の定数化」「その定数を使ったサービスへのセクション読込」、「サービスのセクションを指定した利用時のバインド指定」に一貫性を保持したコーディングができるようになっています。
  • #10: 設定値を受け取るインスタンスの型について詳細の解説になります。 【クリック】オプションズパターンのひとつの特長ですが、こんな感じのクラスや構造体が生成されるようなイメージをしてください。実際は、中に入っているデータが英語か日本語かが重要なので、右下の図のC#10.0のレコード構造型をイメージしてもらった方がいいかもしれません。 【クリック】定数フィールドは無視され読み書き可能なプロパティで構成されたインスタンスを生成します。ApplicationContextというクラスをコードで生成した時のインスタンスは、定数で指定した名前のクラスや構造体のようにふるまいます。 【クリック】そのため定数の分だけインスタンスが生成されます。インスタンス化の際は、既定のコンストラクタである非抽象型のパラメーター無しのパブリックコンストラクタ―が使用され、そのインスタンスに定数で指定した名前に対応するJSONファイルのセクションがデシリアライズされます。これはデシリアライズの際の.NETの標準的な動作なので、gRPCのProtocol Buffersフォーマットのデータをデシリアライズする際やJSON Serializerのデシリアライズなどでも同じように非抽象型のパラメーター無しのパブリックコンストラクタ―が使用されます。 ここまでがオプションズパターンのカプセル化の話になります。ここでは英語と日本語をカプセル化しました。【クリック】
  • #11: 設置値をソースコードから分離する場合、それらが「グルーピングされた階層の無い並列なキーと値の組合せのセット」で十分なのか、「階層化されている必要がある」のかを考慮してください。これは、ソースコード側にも影響が出ます。前述の「ViewBag」と「ViewData」の使い分けにも影響が出ますし、nullチェックや型変換といったソースコードの全域に影響があり、継続的インテグレーションにも大きな影響があります。実際に例を見ていきます。
  • #12: たとえばサンプルのような階層型の設置値をresxで定義した場合、階層化の表現が非常に複雑になります。Excelなどで管理していて、ワークシート関数などを使ってコードを自動生成している場合は、なおさら継続的インテグレーションが困難になります。
  • #13: resxファイルはWTI Converterなどで変換可能ですので、Visual Studio Codeで設定値を使いたい場合は、Jsonファイルに変換して利用することができます。WTI Converterは、非常に豊富な種類の変換ができます(画面左)ので、継続的インテグレーションのエコシステムに組み込むことも可能です。
  • #14: オプションズパターンが設定値の関心ごとの分離に適している理由のひとつはオブジェクト表現です。オブジェクト表現は最終的にプリミティブデータの集合になるまで階層的に表現されます。ApplicationContextの場合、Pagesプロパティは文字列型の集合体であるPageオブジェクトの配列でプリミティブ表現できます。一般的な設定値の多くはキーと値のペアで表現できますが、関心ごとを表現する場合はほとんどのケースでオブジェクト表現が必要になります。 【クリック】今回のグローバリゼーションへの流用では、グルーピングは日本語文字列と英語文字列ということになります。関心ごとの分離とはページごとの分離などが一例に挙げられます。
  • #15: 以前ドットネットラボでDomain Driven Designのお話をした際に、バリューオブジェクトという概念を解説しました。特定の型のインスタンスに入っているデータによって一意性が発生するオブジェクトで、たとえばシネマコンプレックスのスクリーンなどは「何月何日何時」の「スクリーンN番」で「上映作品」が一意に決まります。オプションとして席数とか音響設備、非常口の数などがあった方がオブジェクトの形としては理想的なので、上映作品やスクリーンオブジェクトをDomain Driven Designでエンティティ表現してもいいのですが、鑑賞者にとっては優先度の低い属性です。おそらく関心ごととしては「何月何日」の「何時ごろ」の「上映作品」の3つです。ユースケースとしては、日時を優先したいケースと上映作品を優先して別の候補日を見たいケースがあります。つまり「何月何日」「何時」「スクリーン番号」「上映作品」といった属性を持つバリューオブジェクトで十分一意性を保証でき、映画を鑑賞する人に向けたアプリケーションを作成することができます。映画を鑑賞する人に向けたアプリケーションというサブドメインの上映作品検索というバウンダリーコンテキストには検索対象のバリューオブジェクトだけ実装するというサービス設計が可能です。 【クリック】もちろん、シネマコンプレックスの予約システム管理側のバウンダリーコンテキストには、上映作品エンティティやスクリーンエンティティがあって、正規化されたリレーショナルデータベースを永続化層に持つマイクロサービスで実装され、ステートフルミドルウェア上で上映作品検索サービスとのステートマシンが形成されます。 【クリック】映画検索のようなデータセントリックなユースケースでは、ポリグロットパーシステンスの概念を採用したドキュメントスキーマDBを永続化層に持つマイクロサービスを作成することができます。適材適所の永続化層の設計を行えば、上映作品検索サービスでエンティティ表現された場合よりも高速に検索できることが容易に想像できると思います。
  • #16: カプセル化として分離しているのは各ページの層までの部分になります。構成する属性が同じで、入っているデータによって一意性が決まるバウンダリーコンテキストの意味合いで分離されています。 【クリック】一方、各ページの下位の層は、それぞれが構成する属性が異なり、関心ごとによって分離しています。このバウンダリーコンテキストは業務の結果の記録なので、正規化されておらずドキュメント・スキーマをサポートするDBに保持されるように設計します。検索ページで検索条件が増えてもホームや個人情報のページのグローバリゼーションには影響しません。
  • #17: オプションズ・パターンによるグローバリゼーションの実装の説明をします。まずは細かなところよりも実装の流れをつかんでください。
  • #18: Visual Studio Codeを開いてターミナルを開きます。ターミナルを最大化してから、ここでlistオプションを使ってテンプレートの一覧を確認してください。作業ディレクトリを作成してカレントディレクトリにします。そこでRazor Pagesをdotnet newしてから、Visual Studio Codeでそのフォルダを開きます。
  • #19: まずは、appsettings.jsonに日本語と英語のテキストを追加します。サンプルは私のMicrosoft MVPのプロフィールの本日の実績のところにGitHubのURLが載ってますのでそこを参照してください。
  • #20: ポイントとしてはJapanese-Pages-Search-Areas-ControlLavelsなどのように階層化してある部分です。英語も同じ構造で設定しています。
  • #21: Jsonの用意が終わったら受け取るためのクラスを作ります。ApplicationContextクラスを作っています。クラスの階層が深い部分でrecordで設定してある構造体があります。 【クリック】そのクラスを使ってProgram.csで設定ファイルを読み込んだサービスを提供するようにしています。
  • #22: ポイントはrecordの部分になります。これが先ほど説明したデータセントリックな検索ページの構造体になります。
  • #29: OptionsパターンはWeb AppやAPI、MVCはもちろんですが、.NET全般に利用できる機能です。本日お話したOptionsパターンの設計概念は、マイクロサービス、ポリグロットパーシステンス、ドメインドリブンデザインと非常に親和性の高い機能です。
  • #30: 例としてグローバリゼーションが説明しやすかったのでスペイン語の追加を行っています。
  • #31: ここでのポイントは英語と日本語のセクションを読み込んでいた部分について、セクションではなく全体を読み込むように変更しています。
  • #32: View側を作成します。
  • #33: 選択リストが変更されるとフォームをPOSTして、サービス側でリクエストから取得した言語指定を使った「configuration.GetSection(ApplicationContext.Japanese).Bind(Context)」などで切り替えることが可能です。