2012-07-31 13 views
10

我有一個設計得非常好的架構,其中控制器轉到訪問與數據庫通信的存儲庫的服務。如何保持ASP.NET MVC中的控制器小?

這樣,在控制器邏輯被保持在最小,但我仍然有代碼非常微妙件執行一些任務,如

  • 驗證模型
  • 安排的動作方法參數
  • 用這些參數調用一些服務,也許驗證結果並返回視圖如果模型是現在無效
  • 最後從服務的結果產生一個模型,並返回該模型。

根據服務返回的「狀態」,一些較長的情況會做不同的事情。

這裏有幾個例子:

[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項目作爲一項規則,或者他們實際上可能是域或其他項目的一部分。

我不確定我可以對預覽操作做很多事情,除了可能使用接收鏈接的預覽模型,並截斷描述,但這樣可以節省兩行。

模型轉換器應該可能在別的地方,但我對於應該在哪裏卻一無所知。

想到的另一點是,如果我應該使用關鍵字partial來分割此控制器(將其用於除自動生成的類之外的其他項目是否是一種不好的做法?),或者添加使用不同控制器的路由,具體取決於請求什麼操作或者使用了什麼http方法,處理這個問題的常用方法是什麼?

+0

只是個人喜好,但你可以使用switch語句而不是if .. else if ...等等。 – 2012-07-31 20:50:22

回答

4

這已被多次詢問:
Business logic in the controller
Where should I put my controller business logic in MVC3
Keep Controllers Thin

除了在別處寫:
ASP MVC Best Practices - Skinny Controllers
Keep Controllers Thin

社區似乎對這種邏輯屬於控制器以外屬於很好的共識。一般在模型(或ViewModel)中,但某處處於業務層。

作爲最後的註釋,對於非自動生成的代碼使用partials並不鼓勵。如果分割事物是有意義的,那就這樣做。想想你分裂它的原因是什麼。這將是一個逐個案例。

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

0

控制器將不包含任何域邏輯

控制器應該只負責:

驗證輸入

調用模型製備視圖

返回視圖或重定向到另一個動作

如果您正在做其他事情,那麼您在錯誤的地方做它,這是您在Controller中執行的Model責任。

如果您遵循此規則,您的操作方法將不會超過20 - 25行代碼。伊恩庫珀擁有優秀的職位Skinny Controller Fat Model,請閱讀。