APS.NET MVC + EF (04)---路由和數據傳遞


4.1 視圖引擎

ASP.NET MVC 提供兩種視圖引擎:ASPX(C#)和Razor(CSHTML),推薦使用Razor。

4.1.1 Razor的語法

在Razor視圖中,所有的服務器端代碼都是圍繞@展開的,下面介紹@使用的各種語法形式和應用情況。

  1. @( expression) 或 @ expression

    @是Razor中的一個重要符號,它被定義為Razor服務器代碼塊的開始符號。例如,我們可以在View中直接寫C#代碼輸出日期

<p> @Datetime.Now.ToStirng()</p>

@(expression)一般可以吧"()"省略,但這只限於@后緊鄰變量或對象的情況,如果后面是常數,則必須加"()",如下面的用法。

@("razor視圖".ToString() )

如果去掉()則不能正常解析。

   

  1. 語句塊

    在Razor視圖引擎中,我們可以使用@{code}來定義一段代碼塊。並支持與HTML代碼混寫。如下面代碼所示。

@{

var stu = new RazorDemo.Models.Student();

stu.StudentName = "王五";

stu.Gender = "男";

<p>姓名:@stu.StudentName</p>

<p>性別:@stu.Gender</p>

}

@foreach (var stu in students)

{

<p>姓名:@stu.StudentName</p>

<p>性別:@stu.Gender</p>

}

@if (stu.Gender == "男")

{

<p>姓名:@stu.StudentName</p>

<p>性別:@stu.Gender</p>

}

  

   

  1. 輸出特殊字符

    如果要輸出"@"符號,可以使用"@@"進行轉義,如:

<p>@@2013 copy right</p>

www.163@@.com

  1. 引用命名空間

@using RazorDemo.Models

  1. 注釋

@* 被注釋的內容 *@

   

4.1.2 布局頁

Razor的布局有助於使應用程序中的多個視圖保持一致外觀。如果熟悉WebForm的話,其中母版頁和布局的作用基本上是相同的,但是布局提供了更加簡潔的語法和更強大的靈活性。

可以使用布局為網站定義公共模板(或只是其中的一部分)。公共模板包含一個或多個占位符,應用程序中的其他視圖為他們提供內容。從某些角度來看,布局很像視圖的抽象基類。

下面來看一個簡單的布局。這里稱這個布局文件為SiteLayout.cshtml

<!DOCTYPE html>

<html>

<head>

<meta name="viewport" content="width=device-width" />

<title>@ViewBag.Title</title>

</head>

<body>

<div id="main-content">

@RenderBody() <!--占位符-->

</div>

</body>

</html>

它看起來很像一個標准的Razor視圖,但需要注意的是在視圖中由一個@RenderBody調用。這是一個占位符,用來標記使用這個布局的視圖將渲染他們的主要內容的位置。多個Razor視圖現在可以利用這個布局來顯示一致的外觀。

接下來看一個使用這個布局的例子Index.cshtml 。

@{

ViewBag.Title = "Index";

Layout = "~/Views/Shared/SiteLayout.cshtml";

}

   

<h2>這是主頁內容</h2>

上面這個視圖通過Layout屬性來指定布局頁面。當渲染這個視圖時,它的HTML內容將被放在SiteLayout.cshtml中的id屬性為main-content的div元素中,最后生成的html頁面如下。

<!DOCTYPE html>

<html>

<head>

<meta name="viewport" content="width=device-width" />

<title>Index</title>

</head>

<body>

<div id="main-content">

<h2>這是主頁內容</h2>

</div>

</body>

</html>

注意視圖內容,其中標題和內容都是視圖提供的,除此以外都是布局提供的。

   

在一個布局頁中只允許有一個@RenderBody()占位符如果需要多個占位符,可以使用@RenderSection( ) 方法來完成例如再SiteLayout.cshtml頁面上添加一個頁腳占位符。

<!DOCTYPE html>

<html>

<head>

<meta name="viewport" content="width=device-width" />

<title>@ViewBag.Title</title>

</head>

<body>

<div id="main-content">

@RenderBody()

</div>

   

<footer>

@RenderSection("Footer")

</footer>

</body>

</html>

在不做任何改變的情況下再次運行前面的視圖,將會拋出一個異常,提示沒有定義Footer。默認情況下,視圖必須為布局中定義的每一個占位符section提供相應的內容。

更新后的Index.cshtml 。

@{

ViewBag.Title = "Index";

Layout = "~/Views/Shared/SiteLayout.cshtml";

}

<h2>這是主頁內容</h2>

@section Footer

{

this is the <strong>這是底部</strong>

}

@RenderSection( )方法有一個重載,第二個參數是bool類型,指明該Section是否為必須的。所以可以在使用該RenderSection方法的時候直接利用第二個重載,再把bool參數值設為false,即使你在具體的View中沒有聲明實現@section,運行起來也不會報錯了。

   

在項目中,如果每個頁面都使用布局頁,那么就必須在每個內容頁中都要使用 Layout 進行聲明,這就形成了代碼冗余。

_ViewStart.cshtml頁面可以用來消除這種冗余。這個文件中的代碼先於同目錄下任何視圖代碼的執行。這個文件也可以遞歸地應用到子目錄下的任何視圖。

當創建一個默認的ASP.NET MVC項目時,你將會注意到Views目錄下會自動添加一個_ViewStart.cshtml文件,它指定了一個默認布局。

@{

Layout = "~/Views/Shared/_Layout.cshtml";

}

這樣在內容頁中就不用再指定 Layout 了。

   

4.2 路由

4.2.1 為什么需要路由

在前面的內容中,我們已經初步接觸了路由的定義代碼,示例1所示代碼能將"/Home/Index/0"、/Home/Index"、/Home"、"/"多種形式的URL指向同一個頁面。

示例1

routes.MapRoute(

"Default", // 路由名稱

"{controller}/{action}/{id}", // 帶有參數的URL

new { controller = "Home", action = "Index", id = UrlParameter.Optional }

// 參數默認值

);

在系統中使用路由的好處有兩點。

  1. 屏蔽物理路徑,提高安全性
  2. 有利於搜索引擎的優化

4.2.2 路由規則

示例1中,MapRoute()中URL的參數值是"{controller}/{action}/{id}",稱之為URL模式。該模式是一種字符串,包括一些固定的字符字面量和占位符,占位符由一對{}表示,其語法為:

字面量{占位符}字面量{占位符}字面量…{占位符}字面量

在上述語法中字面量可能是一個固定的字符,比較常見的是"/",也可能是一個字符串,如"Users"。占位符也是一個字符或字符串。

表4-1 URL模式匹配示例

序號

URL模式

匹配的URL示例

1

{controller}/{action}/{id}

/books/Edit/1,/Books/Detail/2

2

{first}/{second}/{third}

/books/Edit/1,/Books/Detail/2

3

{table}/Detail.aspx

/Users/Detail.aspx, /Books/Detail.aspx

4

Blog/{action}/{id}

/Blog/Show/1001, /Blog/delete/1001

5

{language}-{country}/{action}

/zh-cn/display, /en-us/list

注意事項:

  • URL模式匹配不區分大小寫。
  • 兩個占位符之間不能連續。
  • "/"和一般的字面量相比,是比較特殊的。
  • 不能以"/"或"~"字符開頭,不能包含"?"。

除了上面一些規則為,還有一些特殊的模式。

(1) * 匹配

* 用來匹配剩余部分。如URL模式"{controller}/{action}/{query}/{*plus}"匹配的URL,產生的部分路由數據如表4-2所示。

序號

路由模式

路由數據

1

/home/index/select/a/b

Key=plus, Value= a/b

2

/home/index/select/a/b/c

Key=plus, Value= a/b/c

3

/home/index/select/

Key=plus, Value=

(2) 貪婪匹配

例如URL模式: {filename}.{ext}

如果匹配"/food.xml.aspx",則會產生路由數據如下:

filename= food.xml, ext=aspx

所謂貪婪匹配就是,在模式匹配過程中,尋找字面量時不是找到第一個后就放棄,而是貪婪的尋找到最有一個為止。

   

(3) 默認值

路由可以有默認值的,如示例1中指定的默認值。如果沒有默認值,只能使用諸如"book/eidt/0"這樣的地址去匹配,使用時非常不方便。

在使用路由默認值時要注意以下兩點。

  • 只提供中間參數的默認值不起作用。

    如只提供 action="index", 則"/home/0"不匹配,只能是"/home/index/0"

  • 包含字面量時默認值不起作用("/"除外)

    如:對於模式{controller}-{action},提供默認值action="index", 則"/home-"不能匹配,只能使用 /home-index

   

(4) 路由約束

可以給路由參數增加正則表達式約束,如示例2所示。

routes.MapRoute(

"Default", // 路由名稱

"{year}/{month}/{day}", // 帶有參數的URL

new { controller = "Home", action = "Index", id =

UrlParameter.Optional } , // 參數默認值

constraints: new { year=@"\d{4}", month=@"\d{2}",

day=@"\d{2}" }

);

   

(5)多個路由

如果有多組路由時,排在最前面的優先匹配。

   

4.2.3 路由數據

RouteData對象用來保存URL模式和實際URL匹配產生的路由數據,這些路由數據以鍵-值對的形式保存。如:

表4-2 URL模式匹配示例

序號

URL模式

匹配的URL示例

路由數據

1

{controller}/{action}/{id}

/books/Edit/1,

/Books/Detail/2

Key=Controller,Value=Books

Key=action,Value=Edit

Key=id,value=1

2

{first}/{second}/{third}

/books/Edit/1,

/Books/Detail/2

Key=first,Value=Books

Key=second,Value=Edit

Key=third,value=1

3

{table}/Detail.aspx

/Users/Detail.aspx,

Key=table, value=Users

4

Blog/{action}/{id}

/Blog/Show/1001

Key=action, value=show

Key=id, value=1001

5

{language}-{country}/{action}

/zh-cn/display,

Key=language, value=zh

Key=country,value=cn

Key=action, value=display

   

可以使用如下代碼在動作方法中讀取路由中的值:

string id = RouteData.Values[ "id" ] ;

 

在使用時注意驗證是否為null。

   

   

4.3 數據傳遞---從控制器到視圖

在ASP.NET MVC中,使用RouteData對象可以方便的獲取URL中的參數值。同樣,也提供了若干對象可以從控制器向視圖傳遞數據。

4.3.1 ViewData對象

ViewData是一種字典集合數據,同時屬於視圖基類和控制器基類的屬性。常見的用法是在控制器中寫入數據,在視圖中讀取數據。如示例2所示。

示例2

   

//控制器代碼

public class HomeController : Controller

{

public ActionResult Index()

{

ViewData["data"] = "Hello,MVC!";

return View();

}

}

   

//視圖代碼

<h1>@ViewData["data"]</h1>

   

注意:ViewData 的 Value 是 Object 類型。

4.3.2 ViewBag對象

ViewBag是 dynamic 類型的對象,同時屬於視圖基類和控制器基類的屬性,用法如示例3所示。

示例3

//控制器代碼

public class HomeController : Controller

{

public ActionResult Index()

{

ViewBag.data = "Hello,MVC!";

return View();

}

}

   

//視圖代碼

<h1>@ViewBag.data</h1>

   

本質上,ViewBag是對ViewData數據的包裝,也就是說兩個對象中的數據是可以相互讀取的。

4.3.3 TempData對象

TempData的用法和ViewData用法相似,但和ViewData保存的數據互不干擾。如示例4所示。

示例4

//控制器代碼

public class HomeController : Controller

{

public ActionResult Index()

{

TempData["data"] = "Hello,MVC!";

return View();

}

}

   

//視圖代碼

<h1>@TempData["data"]</h1>

在實際開發中,TempData主要用來跨請求傳遞數據,也就是說跨越動作方法傳遞數據,如示例5所示。

示例5

//控制器代碼

public class HomeController : Controller

{

public ActionResult Index()

{

TempData["data"] = "來自Index()的數據";

Response.Redirect("~/Home/Detail");

return View();

}

public ActionResult Detail()

{

return View();

}

   

<!-- Detail.cshtml 視圖代碼 -->

<h1>@TempData["data"]</h1>

需要注意的是,如果TempData中的數據被使用過(從視圖中輸出),就會被清除。如果沒有被使用過,那么它保存的時間和Session相同。

   

4.3.4 強類型視圖

在使用ViewBag 向視圖傳遞數據時,有一個明顯的缺陷就是在使用時要做數據類型轉換。有一種更好的方式就是使用強類型視圖。在添加視圖的時候,在向導對話框中選擇"Empty模板",如圖4-1所示,並選擇模型類。這樣創建完成的視圖基類就變成了 System.Web.Mvc.ViewPage<T>。

圖4-1 創建強類型視圖

如果使用強類型視圖,則在控制器中傳遞數據的方式變成直接使用 View()的一個帶"model"的參數的重載方法。在視圖中可以直接通過模型類的屬性使用傳遞的數據。如示例6所示。

示例6

//動作方法中的代碼

Book book = manager.GetBookById(id);

return View(book);

//視圖中的代碼

<div>

作者: @Model.Author 著 <br />

出版社:@Model. Publisher.Name

</div>

   

4.4 案例:實現帶搜索條件和分頁的列表展示


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM