Asp.net-Mvc

哪一層應該建構一個視圖模型?

  • March 24, 2020

我正在使用S#arp 架構。我不記得在哪裡讀到了,但我知道視圖模型應該儲存在服務層,並且您的視圖應該將視圖模型送出給服務進行處理。

那麼我的問題是:哪一層應該建構視圖模型?它應該在服務層,由控制器請求嗎?或者控制器應該自己建構視圖模型?還有一個關於更新視圖模型的問題,因為如果它包含集合,並且模型狀態無效,您還需要重新填充任何列表。

有什麼建議?

我在控制器內創建視圖模型。控制器獲取域實體(通過模型綁定器從數據庫中檢索),可能在其他視圖模型中,聯繫儲存庫以獲取其他數據,創建新的視圖模型,並將其傳遞給適當的視圖(或重定向)。因此控制器的職責是根據輸入的域數據準備視圖/視圖模型(當然還要處理錯誤)。

您可以在此處尋找在控制器中創建視圖模型的替代方法。這種技術將視圖模型的創建移到動作之外,因此控制器動作不僅接受純域對象,而且還返回純域對象。我不會說它在所有情況下都適用,但學習起來非常有趣。

上述與 AutoMapper 相關的技術也提出了類似於“我應該將視圖模型傳遞給服務層”的問題。不,你沒有。如果您需要將復雜對像傳遞給服務或域層,您可以在適當的服務/域層中定義此對象,並使用它將數據傳遞給這些層。然後可以輕鬆地將這個對象映射到視圖模型或從視圖模型映射(例如,使用 AutoMapper)。但是你的下層(服務/域)不應該耦合到上層(視圖/控制器)。在這種情況下不是,在其他情況下也不是。從來沒有低級別的層應該依賴於它們上面定義的東西。

按照傳統的方法或理論,ViewModel 應該是使用者界面(UI)層的一部分。至少名字是這樣說的。

但是當你開始使用 Entity Framework、MVC、Repository 等自己實現它時,你就會意識到別的東西。

必須有人用 ViewModels 映射實體模型(最後提到的 DTO)。這應該在 A)UI 層(由控制器)中完成,還是在 B)服務層中完成?

我選擇選項 B。選項 A 是一個禁忌,因為幾個實體模型組合在一起形成一個 ViewModel 很簡單。我們可能不會將不必要的數據傳遞給 UI 層,而在選項 B 中,服務可以處理數據並在映射(到 ViewModel)後僅將所需/最少的數據傳遞給 UI 層。

但是,讓我們假設我們使用選項 A,我們將 ViewModel 放在 UI 層(而將實體模型放在服務層)。

如果Service層需要映射到ViewModel,那麼Service層需要在UI層訪問ViewModel。哪個圖書館/項目?Viewmodel 應該在 UI 層的一個單獨的項目中,這個項目需要被 Service Layer 引用。如果 ViewModel 不在單獨的項目(.dll)中,則存在循環引用,所以不行。讓服務層訪問 UI 層看起來很尷尬,但我們仍然可以應付它。

但是,如果有另一個 UI 應用程序使用此服務怎麼辦?如果有移動應用怎麼辦?ViewModel 可以有多大不同?服務應該訪問同一個視圖模型項目嗎?還是所有 UI 項目都會競爭?

在這些考慮之後,我的答案是將 Viewmodel 項目放在服務層中。無論如何,每個 UI 層都必須訪問服務層!並且可能有很多類似的 ViewModel 都可以使用(因此服務層的映射變得更容易)。這些天映射是通過 linq 完成的,這是另一個優點。

最後是關於 DTO 的討論。還有關於 ViewModels 中的數據註釋。帶有數據註釋的 ViewModel 不能駐留在服務層。因此,DTO 將是 ViewModel 的精確副本,兩者之間存在一對一的映射(例如使用 AutoMapper)。同樣,DTO 仍然具有 UI(或多個應用程序)所需的邏輯,並且駐留在服務層中。而 UI 層 ViewModel 只是從 DTO 複製數據,並添加了一些“行為”(例如:屬性)。

$$ Now this discussion is about to take an interesting turn read on…:I $$ 並且不要認為數據註釋屬性僅適用於 UI。如果您使用 System.ComponentModel.DataAnnotations.dll 限制驗證,則相同的 ViewModel 也可以用於前端和後端驗證(從而刪除 UI-residing-ViewModel-copy-of-DTO)。此外,屬性也可以在實體模型中使用。例如:使用 .tt,可以使用驗證屬性自動生成實體框架數據模型,以在發送到後端之前執行一些數據庫驗證,例如最大長度。另一個優點是,如果 DB 中的後端驗證發生變化,那麼 .tt(讀取 DB 細節並為實體類創建屬性)將自動選擇它。這也會迫使 UI 驗證單元測試失敗,這是一個很大的優勢(因此我們可以更正它並通知所有 UI/消費者,而不是意外忘記和失敗)。是的,討論正朝著良好的框架設計方向發展。如您所見,它們都是相關的:分層驗證、單元測試策略、記憶體策略等。

雖然與問題沒有直接關係。‘ViewModel Façade’ (viewmodel inside another viewmodel) & ‘command’ 在此必看頻道 9 連結也值得探索(@11:48 開始)

引用自:https://stackoverflow.com/questions/2720078