ASP.NET MVC 是微軟官方提供的以MVC模式為基礎的ASP.NET Web應用程式(Web Application)框架,它由Castle的MonoRail而來。 MVC 編程模式 MVC 是三種 ASP.NET 編程模式中的一種。 MVC 是一種使用 MVC(Model View Cont ...
ASP.NET MVC 是微軟官方提供的以MVC模式為基礎的ASP.NET Web應用程式(Web Application)框架,它由Castle的MonoRail而來。
MVC 編程模式
MVC 是三種 ASP.NET 編程模式中的一種。
MVC 是一種使用 MVC(Model View Controller 模型-視圖-控制器)設計創建 Web 應用程式的模式。
(1)Model(模型)表示應用程式核心(比如資料庫記錄列表)。
(2)View(視圖)顯示數據(資料庫記錄)。
(3)Controller(控制器)處理輸入(寫入資料庫記錄)。
MVC 模式同時提供了對 HTML、CSS 和 JavaScript 的完全控制。Model(模型)是應用程式中用於處理應用程式數據邏輯的部分。通常模型對象負責在資料庫中存取數據。View(視圖)是應用程式中處理數據顯示的部分。通常視圖是依據模型數據創建的。Controller(控制器)是應用程式中處理用戶交互的部分。通常控制器負責從視圖讀取數據,控制用戶輸入,並向模型發送數據。
新建一個ASP.NET MVC4應用程式,結構如下圖所示:
對各個文件夾的說明:
(1)App_Data 文件夾用於存儲應用程式數據。
(2)Content 文件夾用於存放靜態文件,比如樣式表(CSS 文件)、圖標和圖像。
(3)Controllers 文件夾包含負責處理用戶輸入和相應的控制器類。
(4)Models 文件夾包含表示應用程式模型的類。模型控制並操作應用程式的數據。
(5)Views 文件夾用於存儲與應用程式的顯示相關的 HTML 文件(用戶界面)。
(6)Scripts 文件夾存儲應用程式的 JavaScript 文件。
下麵就主要的Controller、Model和View做出說明。
一、控制器
1、描述
控制器(Controller)主要負責響應用戶的輸入,併在響應時修改模型(Model)。通過這種方式,控制器主要關註的是應用程式流、輸入數據的處理,以及對相關視圖(View)輸出數據的提供。
2、簡單控制器
新建一個ASP.NET MVC4應用程式,會自動生成一個HomeController和AccountController。
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace MvcApplication1.Controllers { public class HomeController : Controller { public ActionResult Index() { ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application."; return View(); } } }
直接按F5運行程式即可看到index試圖中的內容,此時瀏覽器的URL為:
http://localhost:4573,或者修改瀏覽器地址為:
http://localhost:4573/home
http://localhost:4573/home/index
程式預設會托管在VS2013自帶的IIS中,採用的埠號為4573。如果程式托管在MyWeb.com中,則URL應為:
http://MyWeb.com/home/index。
3、控制器操作中的參數
前面的例子Action中返回的是字元串常量,下麵就讓它們通過相應URL傳進來的參數動態地執行操作。
在這裡,我們使用HttpUtility.HtmlEncode來預處理用戶輸入。這樣就能阻止用戶用鏈接向視圖中註入JavaScriptd代碼或HTML標記,比如/home/sayhello?content=<script>window.location='http://www.baidu.com'</script>。
public string SayHello(string content) { string message = HttpUtility.HtmlEncode("Hello " + content); return message; }
4、路由---將URL映射到動作
框架是如何知道將URL映射到一個特定的控制動作的?答案就在Global.asax文件的RegisterRoutes方法中。該方法定義了將一個URL模式映射到控制器或動作的路由。
using System.Linq; using System.Web; using System.Web.Http; using System.Web.Mvc; using System.Web.Optimization; using System.Web.Routing; namespace MvcApplication1 { // 註意: 有關啟用 IIS6 或 IIS7 經典模式的說明, // 請訪問 http://go.microsoft.com/?LinkId=9394801 public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); AuthConfig.RegisterAuth(); } } }
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Routing; namespace MvcApplication1 { public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } } }
5、控制器總結
(1)不需要做任何配置,只需瀏覽到/控制器/動作URL即可;
(2)控制器是一個非常簡單的類,繼承自System.Web.Mvc.Controller類;
(3)用控制器在瀏覽器中顯示文本,沒有用到View或Model。
二、視圖
1、作用
提供用戶界面。一個控制器可以對應多個試圖,一個視圖可以被多個控制器使用。
在Action名上右鍵→添加試圖→View1。
2、指定視圖
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>View1</title> </head> <body> <div> <h2>@ViewBag.Message</h2> </div> </body> </html>
3、ViewData和ViewBag的區別於聯繫
在前面的例子中,使用了ViewBag的Message屬性從控制器往視圖傳遞數據,ViewData是一個特殊的字典類,可以按標準語法進行使用:ViewData["CurrentTime"]=DateTime.Now;
這種語法也可以用動態封裝器ViewBag:ViewBag.CurrentTime=DateTime.Now;
註意:
(1)儘管只有當要訪問的關鍵字是有效的C#標識符是,ViewBag才起作用,如在ViewData["Key With Spaces"]就不能使用ViewBag訪問,編譯不通過;
(2)動態值不能作為一個參數傳遞給擴展方法。因為C#編譯器為了選擇正確的擴展方法,在編譯是必須知道每個參數真正類型。如:@Html.TextBox("name",ViewBag.Name)不會編譯通過,可以改為:
①@Html.TextBox("name",ViewData["Name"])
②@Html.TextBox("name",(string)ViewBag.Name)
4、強類型視圖
現在需要編寫一個顯示Album實例列表的視圖。一簡單的方法就是通過ViewBag屬性把那些Album實例添加到視圖數據字典中,然後在視圖中迭代他們。
(1)首先,在Models文件夾下新建一個Album類,為了簡單起見,只定義一個Title屬性。
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace MvcApplication1.Models { public class Album { public string Title { get; set; } } }
public ActionResult List() { var album = new List<Album>(); for (int i = 0; i < 10; i++) { album.Add(new Album { Title = "Product " + i.ToString() }); } //一、使用ViewBag傳值 //ViewBag.Album = album; //return View("ListView"); //二、使用ViewData傳值 ViewData["Album"] = album; return View("ListView"); }
(3)視圖
在List上右鍵→添加視圖。
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>ListView</title> </head> <body> <div> <ul> @*一、使用ViewBag傳值*@ @*@foreach(MvcApplication1.Models.Album a in (ViewBag.Album as IEnumerable <MvcApplication1.Models.Album>)) { <li>@a.Title</li> }*@ @*二、使用ViewBag傳值*@ @foreach (MvcApplication1.Models.Album a in (ViewData["Album"] as IEnumerable<MvcApplication1.Models.Album>)) { <li>@a.Title</li> } </ul> <pre name="code" class="html"> <ul> @foreach(dynamic d in ViewBag.Album) { <li>@d.Title</li> } </ul> </div> </body> </html>
運行效果:
<ul> @foreach (dynamic d in ViewBag.Album) { <li>@d.Title</li> } </ul>
請記住,ViewData是ViewDataDictionary類型的,它有一個額外的Model屬性,可以用來在視圖中獲取指定的模型對象。由於在ViewData中只能傳遞一個模型對象,因此,我們利用這一點可以很容易的實現向視圖傳遞一個特定的類對象。
在Controller方法中,可以通過重載的List方法中傳遞模型實例來指定模型,代碼如下:
public ActionResult List() { var album = new List<Album>(); for (int i=0;i < 10; i++) { album.Add(new Album { Title="Product " + i.ToString() }); } ViewData["Album"]=album; return View("ListView",album); } @model IEnumerable<MvcApplication1.Models.Album> @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>ListView</title> </head> <body> <div> <ul> @foreach(dynamic d in Model) { <li>@d.Title</li> } </ul> </div> </body> </html>
如果不想輸入模型類型的完全限定類型名,可使用using關鍵字聲明,如下所示:
@using MvcApplication1.Models @model IEnumerable<Album> @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>ListView</title> </head> <body> <div> <ul> @foreach (dynamic d in Model) { <li>@d.Title</li> } </ul> </div> </body> </html>
對於在視圖中經常使用的名稱空間,一個較好的方法就是在Views目錄下的web.config文件中聲明。
<system.web.webPages.razor> <host factoryType = "System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> < pages pageBaseType="System.Web.Mvc.WebViewPage"> <namespaces> <add namespace="System.Web.Mvc" /> <add namespace="System.Web.Mvc.Ajax" /> <add namespace="System.Web.Mvc.Html" /> <add namespace="System.Web.Optimization"/> <add namespace="System.Web.Routing" /> <add namespace="MvcApplication1.Models"/> </namespaces> </pages> </system.web.webPages.razor>
5、Razor視圖引擎
5.1 先來看一個簡單的例子。
@{ Layout = null; } @{ var items = new string[] { "one", "two", "three" }; } <!DOCTYPE html> <html> <head> <title>ListView</title> </head> <body> <div> <ul> @foreach (var item in items) { <li>@item</li> } </ul> </div> </body> </html>
5.2 Html編碼
因為在很多情況下需要用視圖顯示用戶輸入,如博客評論等,所以總是存在著潛在的跨站腳本註入攻擊(也成XSS),值得稱贊的是,Razor表達式是Html自動編碼的,如下不會彈出一個警示框,而是直接顯示html代碼。
@{ string message = "<script>alert('haacked!');</script>"; }
然而,如果想要展示Html標簽,就要返回一個System.Web.IHtml對象的實例,Razor並不對它進行編碼。當然也可以創建一個HtmlStringl實例或者使用Html.Raw便捷方法。
@{ string message = "<script>alert('haacked!');</script>"; } <span>@Html.Raw(message)</span>
雖然這種自動的HTML編碼通過對一HTML形式顯示的用戶輸入進行編碼能有效的緩和XSS的脆弱性,但是對於在JavaScript中時遠遠不夠的。例如:
<script type="text/javascript"> $(function () { var message = 'Hello @Ajax.JavaScriptStringEncode(ViewBag.Message)'; $("#message").html(message).show('slow'); }); </script>
5.3 佈局
Razor的佈局有助於使用應用程式中的多個視圖保持一致的外觀,可使用佈局為網站定義公共模板(或只是其中的一部分),公共模板包含一個或多個占位符,應用程式中的其他視圖為他們提供內容。
下麵看一個非常簡單的佈局,新建一個名稱為MyLayout.cshtml的視圖,由於要作為公共模板,所以將其放在/Views/Shared/路徑下。
<!DOCTYPE html> <html> <head> <title>@ViewBag.Title</title> </head> <body> <h1>@ViewBag.Title</h1> <div id="Container">@RenderBody()</div> </body> </html>