Pro ASP.NET Core MVC 6th 第三章

第三章 MVC 模式,項目和約定

在深刻了解ASP.NET Core MVC的細節以前,我想確保您熟悉MVC設計模式背後的思路以及將其轉換爲ASP.NET Core MVC項目的方式。 您可能已經瞭解本章中討論的一些想法和約定,特別是若是您已經完成了高級ASP.NET或C#開發。 若是沒有,我鼓勵你仔細閱讀 - 深刻地理解隱藏在MVC背後的東西能夠幫助你在通讀本書時更好地與MVC框架的功能聯繫起來。html

MVC的歷史

模型視圖控制器模式起源於20世紀70年代後期,來自施樂PARC的Smalltalk項目,它被設想爲組織一些早期的GUI應用程序。 原始MVC模式的一些細節與Smalltalk特定的概念(如屏幕和工具)有關,但更普遍的概念仍然適用於應用程序,而且它們特別適合於Web應用程序。程序員

理解MVC模式

在高層次上,MVC模式意味着MVC應用程序將被分紅至少三個。數據庫

  • 模型,其中包含或表示用戶使用的數據
  • 視圖,用於將模型的某些部分呈現爲用戶界面
  • 控制器處理傳入請求,對模型執行操做,並選擇要呈現給用戶的視圖 每一塊MVC架構都有明確的界定和獨立的,這被稱爲分離問題。 在模型中操縱數據的邏輯只包含在模型中; 顯示數據的邏輯只在視圖中,處理用戶請求和輸入的代碼只包含在控制器中。 每一個部分之間有明確的劃分,您的應用程序將更容易維護並延長其使用壽命,不管它最終變得多麼複雜。
理解模型

模型 - MVC中的M - 包含用戶使用的數據。有兩種普遍的模型:視圖模型,它們表明從控制器傳遞到視圖的數據。領域模型:業務領域中的數據以及操做,轉換和規則,用於建立、存儲並操縱該數據,統稱爲模型邏輯。 模型是您的應用程序工做的環境的定義。例如,在銀行應用程序中,該模型表示應用程序支持的銀行中的全部內容,如賬戶、總賬和客戶的信用限額以及可用於存入資金並從帳戶中提款等相似模型中數據的操做。該模型還負責保存數據的總體狀態和一致性 - 確保全部事務被添加到客戶不會比銀行有權得到更多的錢或者比銀行更多的錢提取更多的錢。 對於MVC模式中的每一個組件,我將描述它應該包括哪些東西和不該該包括哪些東西。json

使用MVC模式構建的應用程序中的模型應該:設計模式

  • 包含域數據
  • 包含用於建立,管理和修改域數據的邏輯
  • 提供一個清晰的API,以暴露模型數據和操做

模型不該該:瀏覽器

  • 揭示如何獲取或管理模型數據的細節(換句話說,細節的數據存儲機制不該該暴露給控制器和視圖)
  • 包含根據用戶交互轉換模型的邏輯(由於這是控制器的工做)
  • 包含向用戶顯示數據的邏輯(應由視圖負責) 確保模型與控制器和視圖隔離的好處是可讓測試變得更容易(我在第7章中描述單元測試),而且可讓整個應用程序更簡單。

提示:許多剛接觸MVC的開發人員對在數據模型中包含邏輯感到困惑,認爲MVC模式的目標是將數據與邏輯分離。 這是一個誤會:MVC模式的目標是將應用程序分紅三個功能區域,每一個功能區域能夠包含邏輯和數據。 目標不是消除模型中的邏輯。 而是確保模型只包含用於建立和管理模型數據的邏輯。架構

理解控制器

控制器是MVC模式中的結締組織,用做數據模型和視圖之間的通道。 控制器定義提供在數據模型上運行的業務邏輯的動做,並向用戶提供查看顯示的數據。框架

使用MVC模式構建的控制器應該是:工具

  • 根據用戶交互包含更新模型所需的操做

控制器不該該:佈局

  • 包含管理數據外觀的邏輯(即視圖的工做)
  • 包含管理數據持久性的邏輯(即模型的工做)
理解視圖

視圖包含向用戶顯示數據或從用戶捕獲數據所需的邏輯,以即可以經過控制器操做進行處理。

視圖應該:

  • 包含向用戶呈現數據所需的邏輯和標記

視圖不該該:

  • 包含複雜的邏輯(放在控制器中更好)
  • 包含建立,存儲或操縱域模型的邏輯 視圖能夠包含邏輯,但應該簡單,且須謹慎使用。除了最簡單的方法調用或表達式,在視圖中放置任何東西,會使整個應用程序更難測試和維護。

MVC的在ASP.NET上的實現

顧名思義,ASP.NET Core MVC將抽象MVC模式應用於ASP.NET和C#開發的世界。 在ASP.NET Core MVC中,控制器是C#類,一般派生自Microsoft AspNetCore.Mvc.Controller類。 從Controller派生的類中的每一個公共方法都是與URL相關聯的行動方法。 當請求發送到與行動方法相關聯的URL時,執行該行動方法中的語句,以便對域模型執行某些操做,而後選擇要向客戶端顯示的視圖。 圖3-1顯示了控制器,模型和視圖之間的交互。

控制器,模型和視圖之間的交互

圖3-1 控制器,模型和視圖之間的交互。

ASP.NET Core MVC使用一種稱爲Razor的視圖引擎,它是負責處理視圖的組件,以便爲瀏覽器生成響應。 Razor視圖是包含C#邏輯的HTML模板,用於處理模型數據以生成響應模型更改的動態內容。 我將在第5章中解釋Razor的做用。 ASP.NET Core MVC不會對領域模型的實現施加任何限制。 您可使用常規C#對象建立模型,並使用任何數據庫,對象關聯映射框架或.NET支持的其餘數據工具來實現持久性。

MVC與其餘模式的對比

固然,MVC不是惟一的軟件架構模式。 還有不少其餘的,其中有些是或至少已經很是受歡迎。 您能夠經過查看替代方案瞭解有關MVC的許多內容。 在如下部分中,我簡要介紹了構建應用程序的不一樣方法,並將其與MVC進行對比。 一些模式與MVC有些許的差別,而另外一些則徹底不同。

我不是說MVC是最完美的模式。 我支持採起最佳方法解決手頭問題。 有些狀況下,某些模式與MVC同樣好或可能更好。 我鼓勵您在選擇模式時作出明智的選擇。 您正在閱讀本書的事實代表,您已經決定使用MVC模式了,可是保持開闊的視野對你老是有好處的。

理解Smart UI 模式

最多見的設計模式之一就是智能用戶界面(smart UI)。大多數程序員在職業生涯中的某個時候建立​​了一個智能UI應用程序 - 我固然有。若是您已經使用Windows窗體或ASP.NET Web窗體,那麼您也這樣作了。 要構建一個智能UI應用程序,開發人員一般將一組組件或控件拖到設計表面或畫布上構建用戶界面。控件經過發出按鈕按壓,擊鍵,鼠標移動等事件來報告與用戶的交互。開發人員添加了一系列事件處理程序來響應這些事件的代碼;這些是在發出特定組件上的特定事件時調用的小塊代碼。這將建立一個單片應用程序,如圖3-2所示。處理用戶界面和業務的代碼都是混合在一塊兒的,沒有任何分離的問題。定義數據輸入的可接受值而且查詢數據或修改用戶賬戶的代碼最終以小部分結束,並按預期的順序耦合在一塊兒。

fig.3-2

圖3-2 Smart UI 模式

智能UI是簡單項目的理想選擇,由於您能夠快速得到一些好的結果(相比之下,在MVC開發中,正如你將在第8章中看到的那樣,須要在交付結果前進行大量的初始投資)。智能UI也適用於用戶界面原型。這些設計UI工具能夠真的很好,若是你和客戶坐在一塊兒,想要捕捉到外觀和流程的要求,一個智能的UI工具能夠快速有效地生成和驗證不一樣的想法。Smart UI最大的缺點是難以維護和擴展。混合領域模型和業務邏輯代碼與用戶界面代碼致使代碼冗餘,其中相同的業務邏輯被複制和粘貼以支持新添加的組件。找到全部重複的部分並修復可能很困難。添加新功能而不會破壞現有的功能幾乎是不可能的。測試智能UI應用程序也可能很困難,惟一的方法是模擬用戶交互,那很是不理想,提供全面測試覆蓋更是不太可能。 在MVC的世界中,Smart UI一般被稱爲反模式:應該不惜一切代價避免。這種反感來自,人們花了一半的職業生涯嘗試開發和維護智能UI應用程序,後來結果卻一團糟,後來人們才發現MVC是一個更好的方案。 個人意思是說,拒絕智能UI模式是錯誤的。Smart UI模式並不是都那麼糟糕,它有好的方面。Smart UI應用程序快速且容易開發。組件和設計工具生產者已經爲開發作出了很大的努力。開發體驗是愉快的,甚至最無經驗的程序員能夠在短短几個小時內產生一些專業而又合理的東西。

Smart UI應用程序的最大弱點 - 可維護性 - 在小型開發工做中不會出現。 若是您正在爲小客戶製做一個簡單的工具,Smart UI應用程序能夠是一個很好的解決方案。 MVC應用程序太複雜太煩人。

理解模型-視圖體系結構

在Smart UI應用程序中容易出現維護問題的部分是業務邏輯,它分散在整個應用程序中,使得修改或添加功能十分麻煩。 模型-視圖架構改進了好多,它將業務邏輯轉化爲單獨的域模型。 這樣數據、進程和規則都集中在應用程序的一部分中,如圖3-3所示。

fig.3-3圖 3-3 模型-視圖模式

模型視圖架構能夠是單片智能UI模式的改進 - 例如,更容易維護,可是會出現兩個問題。 首先是由於UI和領域模型是緊密結合的,因此在這二者之間進行單元測試是很困難的。 第二個問題來自實踐,而不是模式的定義。 該模型一般包含大量的數據訪問代碼 -雖然不老是這樣,但一般是- 這意味着數據模型不只包含業務數據,操做和規則。

理解經典的三層架構

爲了解決模型視圖架構的問題,三層模式將持久性代碼與域模型分離,並將其放置在稱爲數據訪問層(DAL)的新組件中。 如圖3-4所示。

fig.3-4圖 3-4 三層架構

三層架構是業務應用程序中使用最普遍的模式。 它對UI的實現沒有任何限制,而且提供了很好的分離關注點,而不會太複雜。 並且能夠建立DAL,使單元測試相對容易。 您能夠看到經典三層應用程序和MVC模式之間的明顯類似之處。 不一樣的是,當UI層直接耦合到點擊事件GUI框架(如Windows窗體或ASP.NET Web窗體)時,幾乎不可能執行自動化單元測試。 並且由於三層應用程序的UI部分可能很複雜,因此有不少代碼不能被嚴格的測試。

在最糟糕的狀況下,三層架構在UI層面缺少執行規則意味着許多這樣的應用程序最終都是虛擬假裝的Smart UI應用程序,並無真正的關注分離。 這給了最糟糕的可能結果:一個很是複雜的,不可測試的,不可維護的應用程序。

理解MVC變種

我已經描述了MVC應用程序的核心設計原則,特別是適用於ASP。 NET Core MVC。 其餘人以不一樣的方式來解釋模式的各個方面,並添加到MVC中,以適應其項目的範圍和主題。 在如下部分中,我簡要介紹一下關於MVC主題的兩個最流行的變體的概述。 瞭解這些變體對於使用ASP.NET Core MVC並非必不可少的,可是爲了知識的完整,我將它包含進來,由於這涉及到大多數軟件模式討論中使用的術語。

理解Model-View-Presenter 模式

模型視圖呈現器(MVP)是MVC的一個變體,旨在更容易地與諸如Windows窗體或ASP.NET Web窗體之類的狀態GUI平臺相配合。這是值得嘗試的,可以得到最好的Smart UI模式的優勢並且不會帶來問題。 在這種模式中,演示者(Presenter)與MVC中的控制器具備相同的職責,但與有狀態視圖的關係也更爲直接,對用戶的輸入的值和操做可直接在UI組件中顯示。 這種模式有兩種實現方式:

  • 被動視圖實現,視圖不包含邏輯。該視圖是由演示者直接操縱的用於UI控件的容器。
  • 監督控制器實現,視圖負責展示邏輯的元素(如數據綁定),而且已經從域模型中引用了數據源。 這兩種方法的區別在於視圖的智能化程度。不管哪一種方式,Presenter都從GUI框架中解耦,這使得Presenter邏輯更簡單,適合於單元測試。
理解Model-View-View Model模式

模型視圖模型(MVVM)模式是MVC最近的一個變化。 它源於Microsoft,並在Windows Presentation Foundation(WPF)中使用。 在MVVM模式中,模型和視圖與MVC中具備相同的角色。 不一樣之處在於MVVM中視圖模型的概念,它是用戶界面的抽象表示,一般是一個C#類,用於顯示要在UI中顯示的數據的屬性,以及能夠從UI調用的數據的操做 。 與MVC控制器不一樣,MVVM視圖模型不存在視圖(或任何特定UI技術)的概念。 MVVM視圖使用WPF綁定功能將視圖中的控件(下拉菜單中的項目或按下按鈕的效果)暴露的屬性與視圖模型公開的屬性進行雙向關聯。

提示:MVC模式還使用術語view模型,可是指的是一個簡單的模型類,僅用於將數據從控制器傳遞到視圖,而不是域模型,這些模型是數據,操做和規則的複雜表示。

理解ASP.NET Core MVC 工程

當您建立一個新的ASP.NET Core MVC項目時,Visual Studio會爲您提供項目中所需的初始內容的一些選擇。這個想法是爲了減輕新開發人員的學習過程,併爲常見的功能和任務應用一些節省時間的最佳實踐。我不是這種代碼模具方式的粉絲。意圖是好的,但執行老是很讓人崩潰。我最喜歡ASP.NET和MVC的特色之一就是我在裁剪平臺時有多大的靈活性來適應個人開發風格。 Visual Studio建立和填充的項目,類和視圖使我感到是在別人的風格下工做。我也發現內容和配置太通用,太平淡,沒法使用。微軟不可能知道須要什麼樣的應用程序,因此它涵蓋了全部的基礎,可是以這樣的通常化方式,我最終只是刪除默認內容。 個人建議(給任何提出錯誤的人)是從一個空項目開始,並添加所需的文件夾,文件和包。不只您將更多地瞭解MVC的工做原理,並且您能夠徹底控制您的應用程序所包含的內容。可是,個人想法可能不適合你。您可能會發現模板比我更加有用,特別若是您是ASP.NET的新手,而且還沒有開發出適合您的開發樣式。您可能還會發現項目模板是一個有用的資源和創意來源,儘管在徹底瞭解應用程序的工做原理以前,您應該謹慎地嚮應用程序添加任何功能。

創建工程

當您首次建立新的ASP.NET Core項目時,您能夠選擇如下三個基本的起點:空模板,Web API模板和Web應用程序模板,如圖3-5所示。

fig.3-5

圖3-5 ASP.NET 工程模板

空項目模板包含ASP.NET Core的管道,但不包括MVC應用程序所需的庫或配置。 Web API項目模板包括ASP.NET Core和MVC,其中包含示例應用程序,演示如何從客戶端接收和處理Ajax請求。 Web應用程序項目模板包括ASP.NET Core和MVC,其中包含演示如何生成HTML內容的示例應用程序。 Web API和Web應用程序模板能夠配置不一樣的方案來驗證用戶並受權他們訪問應用程序。 項目模板能夠給人須要遵循特定的路徑來建立某種ASP.NET應用程序的印象,但事實並不是如此。模板僅僅是相同功能的不一樣起點,您可使用任何模板添加所需的任何功能。例如,第20章中,我解釋瞭如何處理的Ajax請求以及第28-30頁的身份驗證和受權,全部這些都是從空項目模板開始的。

所以,項目模板之間的真正區別是Visual Studio在建立項目時添加的庫,配置文件,代碼和內容的初始集合。最簡單的模板(空)和最複雜(Web應用程序)之間存在不少差別,如圖3-6所示,它顯示了在建立項目以後的解決方案資源管理器。對於Web應用程序模板,我不得不將解決方案資源管理器集中在不一樣的文件夾上,由於單個列表對於打印頁面來講太長。

fig.3-6

圖3-6 空項目模板和Web應用模板中的默認內容

Web應用程序模板添加到項目中的額外文件看起來使人望而生畏,但其中一些只是佔位符或經常使用功能的示例實現。 一些其餘文件設置MVC或配置ASP.NET。 還有一些是客戶端庫,它們將被併入應用程序生成的HTML中。 文件列表如今可能看起來很崩潰,可是在完成這本書時你會明白所作的一切。

不管您用於建立工程的模板如何,都會顯示一些常見的文件夾和文件。 工程中的某些項具備特殊角色,他們是硬編碼到ASP.NET中或MVC中或Visual Studio提供支持的工具中。 其餘的則受到大多數ASP.NET項目或MVC項目中使用的命名約定的約束。 在表3-1中,我描述了您將在ASP.NET Core MVC項目中遇到的重要文件和文件夾,其中有些文件和文件夾默認不存在於項目中,但在後面的章節中我將介紹。

Table 3-1 MVC 工程中的文件項彙總

文件夾或文件
描述

/Areas
區域是將大型應用程序分割成較小的部分的一種方式。 我在第16章描述區域。

/Dependencies
「依賴關係」項目提供項目依賴的全部包的詳細信息。我在第6章中描述Visual Studio使用的包管理器。

/Components
這是定義用於顯示自包含功能(如購物車)的視圖組件類。 我在第22章中描述視圖組件。

/controllers
這是控制器類所在的地方。 這是一個約定,您能夠將控制器類放在您喜歡的任何地方,由於它們都被編譯成同一個程序集。 我在第17章詳細描述了控制器。

Data
這是定義數據庫上下文類的地方,儘管我更傾向於忽略此約定,並在Models文件夾中定義它們,如第8章所示。

/Migrations
這是存儲數據庫模式的詳細信息,以即可以更新部署數據庫。 我在第12章中演示了部署的過程。

/Models
這裏放置視圖模型和域模型。 這是一個約定 您能夠在項目中的任何位置或單獨的項目中定義模型類。

/Views
該目錄包含視圖和部分視圖,一般在與它們相關聯的控制器上命名的文件夾中組合在一塊兒。 我在第21章詳細描述了視圖。

/Views/Shared
此目錄包含共享的佈局和視圖。 我在第21章詳細描述視圖。

/Views/_ViewImports.cshtml
該文件用於指定將包含在Razor視圖文件中的命名空間,如第5章所述。 它也用於設置標籤助手,如第23章所述。

/Views/_ViewStart.cshtml
該文件用於指定Razor視圖引擎的默認佈局,如第5章所述。

/bower.json
此文件默認隱藏。 它包含由Bower軟件包管理器管理的軟件包列表,如第6章所述。

/project.json
該文件指定了項目的一些基本配置選項,包括其使用的NuGet軟件包,如第6章所述。

/Program.cs
這個類配置了應用程序的託管平臺,如第14章所述。

/Startup.cs
該類配置應用程序,如第14章所述。

/wwwroot
這是靜態內容,如CSS文件和圖像所在的地方。 Bower包管理器、JavaScript和CSS包也在這裏,如第6章所述。

理解 MVC 約定

在MVC項目中有兩種約定。第一類只是建議您如何組織您的項目。例如,一般將您所依賴的第三方JavaScript和CSS包放在wwwroot/lib文件夾中。這是其餘MVC開發人員但願找到它們以及軟件包管理器安裝的地方。可是你能夠自由地重命名lib文件夾,或者徹底刪除它,並將你的包放在別的地方。只要您的視圖中的腳本和連接元素指向您所在的位置,MVC就會運行您的應用程序。 另外一種慣例來自於約定大於配置的原則,這是Ruby on Rails受歡迎的主要賣點之一。例如,約定大於配置意味着您不須要顯式地配置控制器及其視圖之間的關聯。您只需遵循一個特定的命名約定爲您的文件,一切都正常。在處理這種慣例時,改變項目結構的靈活性較小。如下部分將說明用於替代配置的約定。

提示:全部的約定都是能夠更改的,經過用你本身的MVC組件替換默認組件來實現。 我在本書中描述了不一樣的方法來解釋MVC應用程序的工做原理,但這些是大多數項目中將要處理的約定。

遵循控制器類的約定

Controller類的名稱以Controller結束,如ProductController,AdminController,和HomeController。 當從項目其餘地方引用控制器時,例如使用HTML幫助器方法時,您能夠指定名稱的第一部分(例如Product),MVC會自動將Controller添加到名稱中,並開始查找控制器類。

提示:您能夠經過建立一個模型約定來改變這一點,我在第31章中描述。

遵循視圖的約定

視圖放在文件夾/Views/Controllername。 例如,與ProductController類相關聯的視圖放在/Views/ Product文件夾。

提示:請注意,Views文件夾中省略了"Controller"單詞:/Views/Product,not/Views/ ProductController。 起初看起來彷佛是違反直覺的,但它很快就變得天然了。 MVC但願以該方法命名操做方法的默認視圖。 例如,與名爲List的動做方法關聯的默認視圖應該稱爲List.cshtml。 所以,對於ProductController類中的List操做方法,默認視圖預期爲/Views/Product/List.cshtml。 在動做方法中返回調用View方法的結果時使用默認視圖,以下所示:

return View();

你能夠用名字指定不一樣的視圖,像這樣:

return View("MyOtherView");

請注意,我不包括文件擴展名或視圖的路徑。 當尋找一個視圖時,MVC在控制器後面命名的文件夾中,而後在/Views/Shared文件夾中。 這意味着我能夠在/Views/Shared文件夾中放置多個控制器使用的視圖,而MVC會發現它們。

遵循佈局的約定

佈局的命名約定是使用文件前面加下劃線(_)字符,而且佈局文件放在/Views/Shared文件夾中。 默認狀況下,此佈局將應用於全部視圖/Views/_ViewStart.cshtml文件。 若是您不但願將默認佈局應用於視圖,則能夠更改ViewStart.cshtml中的設置(或徹底刪除該文件)以在視圖中指定其餘佈局,以下所示:

@{ Layout = "~/_MyLayout.cshtml"; }

或者你能夠不使用任何佈局,像下面這樣:

@{ Layout = null; }

總結

在本章中,我向您介紹了MVC架構模式,並將其與您以前看到或聽到的其餘模式進行了比較。 我討論了領域模型的重要性並引入了依賴注入,它容許您去分離組件以強制應用程序的各個部分之間的嚴格分隔。 在下一章中,我將解釋Visual Studio MVC項目的結構,並描述MVC Web應用程序開發中使用的基本C#語言特性。

相關文章
相關標籤/搜索