65

ASP.NET MVCプロジェクトがあり、asp.netサイトの次の連絡先マネージャーチュートリアルのように、サービスレイヤーを使用しているとし ます。http ://www.asp.net/mvc/tutorials/iteration-4-make- the-application-loosely-coupled-cs

ビューのビューモデルがある場合、サービスレイヤーは各ビューモデルを提供するのに適切な場所ですか?たとえば、サービスレイヤーのコードサンプルにはメソッドがあります

    public IEnumerable<Contact> ListContacts()
    {
        return _repository.ListContacts();
    }

代わりにIEnumerableが必要な場合は、サービスレイヤーに配置する必要がありますか、それとも「正しい」場所である他の場所にありますか?

おそらくもっと適切なのは、ContactControllerに関連付けられたビューごとに個別のビューモデルがある場合、ContactManagerServiceに各ビューモデルを返すための個別のメソッドが必要ですか?サービスレイヤーが適切な場所でない場合、コントローラーで使用するためにviewmodelオブジェクトをどこで初期化する必要がありますか?

4

6 に答える 6

52

一般的にはありません。

ビューモデルは、ビューとの間で情報を提供することを目的としており、一般的なドメインではなく、アプリケーションに固有である必要があります。コントローラーは、リポジトリー、サービス(ここではサービスの定義についていくつかの仮定をしています)などとの相互作用を調整し、ビューモデルの構築と検証を処理し、レンダリングするビューを決定するロジックも含める必要があります。

ビューモデルを「サービス」レイヤーにリークすることで、レイヤーをぼかし、ドメインレベルの責任に焦点を当てるべきものと特定のアプリケーションとプレゼンテーションを組み合わせることができます。

于 2010-06-09T00:18:43.840 に答える
27

いいえ、そうは思いません。サービスは、結果をレンダリングするビューではなく、問題のあるドメインのみを考慮する必要があります。戻り値は、ビューではなく、ドメインオブジェクトで表す必要があります。

于 2010-06-09T00:07:07.120 に答える
26

従来のアプローチまたは理論に従って、ViewModelはユーザーインターフェイスレイヤーの一部である必要があります。少なくともその名前はそう言っています。

しかし、Entity Framework、MVC、リポジトリなどを使用して自分で実装することに取り掛かると、別のことに気づきます。

誰かがエンティティ/DBモデルをViewModels(最後に記載されているDTO)にマップする必要があります。これは、[A] UIレイヤー(コントローラーによる)で実行する必要がありますか、それとも[B]サービスレイヤーで実行する必要がありますか?

オプションBを使用します。複数のエンティティモデルが組み合わされてViewModelを形成するという単純な事実のため、オプションAはノーノーです。不要なデータをUIレイヤーに渡さない場合がありますが、オプションBでは、サービスはデータを操作し、マッピング後に(ViewModelに)必要な/最小限のデータのみをUIレイヤーに渡すことができます。

それでも、オプションAを使用して、ViewModelをUIレイヤー(およびエンティティモデルをサービスレイヤー)に配置しましょう。

サービスレイヤーをViewModelにマップする必要がある場合、サービスレイヤーはUIレイヤーのViewModelにアクセスする必要があります。どのライブラリ/プロジェクト?ビューモデルはUIレイヤーの別のプロジェクトにある必要があり、このプロジェクトはサービスレイヤーによって参照される必要があります。ViewModelが別のプロジェクトにない場合は、循環参照があるので、行きません。サービスレイヤーがUIレイヤーにアクセスするのは厄介に見えますが、それでも対処できます。

しかし、このサービスを使用している別のUIアプリがある場合はどうなりますか?モバイルアプリがある場合はどうなりますか?ViewModelはどのように異なりますか?サービスは同じビューモデルプロジェクトにアクセスする必要がありますか?すべてのUIプロジェクトは同じViewModelプロジェクトにアクセスしますか、それとも独自のプロジェクトを持っていますか?

これらの考慮事項の後、私の答えは、Viewmodelプロジェクトをサービスレイヤーに配置することです。とにかく、すべてのUIレイヤーはサービスレイヤーにアクセスする必要があります。そして、それらすべてが使用できる類似のViewModelが多数存在する可能性があります(したがって、サービスレイヤーのマッピングが容易になります)。最近のマッピングはlinqを介して行われていますが、これはもう1つの利点です。

最後に、DTOについてのこの議論があります。また、ViewModelsのデータ注釈についても説明します。データ注釈付きのViewModel(Microsoft.Web.Mvc.DataAnnotations.dll)は、UIレイヤーに常駐する代わりに、サービスレイヤーに常駐できません(ただし、ComponentModel.DataAnnotations.dllはサービスレイヤーに常駐できます)。すべてのプロジェクトが1つのソリューション(.sln)に含まれている場合、どのレイヤーに配置してもかまいません。エンタープライズアプリケーションでは、各レイヤーに独自のソリューションがあります。

したがって、DTOは実際にはViewModelです。これは、ほとんどの場合、2つの間に1対1のマッピングがあるためです(たとえば、AutoMapperを使用)。この場合も、DTOにはUI(または複数のアプリケーション)に必要なロジックがあり、サービスレイヤーに存在します。また、UIレイヤーViewModel(Microsoft.Web.Mvc.DataAnnotations.dllを使用する場合)は、DTOからデータをコピーし、いくつかの「動作」/属性を追加するだけです。

[今、この議論は興味深い方向に進んでいます...:I]

また、データ注釈属性はUI専用であるとは思わないでください。System.ComponentModel.DataAnnotations.dllを使用して検証を制限すると、同じViewModelをフロントエンドとバックエンドの検証に使用することもできます(したがって、UI-residing-ViewModel-copy-of-DTOを削除します)。さらに、属性はエンティティモデルでも使用できます。例:.ttを使用すると、Entity Frameworkデータモデルを検証属性で自動生成して、バックエンドに送信する前にmax-lengthなどのDB検証を実行できます。これにより、検証のためにUIからバックエンドへのラウンドトリップが節約されます。また、セキュリティ上の理由から、バックエンドで再検証することもできます。したがって、モデルは自立型のバリデーターであり、簡単に渡すことができます。もう1つの利点は、バックエンドの検証がDBで変更された場合、.tt(DBの詳細を読み取り、エンティティクラスの属性を作成する)が自動的にそれを取得することです。これにより、UI検証ユニットテストも失敗する可能性があります。これは大きなプラスです(誤って忘れて失敗するのではなく、修正してすべてのUI /コンシューマーに通知できます)。はい、議論は優れたフレームワーク設計に向かって進んでいます。ご覧のとおり、階層ごとの検証、単体テスト戦略、キャッシング戦略など、すべてが関連しています。

質問に直接関係していませんが。この必見のチャンネル9のリンクで言及されている「ViewModelFaçade」も探索する価値があります。それはビデオの11分49秒で正確に始まります。上記の現在の質問が整理されたら、これが次のステップ/思考になるためです:「ViewModelsを整理する方法は?」

そして最後に、これらのモデルとロジックの問題の多くは、RESTで解決できます。すべてのクライアントは、データを照会し、必要なデータのみを取得するためのインテリジェンスを持つことができるためです。また、モデルをUIに保持し、サーバー/サービスレイヤーのモデル/ロジックはありません。その場合、唯一の重複は、各クライアントが実行する必要のある自動テストになります。また、データに変更があった場合、変更に適応しないと一部のクライアントが失敗します。問題は、サービスレイヤー(およびそれらが運ぶモデル)を完全に削除するのか、それともREST APIを呼び出すUIプロジェクト(モデルの問題がまだ続く)にサービスレイヤーをプッシュするのかということです。しかし、サービス層の責任に関しては、それらは関係なく同じです。

また、あなたの例では、「_ repository.ListContacts()」はリポジトリからViewModelを返しています。これは成熟した方法ではありません。リポジトリは、エンティティモデルまたはDBモデルを提供する必要があります。これはビューモデルに変換され、サービスレイヤーによって返されるのはこのビューモデルです。

于 2012-07-04T09:50:05.610 に答える
6

これは、私が働いている場所に少し「依存」しています-通常、コントローラーがいくつかのサービスを消費していました-次に、返されたDTOを「ViewModel」に結合し、JSONの結果を介してクライアントに渡されます、またはRazorテンプレートにバインドされています。

約80%の確率で、DTOからViewModelへのマッピングは1-1になっています。「必要に応じて、DTOを直接使用するだけですが、DTOとクライアント/ビューで必要なものが一致しない場合は、ViewModelを作成し、必要に応じてオブジェクト間のマッピングを行います」に移行し始めています。

これが最善または正しい解決策であるとはまだ確信していませんが、最終的には「ビューのニーズを満たすためにDTOにXを追加するだけですか?」

于 2013-07-25T14:42:53.343 に答える
5

それはあなたが「サービス」とみなすものに依存すると思います。単一のクラスのコンテキストでサービスという用語が本当に好きだったことはありません。それは信じられないほど曖昧で、クラスの実際の目的についてはあまり教えてくれません。

「サービス層」がWebサービスなどの物理層である場合、絶対にそうではありません。SOAコンテキストのサービスは、データやプレゼンテーションロジックではなく、ドメイン/ビジネスオペレーションを公開する必要があります。しかし、サービスがカプセル化のさらなるレベルの抽象的な概念として使用されているだけであれば、あなたが望むようにサービスを使用することに問題はありません。

概念を混ぜないでください。サービスがビューモデルを扱う場合、それはプレゼンテーションサービスであり、データベースやビジネスロジックに直接触れないように、実際のモデルの上に階層化する必要があります。

于 2010-06-08T23:49:26.873 に答える
0

こんにちは私はここで非常に良い答えを見ます。そして私自身のために私は他のアプローチをします。モデルの種類が必要です。1つはビューモデルで、もう1つは共有モデルです。ビューモデルはUIレイヤーに残り、共有モデルは別のプロジェクトに残ります。共有モデルはスタンドアロンであるため、理論的にはどのウェアでも使用できます。このモデルは、サービスレイヤーから特定のデータを返したい場合、またはリポジトリから特定のデータが必要な場合に、ある程度の抽象化を提供します。これが良いアプローチかどうかはわかりませんが、私のプロジェクトでは非常にうまく機能します。たとえば、データベースに新しいオブジェクトを作成するために情報を提供する必要がある場合、共有モデルをサービスレイヤーに直接使用できるため、複雑さが軽減されます。共有モデルは時々マッピングする必要があります、ただし、サービスが不要なデータをUIにリークしていないことを確認できます。共有モデルを拡張機能として表示できますが、それを使用してUIロジックを構築することはできません。そのためには、viewmodelが必要です。ビューモデルをこの共有モデルと組み合わせて、継承を使用できる時間を節約できます。共有モデルはニュートラルである必要があり、いかなる種類のロジックも含まれていてはなりません。

于 2020-11-10T08:14:49.930 に答える