12

私が読むことができる記事へのいくつかのリンク、または MVC (C#) で使用されるさまざまなパターンに関するいくつかの基本的な説明が必要です。

現在、ビュー モデル パターンを使用して Web アプリを構築する傾向があります。ビューごとに 1 つのビュー モデルがあります。私がこのアプローチを気に入っている理由は、モデルから不要なものが大量にある可能性があり、ここでいくつかの基本的なデータ注釈を使用できるからです。

また、コントローラーをできるだけシンプルに保つことができるように、ビュー モデル自体の中にビューモデルを構築するようになりました (これが正しいかどうかわかりませんか?)。

ただし、コントローラー内に多くのロジックを追加していることに気付いたことがありますが、これはコントローラーの目的であるため、私にとっては問題ないと思います。

上記に基づいて、大きな問題なくアプリを作成できます。ただし、コード例などを通常に閲覧しているときに、さまざまな開発者が上記で行っていることを本質的に行うために使用する方法が他にもたくさんあることに気付くことがよくあります。

「リポジトリを使用して何とか何とかする」という言及をよく目にします..私は「時々」リポジトリを使用しますが、これは主に、将来再利用することがわかっているモデルクエリ用であり、常に少しになりますゴミ捨て場。ここでのベストプラクティスは何ですか?

「インターフェース」と「サービスレイヤー」についても言及されていますが、ここで完全に失われています..私にとってほとんどの例は、同じ目標を達成するためにますます多くのステップを追加しているようです. それらはどのように/なぜ使用されますか?

4

3 に答える 3

5

これがベスト プラクティスとは言えませんが、これが私が使用しているものとその理由です。


1. リポジトリ。

それらは次のように構成されています。

IRead<>、およびの 3 つの基本的なインターフェイスがありIReadCreate<>ますIReadCreateDelete<>

interface IRead<T>
{ 
    T FindOne(int id);
    IQueryable<T> GetOne(int id);
    IQueryable<T> FindAll(Expression<Func<T, bool>> predicate);
}

interface IReadCreate<T> : IRead<T>
{ 
    T Create();
    void Create(T entity);
}

interface IReadCreateDelete<T> : IReadCreate<T>
{ 
    void Delete(int id);
    void Delete(T entity);
    void DeleteWhere(Expression<Func<T, bool>> predicate);
}

他のすべてのインターフェイスは次のようになります。

interface ICategoriesRepository : IReadCreate<Category>
{
    IQueryable<Category> GetAllActive();
}

そしてそれらはすべて、依存するデータ ソースに追加の便利な機能を提供します。つまり、実装リポジトリ内の他の型付きリポジトリにアクセスできません。これはServicesで行う必要があります。(下を見てください。)

このアプローチの主な目的は、呼び出し元のコード (すべてのリポジトリ、サービス、およびその他のコントラクトが別の DLL プロジェクトで (インターフェイスとして) 定義されているため、別のアセンブリから) 何ができるか (アイテムの読み取りや作成など) を示すことです。できません(アイテムの削除など)。


2. サービス

ビジネスロジックを実装するためのサービスと最良の方法。それらはすべての重要なロジック メソッドを実装する必要があります。そのような実装を実現するには、いくつかのリポジトリ依存が必要になりますDependency Injector。次のような依存関係プロパティを挿入できるため、Ninjectを使用することを好みます。

internal class CategoriesService : ICategoryService
{
    public ICategoriesRepository CategoriesRepository { get; set; }
    public IWorkstationsRepository WorkstationsRepository { get; set; }

    // No constructor injection. I am too lazy for that, so the above properties 
    // are auto-injected with my custom ninject injection heuristic.

    public void ActivateCategory(int categoryId)
    {
        CategoriesRepository.FindOne(categoryId).IsActive = true;
    }
}

サービスの目標は、コントローラーとリポジトリーからビジネス ロジックを排除することです。


3.ViewModel

あなたが言ったようにクールなことですが、その理由は、なぜあなたがそれらを自分自身で構築しているのか、私には理解できないことです. そのためにオートマッパーを使用しています(クエリ可能な拡張機能付き)。これにより、次のようなビューを作成できます。

モデルが必要なビューがあるとしましょう。IEnumerable<TicketViewModel>私がすることは:

public class FooController : Controller
{
     public IMappingEngine Mapping { get; set; } // Thing from automapper.
     public ITicketsRepository TicketsRepository { get; set; }

     public ViewResult Tickes()
     { 
         return View(TicketsRepository.GetAllForToday().Project(Mapping)
             .To<TicketViewModel>().ToArray();
     }
}

それでおしまい。基礎となるデータソースを呼び出すリポジトリへの単純な呼び出し (別のパターン。その抽象化はテストにのみ必要なので、それについては書きません)。データベース (または実装するものIDataSource<T>) への呼び出しを行います。Automapperは、単一のリクエストでクロステーブルを含む、ViewModel 列に必要なだけを取得するフォーム データベースに自動的にマップTicketします。TicketViewModel


結論

言いたいことはまだまだたくさんありますが、これがあなたの思考の糧になることを願っています。私が使用するすべてのパターンとプログラムは次のとおりです。

  1. オートマッパー (マッピング);
  2. Ninject (依存性注入);
  3. リポジトリ (データ アクセス);
  4. データ ソース (データはデータ ソースから読み取られます);
  5. サービス (データの双方向性);
  6. ViewModel (データ転送オブジェクト);
  7. 多分私が編集して追加する何か他のもの.
于 2012-12-15T08:37:01.020 に答える
3

あなたの投稿を読み始めたとき、あなたが求めているのは SOLID の原則の理解かもしれないと考えていました。最後に、インターフェイスとサービス レイヤーについて言及します。面白い。

SOLID と DRY の聖杯を称賛する記事はたくさんあります (多くの記事は、DRY 支持者が実際に何を提案しているのかを理解していません)。しかし、.NET の世界での一般的な考え方は、aspx で自動生成された Page_Load に移動して、ページが本来の動作を実行するまで意地悪な入力を開始することではありません。救助へのMVC。

ビューごとにモデルがあると言います。私はそれを音と呼んでいます。2 つのモデルが同一であっても、それらは等しいだけであり、同じではありません。例: NewsItem は EventItem ではありません。一方を拡張したい場合は、他方に影響を与えるべきではありません。

次に、ビューモデル自体でモデルを作成していると言い続けます。それは逆に聞こえます。しかし、コントローラーをきれいに保つためにそうしているとあなたは言います。良い!あなたの考え方に欠けているのは、サービスです。

やりたいことは、実際にあらゆる種類の作業を実行するすべてのコードをサービスに移動することです。サービスは、側面、機能、またはコントロールではない理由に基づいている場合があります。1 つの Web プロジェクトを見ると、VisitorService、NewsfeedService、CalendarService、CachingService、MainMenuService、HeaderService、FooterService など、無限に表示されます。

このシナリオでは、コントローラーは、何らかの作業を実行するサービス (ま​​たは複数のサービス) にモデルを要求することのみを担当します。そして、そのモデルをビューに転送します。

「ビジネス ロジック」をサービスに取り込めば、それで満足するなら、簡単に IoC (Inversion of Control) をプロジェクトに適用できます。私はまだ IoC に投票していません。メリットは宣伝されているほど大きくなく、コードの肥大化なしで確実に行うことができます。しかし、IoC では、コーディングする前によく考えてください。

IoC に関する非常に簡単なチュートリアルとして、Ninject をお勧めします。忍者だけでなく、サムライ、刀、手裏剣も登場します。それは車や動物よりもずっとクールです。

https://github.com/ninject/ninject/wiki/Dependency-Injection-By-Hand

于 2012-12-15T08:52:12.370 に答える
2

コントローラ:

理論的には、コントローラーは「データ」のみを処理する必要があります。ある場所から別の場所への情報の断片の移動。

ちょっとした例:

  1. コントローラーは、いくつかのパラメーターを含むリクエスト「GetMessage」を受け取ります。
  2. このデータをサービス層に送信します。サービス層では、メッセージを返すリポジトリにアクセスしています。
  3. コントローラーはこのメッセージを受信し (または null がなかった場合)、受信したメッセージを返信するか、またはエラーが発生して何らかの方法でユーザーに通知する必要があるかを決定します。

「理論上」のすべてのビジネスロジックは、何らかのサービスレイヤーの背後にある必要があります。そうすれば、すべてを簡単にテストできます。コントローラーのロジックにより、一部のテストがより困難になります。

インターフェース:

インターフェイスベースのデザインは、現在非常に人気があります。特に、依存性注入を処理するすべての IOC コンテナーで。しかし、この概念から始めているのであれば、これらのキーワードについて気にする必要はありません。リポジトリのパターンを知っている場合は、まず IRepository インターフェイスを使用してみてください。具象クラスでリポジトリにアクセスする代わりに、IRepository を使用してください。(コントローラのフィールドを Repository から IRepository に変更するだけです)。

インターフェースに関する一般事項

より複雑なシナリオでインターフェイスの利点を確認できますが、このアプローチの素晴らしさを示すテクニックが 1 つあります。単体テスト + モッキング。

于 2012-12-15T08:43:54.200 に答える