為什么需要了解ASP.NET Core MVC的前世今生


我們就擦肩而過(guò)了
有趣
有用
有態(tài)度
ASP.NET Core MVC 是一個(gè)微軟公司的web應(yīng)用開(kāi)發(fā)框架, 結(jié)合了MVC架構(gòu)的高效簡(jiǎn)潔, 敏捷開(kāi)發(fā)的思想和技術(shù), 以及.NET平臺(tái)最優(yōu)秀的部分. 在這一章中, 你將了解到微軟為什么要?jiǎng)?chuàng)建ASP.NET Core MVC, 將它和前輩以及替代品進(jìn)行比較, 最后瀏覽ASP.NET Core MVC的新特性.

了解ASP.NET Core MVC的歷史
最初的ASP.NET誕生于2002年, 當(dāng)時(shí)微軟想要保持傳統(tǒng)的桌面應(yīng)用開(kāi)發(fā)的霸主地位, 將因特網(wǎng)視為潛在威脅. 圖1-1展示了當(dāng)時(shí)微軟的技術(shù)棧.
ASP.NET Web Forms: 一組UI組件(如頁(yè)面, 按鈕等) 加上一個(gè)有狀態(tài)的面向?qū)ο蟮腉UI編程模型
ASP.NET: 一組在IIS中承載.NET應(yīng)用程序的方法, 使用HTTP請(qǐng)求和響應(yīng)進(jìn)行交互
.NET: 一個(gè)多語(yǔ)言代碼托管平臺(tái)(當(dāng)時(shí)是全新的, 本身就是一個(gè)里程碑)

ASP.NET Web Forms
微軟使用Web Forms技術(shù), 將用戶界面(UI)建模為服務(wù)端控制的對(duì)象的層次結(jié)構(gòu), 來(lái)隱藏本身便具有無(wú)狀態(tài)性的超文本傳輸協(xié)議(HTTP)和當(dāng)時(shí)許多開(kāi)發(fā)者不熟悉的超文本標(biāo)記語(yǔ)言(HTML). 每個(gè)控件都在各個(gè)請(qǐng)求之間跟蹤自己的狀態(tài), 在需要時(shí)將自己呈現(xiàn)為HTML, 并自動(dòng)將客戶端事件(如點(diǎn)擊按鈕)與相應(yīng)的服務(wù)端事件處理程序連接起來(lái). 事實(shí)上, Web Forms是一個(gè)巨大的抽象層, 用于在Web上呈現(xiàn)傳統(tǒng)的事件驅(qū)動(dòng)GUI.
這個(gè)想法基于一種讓W(xué)eb開(kāi)發(fā)感覺(jué)和桌面應(yīng)用開(kāi)發(fā)相同的理念. 開(kāi)發(fā)者可以從有狀態(tài)的UI角度來(lái)思考, 不需要考慮一系列獨(dú)立的HTTP請(qǐng)求和響應(yīng). 由此微軟可以將Windows桌面開(kāi)發(fā)大軍無(wú)縫過(guò)渡到Web應(yīng)用的新世界.

ASP.NET Web Forms 出了什么問(wèn)題?
傳統(tǒng)的ASP.NET Web Forms開(kāi)發(fā)在理論上是好的, 但是實(shí)際情況要復(fù)雜得多:
視圖狀態(tài)(View State)負(fù)擔(dān): 在請(qǐng)求之間維護(hù)狀態(tài)的機(jī)制(被稱為視圖狀態(tài), View State)導(dǎo)致服務(wù)端和客戶端之間的大塊數(shù)據(jù)傳遞, 即使在最平常的Web應(yīng)用中也會(huì)達(dá)到幾百KB的數(shù)據(jù)量. 并且這些數(shù)據(jù)在每個(gè)請(qǐng)求中都會(huì)跑一個(gè)來(lái)回, 導(dǎo)致響應(yīng)變慢, 又增加了服務(wù)器的帶寬占用.
頁(yè)面生命周期: 將客戶端事件連接到服務(wù)端事件處理程序代碼的機(jī)制是頁(yè)面生命周期的一部分, 很復(fù)雜也很脆弱. 基本沒(méi)有開(kāi)發(fā)者能在運(yùn)行時(shí)成功操作控件的層級(jí)關(guān)系而不產(chǎn)生試圖狀態(tài)錯(cuò)誤, 一些事件處理程序也會(huì)莫名其妙地失敗.
錯(cuò)誤的關(guān)注點(diǎn)分離: ASP.NET Web Forms的后端代碼模型提供了從HTML標(biāo)記中提取應(yīng)用程序代碼成為單獨(dú)的后端類的方法, 以分離邏輯層和表現(xiàn)層. 但事實(shí)上, 開(kāi)發(fā)人員更愿意在機(jī)型的后端類中將表現(xiàn)層代碼(如操作服務(wù)器端的控件樹(shù))和邏輯層代碼(如操作數(shù)據(jù)庫(kù)數(shù)據(jù))混合起來(lái). 這最終導(dǎo)致了應(yīng)用程序的脆弱和不智能.
對(duì)HTML的有限控制: 服務(wù)器端控件將自己渲染為HTML, 但不一定是你想要的HTML. 在ASP.NET的早期版本中, 輸出的HTML不滿足Web標(biāo)準(zhǔn), 也不能很好的使用層疊樣式表(CSS). 服務(wù)器端控件生成不可預(yù)知的復(fù)雜ID屬性, 很難被JavaScript獲取到. 這些問(wèn)題在最近的Web Forms發(fā)行版中有所改善, 但仍然很難獲取你所期望的HTML.
漏洞百出的抽象: Web Forms試圖盡可能地隱藏HTML和HTTP. 當(dāng)你嘗試實(shí)現(xiàn)自定義的行為時(shí), 經(jīng)常會(huì)陷入抽象的泥潭中. 這迫使你對(duì)回傳事件機(jī)制進(jìn)行逆向工程, 或者執(zhí)行遲鈍的動(dòng)作, 來(lái)生成想要的HTML.
可測(cè)試性差: Web Forms的設(shè)計(jì)者們當(dāng)初并沒(méi)有預(yù)料到自動(dòng)測(cè)試會(huì)成為軟件開(kāi)發(fā)中至關(guān)重要的一部分. 他們?cè)O(shè)計(jì)的緊密耦合的架構(gòu)不適合進(jìn)行單元測(cè)試. 集成測(cè)試也很困難.
Web Forms并非一無(wú)是處. 微軟在提高標(biāo)準(zhǔn)兼容性和簡(jiǎn)化開(kāi)發(fā)過(guò)程上做了很大努力, 甚至將最初的ASP.NET MVC框架的一些特性應(yīng)用到了Web Forms上. 當(dāng)你想快速看到結(jié)果時(shí)選擇Web Forms是很好的, 你可以在一個(gè)工作日內(nèi)將一個(gè)相當(dāng)復(fù)雜的Web應(yīng)用程序運(yùn)行起來(lái). 但除非你在開(kāi)發(fā)過(guò)程中足夠仔細(xì), 否則你會(huì)發(fā)現(xiàn)你創(chuàng)建的應(yīng)用非常難以測(cè)試和維護(hù).

?最初的MVC框架
在2007年10月, 微軟在現(xiàn)有的ASP.NET平臺(tái)上發(fā)布了一個(gè)新的開(kāi)發(fā)平臺(tái), 作為對(duì)對(duì)Web Forms的批評(píng)和競(jìng)爭(zhēng)對(duì)手(如Ruby on Rails)的直接回應(yīng). 新平臺(tái)被稱為ASP.NET MVC框架, 反映了Web應(yīng)用開(kāi)發(fā)的新型趨勢(shì), 如HTML和CSS標(biāo)準(zhǔn)化, RESTful web服務(wù), 游戲的單元測(cè)試, 和開(kāi)發(fā)者應(yīng)該擁抱HTTP的無(wú)狀態(tài)本質(zhì)的理念.
現(xiàn)在看來(lái), 最初的MVC框架的基礎(chǔ)理念是顯而易見(jiàn)的, 但在2007年, .NET web開(kāi)發(fā)的世界是缺少這些東西的. ASP.NET MVC框架的推出讓微軟的web開(kāi)發(fā)平臺(tái)重新走向現(xiàn)代.
MVC框架也標(biāo)準(zhǔn)了微軟態(tài)度的重要轉(zhuǎn)變, 它原本嘗試控制web應(yīng)用開(kāi)發(fā)工具鏈的所有東西.
微軟在MVC框架中采納了新的理念, 如基于開(kāi)源工具構(gòu)建(如jQuery), 接受設(shè)計(jì)約定, 采用競(jìng)爭(zhēng)對(duì)手(更成功的)的最佳實(shí)踐, 并對(duì)開(kāi)發(fā)者公布了MVC框架的源碼.

?最初的MVC框架出了什么問(wèn)題?
在MVC框架初創(chuàng)時(shí), 微軟在現(xiàn)有的ASP.NET平臺(tái)上構(gòu)建是合理的, ASP.NET有很多可靠的底層功能, 為開(kāi)發(fā)過(guò)程提供了一個(gè)良好的開(kāi)端, 并已經(jīng)被ASP.NET開(kāi)發(fā)者所熟知.
但為了將MVC框架移植到最初為Web Forms設(shè)計(jì)的平臺(tái)上, 需要作出妥協(xié). MVC框架開(kāi)發(fā)者逐漸習(xí)慣了使用配置文件和微調(diào)代碼才能使應(yīng)用程序正確運(yùn)行, 盡管這些和他們的web應(yīng)用毫無(wú)關(guān)系.
隨著MVC框架越來(lái)越流行, 微軟開(kāi)始將一些核心特性加入到Web Forms, 結(jié)果越來(lái)越奇怪.
原本用于支持MVC框架的設(shè)計(jì)原則被擴(kuò)展, 以支持Web Forms, 他們之間必須能夠很好地融合. 同時(shí), 微軟開(kāi)始擴(kuò)展ASP.NET, 一般提供創(chuàng)建web服務(wù)(web api)和實(shí)時(shí)通訊(SignalR)的新框架. 每一個(gè)新框架都加入了自己的配置和開(kāi)發(fā)約定, 都有自己的優(yōu)點(diǎn)和古怪, 使得整個(gè)ASP.NET越來(lái)越混亂.

?了解ASP.NET Core
在2015年, 微軟宣布了ASP.NET和MVC框架的新方向, 最終產(chǎn)生了ASP.NET Core MVC, 本書(shū)的主要內(nèi)容.
ASP.NET Core基于.NET Core上, .NET Core是.NET框架的跨平臺(tái)版本. Windows仍然是一個(gè)占據(jù)統(tǒng)治地位的操作系統(tǒng), 但承載在云端小容器中的web應(yīng)用的份額正在增加. 通過(guò)采用跨平臺(tái)的方法, 微軟拓展了.NET的運(yùn)用范圍, 使ASP.NET Core應(yīng)用程序在更廣泛的載體上部署成為可能, 也讓開(kāi)發(fā)者可以在Linux或macOS上創(chuàng)建ASP.NET Core web應(yīng)用程序.
ASP.NET Core是一個(gè)全新的框架. 它更簡(jiǎn)單, 更易用, 擺脫了Web Forms的傳統(tǒng). 而且因?yàn)樗?NET Core, 支持在更多的平臺(tái)和容器上開(kāi)發(fā)web應(yīng)用程序.
ASP.NET Core MVC在新的ASP.NET Core平臺(tái)上提供了最初的ASP.NET MVC框架的功能. 它集成了先前的Web API的特性, 包括了一種更自然的生成復(fù)雜內(nèi)容的方式, 并且使關(guān)鍵的開(kāi)發(fā)任務(wù)(如單元測(cè)試)更簡(jiǎn)單可預(yù)測(cè).

ASP.NET Core MVC 2中的新內(nèi)容
ASP.NET Core MVC 2 發(fā)行版聚焦于整合早期版本中的一些工具和平臺(tái)的更改. ASP.NET Core MVC 2需要.NET Core 2, 其擴(kuò)充了許多API, 并支持更多的Linux發(fā)行版. 有用的更新包括一個(gè)簡(jiǎn)化了NuGet包管理的新的包管理系統(tǒng), 一個(gè)新的ASP.NET Core配置系統(tǒng), 以及對(duì)Entity Framework Core 2的支持. 最大的新特性是Razor Pages, 嘗試用更現(xiàn)代的平臺(tái)來(lái)重建Web頁(yè)面的開(kāi)發(fā)風(fēng)格, 但MVC開(kāi)發(fā)人員對(duì)Razor Pages并不感興趣(我在書(shū)中也沒(méi)有描述).

ASP.NET Core MVC的關(guān)鍵優(yōu)勢(shì)
接下來(lái)的章節(jié)簡(jiǎn)要的描述新的MVC平臺(tái)如何超越傳統(tǒng)的Web Forms和原始的MVC架構(gòu), 它又如何使ASP.NET重新回到前沿.

MVC架構(gòu)
ASP.NET Core MVC遵循MVC模式, 它指導(dǎo)了ASP.NET web應(yīng)用程序的形成和內(nèi)部組件之間的交互.
區(qū)分MVC架構(gòu)模式和ASP.NET Core MVC實(shí)現(xiàn)非常重要. MVC模式不是新鮮事物——可以追溯到1978年在Xerox PARC上的Smalltalk項(xiàng)目——但現(xiàn)在由于以下理由成為受歡迎的web應(yīng)用設(shè)計(jì)模式:
MVC模式應(yīng)用的UI遵循一個(gè)自然循環(huán): 用戶執(zhí)行一個(gè)操作, 應(yīng)用程序更改數(shù)據(jù)模型的狀態(tài)并向用戶更新視圖作為響應(yīng), 然后再次執(zhí)行此循環(huán). 這可以很方便地適應(yīng)傳遞一系列HTTP請(qǐng)求和響應(yīng)的web應(yīng)用程序
Web應(yīng)用程序需要結(jié)合多種技術(shù)(例如數(shù)據(jù)庫(kù), HTML和可執(zhí)行代碼), 通常分為多層. 從這些層的組合中產(chǎn)生的模式可以很自然地映射到MVC模式的概念上.
ASP.NET Core MVC實(shí)現(xiàn)了MVC模式, 相較Web Forms在概念分離方面有極大的提升. 事實(shí)上, ASP.NET Core MVC實(shí)現(xiàn)了各種各樣的特別適合Web應(yīng)用程序的MVC模式.

可擴(kuò)展性
ASP.NET Core和ASP.NET Core MVC是作為一系列具有良好定義的特性的獨(dú)立組件構(gòu)建的, 其實(shí)現(xiàn).NET接口, 或者構(gòu)建在抽象類上. 你可以輕松地將關(guān)鍵組件替換為自己實(shí)現(xiàn)的組件. 一般來(lái)說(shuō)ASP.NET Core為每個(gè)組件提供了三個(gè)選項(xiàng):
使用組件的默認(rèn)實(shí)現(xiàn)(足夠應(yīng)對(duì)大多數(shù)應(yīng)用程序)
使用默認(rèn)實(shí)現(xiàn)的子類來(lái)調(diào)整其行為
使用接口或抽象基類的實(shí)現(xiàn)來(lái)完全替換組件

HTML和HTTP的嚴(yán)格控制
ASP.NET Core MVC提供了符合標(biāo)準(zhǔn)的HTML標(biāo)記. 它內(nèi)置的標(biāo)記助手提供符合標(biāo)準(zhǔn)的輸出, 和Web Forms相比有一個(gè)重大的改變. ASP.NET Core MVC鼓勵(lì)使用CSS來(lái)設(shè)計(jì)簡(jiǎn)潔優(yōu)雅的標(biāo)記, 而不是生成一些幾乎不受控制的HTML.
當(dāng)然, 如果你想為復(fù)雜的UI元素(如日期選擇器或級(jí)聯(lián)菜單)添加一些現(xiàn)成的組件, ASP.NET Core MVC采用的”無(wú)特殊需求”方法使得引用一些單項(xiàng)優(yōu)勢(shì)(best-of-breed)的前端庫(kù)(如jQuery, Angular, React或Bootstrap)很簡(jiǎn)單. ASP.NET Core MVC與這些庫(kù)匹配得很好, 以致于微軟專門(mén)創(chuàng)建了預(yù)包含它們的開(kāi)發(fā)模版.

可測(cè)試性
ASP.NET Core MVC架構(gòu)為應(yīng)用程序的可維護(hù)性和可測(cè)試性提供了良好開(kāi)端, 因?yàn)槟憧梢宰匀坏貙⒉煌膽?yīng)用程序分成獨(dú)立的部分. 另外, ASP.NET Core平臺(tái)和MVC框架的每個(gè)部分都可以被隔離并進(jìn)行單元測(cè)試. 可以使用任意的開(kāi)源測(cè)試框架來(lái)進(jìn)行單元測(cè)試.
在這本書(shū)中, 你會(huì)看到一些例子, 如何為ASP.NET MVC控制器編寫(xiě)簡(jiǎn)潔的單元測(cè)試, 如何使用各種策略以及進(jìn)行模擬操作. 即使你從未寫(xiě)過(guò)單元測(cè)試, 也會(huì)有一個(gè)很好的開(kāi)始.
可測(cè)試性不僅僅包含單元測(cè)試. ASP.NET Core MVC應(yīng)用程序也可以和UI自動(dòng)化測(cè)試工具一起工作. 你可以編寫(xiě)模擬用戶交互的測(cè)試腳本, 而不需要猜測(cè)框架將生成那些HTML元素結(jié)構(gòu), CSS類或ID, 也不需要擔(dān)心結(jié)構(gòu)的意外變化.

強(qiáng)大的路由系統(tǒng)
由于web應(yīng)用程序技術(shù)的發(fā)展, URL風(fēng)格也發(fā)生了演變. 類似/App_v2/User/Page.aspx?action=show%20prop&prop_id=82742的URL逐漸被簡(jiǎn)單的類似/to-rent/chicago/2303-silver-street的URL取代.
關(guān)注URL結(jié)構(gòu)的理由很多:
搜索引擎為URL中的關(guān)鍵字賦予權(quán)重. 搜索
rent in Chicago更容易出現(xiàn)簡(jiǎn)單的URL許多網(wǎng)絡(luò)用戶已經(jīng)足夠了解URL, 并可以通過(guò)在瀏覽器的地址欄中輸入U(xiǎn)RL來(lái)進(jìn)行導(dǎo)航
當(dāng)人們理解URL的含義時(shí), 更容易點(diǎn)擊它, 與朋友分享, 甚至在電話中朗讀.
不會(huì)暴露應(yīng)用程序的技術(shù)細(xì)節(jié)文件夾和文件名結(jié)構(gòu), 因此可以自由更改底層實(shí)現(xiàn), 而不會(huì)破壞傳入鏈接.
早期的框架很難實(shí)現(xiàn)干凈的URL, 但ASP.NET Core MVC默認(rèn)使用稱為URL router的功能來(lái)提供干凈的URL. 這使你可以控制URL結(jié)構(gòu)和應(yīng)用程序的關(guān)系, 自由創(chuàng)建有意義的URL模式, 而不需要遵循預(yù)定義的模式. 當(dāng)然, 這意味著你可以輕松地定義現(xiàn)代的REST風(fēng)格URL結(jié)構(gòu).?

現(xiàn)代的API
微軟的.NET平臺(tái)在每個(gè)發(fā)行版中不斷發(fā)展, 支持甚至引領(lǐng)最新的現(xiàn)代編程趨勢(shì). ASP.NET Core MVC是為.NET Core構(gòu)建的, 因此它的API可以充分利用C#開(kāi)發(fā)者熟悉的語(yǔ)言特性, 包括await關(guān)鍵字, 擴(kuò)展方法, lambda表達(dá)式, 匿名和動(dòng)態(tài)類型, LINQ. 許多ASP.NET Core MVC API方法和編碼模式比早期版本更清晰, 更具表現(xiàn)力. 如果你不熟悉最新的C#語(yǔ)言特性, 請(qǐng)不要擔(dān)心, 我們?cè)诘谒恼轮锌偨Y(jié)了MVC開(kāi)發(fā)中最重要的C#特性.

跨平臺(tái)
之前的ASP.NET版本局限于Windows平臺(tái), 需要在Windows桌面版上編寫(xiě)web應(yīng)用, 并部署和運(yùn)行在Windows server上. 微軟讓ASP.NET Core的開(kāi)發(fā)和部署跨平臺(tái)化了. .NET Core在不同平臺(tái)都可以獲取, 包括macOS和大量流行的Linux發(fā)行版. 跨平臺(tái)支持使得ASP.NET Core應(yīng)用更容易部署, 也很好地支持了應(yīng)用容器平臺(tái), 如Docker.
現(xiàn)在大多數(shù)ASP.NET Core MVC開(kāi)發(fā)都將是使用Visual Studio完成的, 但微軟也創(chuàng)建了跨平臺(tái)的開(kāi)發(fā)工具Visual Studio Code, 意味著ASP.NET Core開(kāi)發(fā)不局限于Windows了.

ASP.NET Core MVC是開(kāi)源的
不像微軟之前的web應(yīng)用開(kāi)發(fā)平臺(tái), 你可以免費(fèi)下載ASP.NET Core和ASP.NET Core MVC的源碼, 甚至編譯自己定制的版本. 當(dāng)你在調(diào)試系統(tǒng)組件并想逐步調(diào)試其代碼(甚至閱讀程序員的原始注釋)時(shí), 這是非常寶貴的. 如果你正在構(gòu)建高級(jí)組件, 并希望了解存在哪些開(kāi)發(fā)可能性, 或內(nèi)置組件實(shí)際如何工作時(shí), 也是很有用的. 你可以在https://github.com/aspnet下載ASP.NET Core和ASP.NET Core MVC的源碼.

總結(jié)
在這一章中, 我解釋了ASP.NET Core MVC存在的背景, 和它從Web Forms和最初的ASP.NET MVC的演變. 我描述了使用ASP.NET Core MVC的好處和這本書(shū)的結(jié)構(gòu). 在下一章中, 你將看到ASP.NET Core MVC的一個(gè)簡(jiǎn)單示例, 來(lái)展示這些優(yōu)越特性.
