10

私は、コントローラーがデータベースと通信するリポジトリーにアクセスするサービスにアクセスする、非常によく設計されたアーキテクチャーを持っています。

そのため、コントローラーのロジックは最小限に抑えられていますが、次のようないくつかのタスクを実行する非常に微妙なコードがまだあります。

  • モデルを検証する
  • アクションメソッドの引数を配置します
  • これらの引数を使用してサービスを呼び出し、結果を検証して、モデルが無効になった場合はビューを返す可能性があります
  • 最後に、サービスの結果からモデルを作成し、それを返します。

いくつかのより長いケースは、サービスによって返される「ステータス」に応じて異なることを行います。

ここにいくつかの例があります:

[HttpPost]
[AjaxOnly]
[Authorize]
public JsonResult Preview(string input)
{
    LinkResult parsed = linkService.ParseUserInput(input);
    if (parsed.Result == LinkParseResult.Used)
    {
        long? postId = parsed.Link.PostId;
        if (postId.HasValue)
        {
            Post post = postService.GetById(postId.Value, false);
            return Json(new
            {
                faulted = "used",
                link = DetailsRoute(post),
                id = postId
            });
        }
        else
        {
            return Json(new { faulted = "invalid" });
        }
    }
    else if (parsed.Result == LinkParseResult.Invalid)
    {
        return Json(new { faulted = "invalid" });
    }
    else
    {
        Link link = parsed.Link;
        if (link.Description != null && link.Description.Length > 200)
        {
            link.Description = link.Description.Substring(0, 200);
        }
        return AjaxView(link);
    }
}

および(Postドメインに由来しPostModel、ビューモデルです)

private PostModel PostModelConverter(Post post)
{
    Link link = post.Link;
    if (link == null)
    {
        throw new ArgumentException("post.Link can't be null");
    }
    if (link.Type == LinkType.Html)
    {
        return new PostedLinkModel
        {
            Description = link.Description,
            PictureUrl = link.Picture,
            PostId = post.Id,
            PostSlug = postService.GetTitleSlug(post),
            Timestamp = post.Created,
            Title = link.Title,
            UserMessage = post.UserMessage,
            UserDisplayName = post.User.DisplayName
        };
    }
    else if (link.Type == LinkType.Image)
    {
        return new PostedImageModel
        {
            PictureUrl = link.Picture,
            PostId = post.Id,
            PostSlug = postService.GetTitleSlug(post),
            Timestamp = post.Created,
            UserMessage = post.UserMessage,
            UserDisplayName = post.User.DisplayName
        };
    }
    return null;
}

これにより、ビューモデルが実際にWebプロジェクトに含まれるべきか、それとも実際にドメインまたは他のプロジェクトの一部である可能性があるかについての疑問が生じます。

リンクを受け取り、説明を切り捨てるPreviewModelを使用する以外に、プレビューアクションについて多くのことができるかどうかはわかりませんが、2行節約できます。

モデルコンバーターはおそらくどこかにあるはずですが、それがどこにあるべきかについては私にはわかりません。

頭に浮かぶもう1つのポイントは、partialキーワードを使用してこのコントローラーを分割するか(自動生成されたクラス以外の目的でこれを使用するのは悪い習慣ですか?)、要求されたアクションに応じて異なるコントローラーを使用するルートを追加するかどうかです。どのhttpメソッドが使用されていますか、それを処理する通常の方法は何ですか?

4

3 に答える 3

5

これは何度か尋ねられています:コントローラーのビジネス ロジック MVC3 の
コントローラーの
ビジネス ロジックはどこに配置すればよいですか?
コントローラーを薄く保つ

他の場所についても書かれています:
ASP MVCのベストプラクティス - スキニーコントローラー
はコントローラーを薄く保つ

コミュニティは、この種のロジックがコントローラーの外部に属しているという点で、良い合意を得ているようです。通常はモデル (または ViewModel) にありますが、ビジネス レイヤーのどこかにあります。

最後の注意として、partials自動生成されていないコードに使用することはお勧めできません。物事を分割することが理にかなっている場合は、分割してください。それを分割する理由が何であるかを考えてみてください。これはケースバイケースのようなものになるでしょう。

于 2012-07-31T20:43:37.747 に答える
2
private PostModel PostModelConverter(Post post)
{
    Link link = post.Link;
    if (link == null)
    {
        throw new ArgumentException("post.Link can't be null");
    }
    if (link.Type == LinkType.Html)
    {
        var model = AutoMapper.Map<PostedLinkModel>(post);
        model.PostSlug = postService.GetTitleSlug(post);
        return model;
    }
    else if (link.Type == LinkType.Image)
    {
        var model = AutoMapper.Map<PostedImageModel>(post);
        model.PostSlug = postService.GetTitleSlug(post);
        return model;
    }
    return null;
}

http://www.viddler.com/v/b568679c

于 2012-07-31T20:42:51.030 に答える
0

コントローラにはドメイン ロジックが含まれていません

コントローラーは、次のことのみを担当する必要があります。

入力の検証

モデルを呼び出してビューを準備する

ビューを戻すか、別のアクションにリダイレクトする

あなたが間違った場所でそれをしている他のことをしているなら、それはむしろコントローラであなたがしているモデルの責任です。

このルールに従えば、アクション メソッドのコードは 20 ~ 25 行以下になります。Ian Cooper の優れた投稿Skinny Controller Fat Modelを読んでください。

于 2012-08-01T09:25:11.980 に答える