創(chuàng)建ASP.NET Core MVC應(yīng)用程序(1)-添加Controller和View

創(chuàng)建ASP.NET Core MVC應(yīng)用程序(1)-添加Controller和View

參考文檔:Getting started with ASP.NET Core MVC and Visual Studio

這系列文章是參考了.NET Core文檔和源碼,可能有人要問(wèn),直接看官方的英文文檔不就可以了嗎,為什么還要寫這些文章呢?

原因如下:

  • 官方文檔涉及的內(nèi)容相當(dāng)全面,屬于那種大而全的知識(shí)倉(cāng)庫(kù),不太適合初學(xué)者,很容易讓人失去重要,讓人掉入到具體的細(xì)節(jié)之中。
  • 對(duì)于大多數(shù)人來(lái)講開發(fā)語(yǔ)言只是工具,程序員都有一個(gè)通病,就是死磕工具,把工具學(xué)深。我認(rèn)為在工具上沒有必要投入太多時(shí)間,以能高效地完成日常的工作項(xiàng)目為準(zhǔn)即可。要需求驅(qū)動(dòng)學(xué)習(xí),你需要什么學(xué)什么。如果你學(xué)的新技術(shù)新特性只是屠龍之技或者只需要用到的時(shí)候去查一下即可的話,這種死磕這又有什么用。沒有必要花120%的時(shí)間去學(xué)100%的知識(shí),你只需要花20%的時(shí)間去學(xué)習(xí)80%的知識(shí)就可以了,剩下的等實(shí)際的項(xiàng)目中用到的時(shí)候去查就可以了,工具只是工具,不是工作本身。
  • 目前基本所有的文章都是基于Windows平臺(tái)的Visual Studio IDE來(lái)介紹的。而我用的是一臺(tái)Mac,所以我將基于Mac平臺(tái)的Visual Studio Code講解適合我們實(shí)際項(xiàng)目中遇到的知識(shí)。
  • 還有一點(diǎn),就是這是我個(gè)人的學(xué)習(xí)總結(jié)。

這系列文章就是讓你去花20%的時(shí)間去學(xué)80%的東西,剩下的20%再去看官方文檔。

之前介紹了《如何在Mac下運(yùn)行ASP.NET Core應(yīng)用程序》,主要是講解了如何在Mac下把ASP.NET Core跑起來(lái),在這一篇中將進(jìn)一步分析如何添加Controller、View、Model等。

Model-View-Controller (MVC)?架構(gòu)模式將一個(gè)應(yīng)用程序分成了三大塊:ModelView、Controller。

  • Models: 用于表示應(yīng)用程序數(shù)據(jù)的類,并使用驗(yàn)證邏輯來(lái)約束數(shù)據(jù)的業(yè)務(wù)規(guī)則。通常模型對(duì)象用來(lái)從數(shù)據(jù)庫(kù)獲取和存儲(chǔ)實(shí)體模型?數(shù)據(jù)。比如User Model 從數(shù)據(jù)庫(kù)獲取用戶數(shù)據(jù),并將它交給View來(lái)顯示或者直接更新,更新后的數(shù)據(jù)再寫入到數(shù)據(jù)庫(kù)中。
  • Views: 用來(lái)顯示應(yīng)用程序UI的組件,該UI會(huì)顯示Model數(shù)據(jù)。
  • Controllers: 是Models和Views的一個(gè)橋梁。用來(lái)處理瀏覽器請(qǐng)求,獲取Model數(shù)據(jù),并將指定視圖模板作為響應(yīng)返回給瀏覽器。視圖(View)僅僅用于顯示信息,控制器(Controller)用于處理并響應(yīng)用戶的輸入和交互。比如,Controller處理路由數(shù)據(jù)查詢字符串值,并將這些值傳遞給Model,Model再去使用這些值去查詢數(shù)據(jù)庫(kù)。

MVC模式幫助你創(chuàng)建一個(gè)關(guān)注分離的應(yīng)用程序(輸入邏輯、業(yè)務(wù)邏輯、UI邏輯),同時(shí)這個(gè)模塊之間是松耦合的。UI邏輯屬于View,輸入邏輯屬于Controller,業(yè)務(wù)邏輯屬于Model。

添加Controller

namespace MyFirstApp.Controllers
{
    public class HomeController : Controller
    {
        // GET: /<controller>/
        public IActionResult Index()
        {
            return View();
        }

        // GET: /<controller>/About
        public IActionResult About()
        {
            ViewData["Message"] = "Your application description page.";

            return View();
        }

        public IActionResult Contact()
        {
            ViewData["Message"] = "Your contact page.";

            return View();
        }

        public IActionResult Error()
        {
            return View();
        }

        public IActionResult Welcome(string name, int id = 1)
        {
            ViewData["Message"] = "Hello " + name;
            ViewData["id"] = id;

            return View();
        }
    }
}

在控制器中的每一個(gè)public方法都可以作為HTTP終結(jié)點(diǎn)被調(diào)用。

第一個(gè)注釋表示這是一個(gè)通過(guò)在根URL添加“/Home/”進(jìn)行調(diào)用的HTTP GET方法。第二個(gè)注釋表示這是一個(gè)通過(guò)在根URL添加"/Home/About/"來(lái)進(jìn)行調(diào)用的HTTP GET方法。

MVC根據(jù)傳入的請(qǐng)求URL調(diào)用相應(yīng)的控制器類以及其中的Action方法,MVC默認(rèn)使用的URL路由邏輯采用類似于這樣的格式來(lái)決定具體的代碼調(diào)用:

/[Controller]/[ActionName]/[Parameters]

打開Startup.cs你會(huì)看到該項(xiàng)目的路由規(guī)則:

當(dāng)你不帶任何URL段(segment)直接運(yùn)行該程序時(shí),將默認(rèn)訪問(wèn)“Home”控制器中的"Index"方法。

第一個(gè)URL segment決定運(yùn)行哪個(gè)Controller,所以http://localhost:5000/Home映射到HomeController類;URL segment第二個(gè)部分決定類里面的Action方法。所以http://localhost:5000/Home/Index會(huì)運(yùn)行HomeController類中的Index方法;URL segment的第三部分(id)是路由數(shù)據(jù)。

這里通過(guò)增加一個(gè)方法來(lái)顯示通過(guò)URL傳遞一些參數(shù)信息到Controller。

public string Welcome(string name, int id = 1)
{
    return HtmlEncoder.Default.Encode($"Hello {name}, id: {id}");
}

上述代碼通過(guò)使用HtmlEncoder.Default.Encode來(lái)保護(hù)應(yīng)用免受JS的惡意輸入,并且使用了C#的新特性Interpolated Strings。

http://localhost:5000/Home/Welcome?name=Charlire&id=1

MVC的模型綁定系統(tǒng)自動(dòng)將查詢字符串的命名參數(shù)映射到具體的方法中的參數(shù),注意名稱必須一致。

上述代碼中URL segment(Parameters)沒有被使用到,參數(shù)nameid都是作為查詢字符串被傳遞的。?是一個(gè)分隔符,后面跟著的就是查詢字符串,&用來(lái)分割查詢字符串。

輸入下面的URL:http://localhost:5000/Home/Welcome/1?name=Charlire。這一次第三個(gè)URL segment將匹配到路由參數(shù)idWelcome方法包含一個(gè)與MapRoute方法中的URL模板相匹配的id參數(shù)。隨后的?(id?)表示id參數(shù)是可選的。

添加View

通過(guò)Razor視圖引擎創(chuàng)建視圖模板文件,基于Razor的視圖模板使用 .cshtml 作為文件擴(kuò)展名,通過(guò)使用C#提供了一個(gè)優(yōu)雅的方式來(lái)創(chuàng)建HTML。

public IActionResult Index()
{
    return View();
}

上面的Index方法使用視圖模板來(lái)生成一個(gè)HTML響應(yīng)給瀏覽器。Controller中的Action方法通常返回一個(gè)IActionResult(或一個(gè)派生于ActionResult 類),而不是像String這樣的基元類型。

點(diǎn)擊Views文件夾,在該文件夾下面新建與Controller名對(duì)應(yīng)的文件夾。

然后我們導(dǎo)航到Views->User文件夾,運(yùn)行命令yo aspnet:mvcview Index在該文件夾下面生成Index.cshtml。

Index方法只是簡(jiǎn)單地運(yùn)行了return View(),來(lái)指定方法去使用一個(gè)視圖模板文件來(lái)為瀏覽器渲染最新的響應(yīng)。因?yàn)闆]有顯式指定所要使用的視圖模板文件,MVC會(huì)默認(rèn)使用 /Views/User 文件夾中的 Index.cshtml。

改變視圖和布局頁(yè)面

通用點(diǎn)擊菜單鏈接,你會(huì)發(fā)現(xiàn)每一個(gè)頁(yè)面都顯示了相同的菜單布局,這個(gè)菜單布局位于 Views/Shared/_Layout.cshtml 文件。

Layout模板允許你在一個(gè)地方指定網(wǎng)站的HTML容器布局,并應(yīng)用到網(wǎng)站的多個(gè)頁(yè)面中。@RenderBody()是一個(gè)占位符,用來(lái)顯示你指定視圖的位置,“包裹在”布局頁(yè)面。舉個(gè)例子,當(dāng)你點(diǎn)擊About鏈接,Views/Home/About.cshtml視圖就會(huì)在RenderBody?方法內(nèi)渲染。

修改Layout文件中的標(biāo)題和菜單鏈接

注意現(xiàn)在每一個(gè)頁(yè)面都顯示了新修改的鏈接,通過(guò)在Layout模板中修改一次,網(wǎng)站上的所有的頁(yè)面都立即顯示成新修改的信息。

通過(guò)查看 Views/_ViewStart.cshtml 文件:

@{
    Layout = "_Layout";
}

Views/_ViewStart.cshtml 文件將 Views/Shared/_Layout.cshtml 文件引入到每一個(gè)視圖中。你可以通過(guò)Layout屬性來(lái)設(shè)置一個(gè)不同的布局視圖,或?qū)⑺O(shè)置成null,那么將不使用任何一個(gè)布局文件。

修改 Views/User/Index.cshtml 文件如下:

@{
    ViewData["Title"] = "User List";
}

<h2>User List</h2>

<p>Hello from View Template!</p>

ViewData["Title"] = "User List";ViewDataDictionaryTitle屬性設(shè)置為User List。這個(gè)Title屬性將用在 Views/Shared/_Layout.cshtml Layout頁(yè)面的<title>?HTML元素上。

<title>@ViewData["Title"] - User MVC Application</title>

注意 Index.cshtml 視圖模板中的內(nèi)容是怎么和 Views/Shared/_Layout.cshtml 視圖模板進(jìn)行合并的,布局模板使得修改應(yīng)用里所有的頁(yè)面很容易。

從Controller傳遞數(shù)據(jù)到View

在談到數(shù)據(jù)庫(kù)和模型(Models)之前,先讓我們討論一下從控制器傳遞信息到視圖。控制器方法會(huì)在傳入的URL請(qǐng)求響應(yīng)時(shí)被調(diào)用。控制器類是用于處理傳入的瀏覽器請(qǐng)求,從數(shù)據(jù)庫(kù)獲取數(shù)據(jù),并最終決定哪種類型的的響應(yīng)會(huì)被回傳給瀏覽器。

控制器主要負(fù)責(zé)提供視圖模板向?yàn)g覽器呈現(xiàn)一個(gè)響應(yīng)所需的數(shù)據(jù)或?qū)ο蟆?/p>

最佳實(shí)踐:視圖模板不應(yīng)該執(zhí)行業(yè)務(wù)邏輯或直接與數(shù)據(jù)庫(kù)進(jìn)行交互,而只應(yīng)該使用控制器提供給它的數(shù)據(jù)。保持這樣的“關(guān)注分離”有助于保持你的代碼整潔,可測(cè)試性及更易于維護(hù)。

當(dāng)前,HomeController控制器中的Welcome方法接受一個(gè)nameid參數(shù),然后直接將值輸出到瀏覽器。我們?cè)诳刂破髦袑⑹褂靡粋€(gè)視圖模板來(lái)代替字符串,視圖模板將生成一個(gè)動(dòng)態(tài)響應(yīng),這就意味著你需要通過(guò)控制器傳遞適當(dāng)?shù)臄?shù)據(jù)給視圖來(lái)生成響應(yīng),可以讓控制器將視圖模板需要的動(dòng)態(tài)數(shù)據(jù)(參數(shù))放入ViewData字典中,隨后視圖模板可以通過(guò)訪問(wèn)該字典獲取到這些數(shù)據(jù)。

ViewData字典是一個(gè)動(dòng)態(tài)對(duì)象,你可以將任何你想要的數(shù)據(jù)加進(jìn)去。在你加入數(shù)據(jù)之前,ViewData對(duì)象沒有任何已定義的屬性。MVC的模型綁定系統(tǒng)自動(dòng)映射地址欄中查詢字符串的命名參數(shù)到你方法中的參數(shù)。

public IActionResult Welcome(string name, int id = 1)
{
    ViewData["Message"] = "Hello " + name;
    ViewData["id"] = id;

    return View();
}

ViewData字典對(duì)象包括將要傳遞到視圖的數(shù)據(jù)。接受,我們來(lái)創(chuàng)建一個(gè)Welcome視圖模板。

這里將在Welcome.cshtml視圖模板中創(chuàng)建一個(gè)循環(huán)。

@*
    For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
*@
@{
    ViewData["Title"]= "Welcome Page";
}
<h2>Welcome</h2>

<ul>
    @for(int i=0; i<(int)ViewData["id"]; i++)
    {
        <li>@ViewData["Message"]</li>
    }
</ul>

數(shù)據(jù)從URL獲得并通過(guò)MVC模型綁定器傳遞到控制器,控制器將數(shù)據(jù)打包封裝到ViewData字典中并將該對(duì)象傳遞給視圖。接著,視圖將數(shù)據(jù)以HTML的形式渲染到瀏覽器。

我們使用了一個(gè)ViewData字典來(lái)將數(shù)據(jù)從控制器傳遞到視圖,接下來(lái)我們將使用視圖模型(View Model)來(lái)實(shí)現(xiàn)相同的目的。通過(guò)View Model來(lái)傳遞數(shù)據(jù)比通過(guò)ViewData更受歡迎。

個(gè)人博客

我的個(gè)人博客

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容