ここ数日、VS2013、EF6、WCF Service App プロジェクトのエンティティに DTO をマッピングするためのさまざまなソリューションを試してきました。
これはかなり大規模なプロジェクトであり、現在、レガシ コードをテスト対象にするために主要なリファクタリングが行われています (また、OpenAccess から EF6 への ORM の移植も行われています)。
正直なところ、AutoMapper を使用したことはありませんでしたが、非常に気に入ったので、デモ アプリでテストしてみました。正直なところ、何時間もかけて作業を行った後、機能するソリューションを実現できなかったことを少し恥じています。いじくり回しとグーグル。プロジェクトの内訳は次のとおりです。
WCF サービス アプリケーション テンプレート ベースのプロジェクト (分離コード付きの .svc ファイル)。Unity 3.x を IoC コンテナーに使用して、UnityServiceHostFactory から継承する独自の ServiceHostFactory を作成します。現在の AutoMapper nuget パッケージを使用します。DTO と DAL は予想どおり 2 つの別個のライブラリにあり、どちらもサービス アプリ プロジェクトによって参照されます。私の目標は単純です (私が思うに): すべてのマップをコンポジション ルートに接続して作成し、必要なオブジェクトを (DI コンテナーを使用して) DTO のドメイン知識と DAL ライブラリへの参照を持つクラスに挿入します。したがって、変換が必要な人は、変換ライブラリを参照するだけで済みます。
問題: うーん、いくつかあります...
1) Unity の AutoMapper の実例がどこにも見つかりません。AutoMapper を Unity に登録するために Web 全体で何度も参照されているコード スニペット (以下を参照) は、もう存在しないように見える Configuration クラスを参照しており、その非推奨に関するドキュメントを見つけることができません。
container.RegisterType<AutoMapper.Configuration, AutoMapper.Configuration>(new PerThreadLifetimeManager(), new InjectionConstructor(typeof(ITypeMapFactory),
AutoMapper.Mappers.MapperRegistry.AllMappers())).RegisterType<ITypeMapFactory,
TypeMapFactoy>().RegisterType<IConfiguration, AutoMapper.Configuration>().RegisterType<IConfigurationProvider,
AutoMapper.Configuration>().RegisterType<IMappingEngine, MappingEngine>();
2) マップ自体を作成する場所... ServiceHostFactory でこの操作を正しく実行できると仮定しますが、それは正しい場所ですか? そこにはBootstrapperプロジェクトがありますが、私はその道を(まだ)進んでおらず、可能であれば避けたいと思っています。
3) DTO lib の AutoMapper への明らかに必要な参照以外に、インスタンス化に何を挿入するか、構成オブジェクト (IConfiguration または IConfigurationProvider を想定)、およびアクセスするために WCF サービスのコンストラクターに挿入するクラス必要なオブジェクト。
#3 は少しあいまいですが、AutoMapper を Unity コンテナーにバインドできないため、テスト/試行/エラーを行って他の問題を把握することはできません。
任意のポインタをいただければ幸いです。
アップデート
そのため、正しくテストされている実用的なソリューションを手に入れましたが、確立されたベスト プラクティスに従っていることを確認したいと考えています。
まず、AutoMapper (2013 年 11 月 13 日現在) v3.x の Unity コンテナー登録は次のようになります。
container
.RegisterType<ConfigurationStore, ConfigurationStore>
(
new ContainerControlledLifetimeManager()
, new InjectionConstructor(typeof(ITypeMapFactory)
, MapperRegistry.AllMappers())
)
.RegisterType<IConfigurationProvider, ConfigurationStore>()
.RegisterType<IConfiguration, ConfigurationStore>()
.RegisterType<IMappingEngine, MappingEngine>()
.RegisterType<ITypeMapFactory, TypeMapFactory>();
すべてのコンテナー登録の直後に、ConfigureContainer() 内で RegisterMaps() メソッドを作成して呼び出しています。同様の名前のプロパティの自動マッピングとカスタム マッピングの両方を行うテスト マッピングを作成しました。主に次の 2 つの理由から、デモ アプリでこれを行いました。
- IIS でホストされ、Unity に注入された WCF アプリの AutoMapper については、その動作を完全に理解するのに十分なほどよくわかりません。変換を行うライブラリに構成オブジェクトを挿入する必要はないようで、その実装を理解するためにソースを読んでいます。
- 私が理解しているように、ここではキャッシュメカニズムが機能しており、キャッシュにマッピングが見つからない場合は、その場で作成されます。これは理論的には素晴らしいことですが、合成ルートで発生していたマッピングをテストできる唯一の方法は、ある種のカスタム マッピングを実行し、マッピングを実行して DTO を返すライブラリで Mapper.Map を呼び出すことでした。
その騒ぎはさておき、これが私が達成できたことです。
- WCF Service App (コンポジション ルート) は、DtoConversionMapper インスタンスを含む必要なすべてのオブジェクトを挿入します。
- このプロジェクトは、WCF Service App (comp ルート)、DtoLib、DalLib、ContractsLib (インターフェイス) で構成されています。
- ServiceFactoryHost では、カスタム マッピングを含むマッピングを作成できます (つまり、DTO と EF 6 エンティティ間の名前付きプロパティとは異なります)。
- DtoConversionMapper クラスは DtoLib ライブラリに存在し、次のようになります。
- DtoLib を参照するすべてのライブラリは、相互に変換できます。これには、これらの呼び出しの大部分が行われる Service App が含まれます。
指針となるアドバイスは大歓迎ですが、この大規模なリファクタリングに取り組んでいる間、動作するデモをテストできるようになりました。
最終更新
別のライブラリ (MappingLib) を追加してデモ プロジェクトを少し変更し、すべての DTO 変換とマッピングを静的メソッドに移動しました。Unity コンテナーが初期化された後もコンポジション ルートで静的メソッドを呼び出しますが、これにより、NUnit 単体テスト ライブラリで同じマップ作成メソッドを呼び出すことができるという柔軟性が追加され、自動マッパーを取り巻くコードの重複を効果的に排除できます。非常にテストしやすくなります。