簡體   English   中英

ASP.NET MVC:“視圖必須是愚蠢的”是正確的說法嗎?

[英]ASP.NET MVC: Is "views must be dumb" correct statement?

Web 上 MVC 的大多數優秀參考資料都強烈建議“視圖必須是愚蠢的”。 它不應該包含任何邏輯。 當我嘗試實現它時,這似乎無效。

  • 我的一些視圖只顯示學生的名字,有些只顯示姓氏,有些只顯示全名。 我的數據庫(以及 POCO 和 DTO)將名稱存儲在單獨的組件中。 我認為格式化名稱的最佳位置是視圖。
  • 我的觀點在客戶端的某些操作上發生了變化,而不會影響服務器。 例如,單擊某個按鈕時,它會隱藏視圖的某些部分並顯示其他部分並禁用某些控件。 或者另一個按鈕打開新窗口並接受一些輸入並驗證它。 此輸入永遠不會發送到服務器; 它僅對某些客戶端活動有用。
  • 我在服務器端進行了驗證。 但只是為了將命中保存到服務器,我還在客戶端進行了驗證。
  • 使用 KnockoutJS 進行數據綁定。
  • 根據從服務器收到的數據(開始和結束日期),我在客戶端生成表格以顯示該時段的部分,每個部分切片 1 小時。 這是像 GUI 一樣調度的東西。 為了實現這一點,我需要進行日期和時間計算。 當我在石器時代(ASP.NET WebForms)時,我在服務器端生成這個表; 我知道你很震驚。 我將它轉移到 JS 以提高性能。
  • 在 SPA 中,視圖通過 AJAX 僅從服務器獲取必要的數據來保存大部分邏輯。

我可以在這里放許多其他類似的例子,這些例子迫使我考慮一些邏輯。 考慮到視圖仍然保持邏輯並且JS的使用日益增加,我們還能說“視圖必須是啞巴”是正確的說法嗎?

關於上述幾點解釋相同的一些細節將有所幫助。

筆記:

  • 盡管我的問題是基於 ASP.NET,但我希望得到僅引用 MVC 作為設計模式的答案; 無論我使用什么技術。 因此,請不要建議進行驗證的另一種方法是什么。 以上幾點只是為了說明一些需要邏輯的情況。
  • 我如何實施上述幾點可能有問題。 但我唯一的觀點是,JS 的使用(並因此將邏輯置於視圖中)正在增加。
  • 如果我以錯誤的方式實施,歡迎大家反駁上述觀點; 只是不要以這種方式重定向整個討論。

編輯 1: @kayess:是的,我有模型和視圖模型,這在 MVC 中很明顯。 與特定視圖密切相關且無法重用的服務器邏輯放在 ViewModel 中。 可重用的領域邏輯的主要部分放在模型中。 即使在有了 ViewModels 之后,我還是會喜歡在客戶端做很多事情。 關於縮小問題,這個問題的基本答案是“是”或“否”。 其他細節將只是為了支持答案。 我不認為這會吸引意見因為必須有一些我還沒有完全理解的關於 MVC 視圖的東西。 回答這個問題的人只需要向我指出這一點

我普遍認為通過“意見必須是啞巴”的意思明確的意見服務器端部分。 在視圖中使用 TypeScript/JS 是完全正常的。 但是,我不希望在從數據庫中獲取記錄的視圖中有幾十行 C#。

但是,有一些非常簡單的邏輯,例如以下內容是很常見的:

@{
    if(user.IsLoggedIn)
    {
        <span>You have new messages!</span>
    }
    else
    {
        <span>You need to login to view messages.</span>
    }
}

然而,服務器端視圖代碼不應該比這更復雜,因為這打破了分離問題的整個點,並具有適當的抽象和設計模式等,並且變得不可維護。

另請參閱: 關於“添加視圖”的 Microsoft 文檔

可能是任何技術都有一套支持不同概念的理論,就像你說的觀點應該是愚蠢的,模型的擁護者應該是愚蠢的。

這里的想法是讓您的視圖模型在需要時處理操作,並讓您的視圖引用視圖模型。 所以這種變化是中心化的。

我相信你已經在這樣做了。

這是進一步接受的答案。
我認為我們應該將渲染邏輯集中到View部分,而不是它們的ViewModel部分。 即使理論表明“視圖必須是愚蠢的”,這也提供了一些實際的優點:

1)由於邏輯較少,因此服務器上的CPU周期較低。

2)節省帶寬,因為更少的數據通過有線傳輸。

3)更好的關注點分離,因為表示邏輯集中在視圖上。 服務器只需要將數據傳遞到客戶端,就可以有效地簡化服務器端的編碼復雜度。

結論:

讓理論說“觀點必須愚蠢”。 將表示邏輯放在客戶端是很好的實用方法。

雖然這是一個老問題並且有一個公認的答案,但我想補充一些任何答案中未涵蓋的要點。

我認為您忽略了可以將更多邏輯推送到域模型的情況。 例如,您提到了“姓名”的概念,並且必須在視圖中使用條件邏輯來決定是顯示名字、姓氏還是全名。 我的域模型中有一個名為 Name 的類。 它包含了 FirstName、LastName 和 FullName 的邏輯,如下所示:

public class Name
{  
    public Name(string firstName, string lastName)
    {
        this.FirstName = firstName;           
        this.LastName = lastName;            
    }

    public string FirstName { get; }       
    public string LastName { get; }      
   
    public string FullName
    {
        get { return $"{this.FirstName} {this.LastName}"; }
    }        
}

在我的 UI 中,我有帶有我需要的任何名稱屬性的 ViewModel。 當我將域模型轉換為視圖模型時,我的轉換邏輯會告訴 ViewModel 要使用哪個屬性。 如果我需要全名,我使用 Name.FullName。 如果我只需要名字,我使用 Name.Firstname。 在任何時候我都不需要在我的視圖中放置關於名稱的條件邏輯。

此外,您可以使用自定義助手、格式化程序和擴展來封裝視圖的可重用邏輯。 例如,我有用於格式化電話號碼、地址等的實用程序,因此我不必將此邏輯放在每個需要它的視圖中。 我的 UI 中還有一個分頁模塊,用於封裝分頁,因此除了調用分頁器外,我的視圖中不必有分頁邏輯。

部分視圖也很有幫助。 例如,從接受的答案中,我會將以下內容放在部分視圖中,並在每個視圖中調用它,而不是在每個視圖中重復條件邏輯:

@{
    if(user.IsLoggedIn)
    {
        <span>You have new messages!</span>
    }
    else
    {
        <span>You need to login to view messages.</span>
    }
}

我的觀點是,你可以做很多事情來將邏輯移出視圖以保持它們的愚蠢。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM