前言
通過(guò)前幾篇文章,我們已經(jīng)能比較自如的使用ASP.NET MVC來(lái)呈現(xiàn)頁(yè)面和數(shù)據(jù)了。但是,有一個(gè)大問(wèn)題沒(méi)有解決:如何處理表單數(shù)據(jù)。例如,我們將要實(shí)現(xiàn)的公告發(fā)布功能,用戶肯定是在某個(gè)表單頁(yè)面輸入標(biāo)題、正文等內(nèi)容,而后提交,然后表單數(shù)據(jù)要被傳遞到相應(yīng)的地方交由業(yè)務(wù)邏輯組件處理。
在傳統(tǒng)的ASP.NET下,使用的是Model1模式,每個(gè)aspx頁(yè)面有一個(gè)同名的aspx.cs文件,當(dāng)提交表單時(shí),默認(rèn)數(shù)據(jù)被提交到這個(gè)同名aspx.cs文件中某個(gè)方法下處理。但是,在ASP.NET MVC中,這種方法不能用了,因?yàn)槲覀儞Q用了Model2模式,不能再用同名代碼文件來(lái)處理aspx的提交請(qǐng)求(但是這不表明同名代碼文件就沒(méi)有用了,實(shí)際上,它依然會(huì)被執(zhí)行,但是我們不提倡在里面處理任何邏輯,但是,有時(shí)會(huì)利用它進(jìn)行一些初始化操作。),那么應(yīng)該怎么做呢?不多講,我們以例子說(shuō)明問(wèn)題。
下面我們一步一步完成“MVC公告發(fā)布系統(tǒng)”的公告發(fā)布功能,等做完這個(gè)功能,上面的問(wèn)題就明了了。
先修改一個(gè)錯(cuò)誤...
這里,首先要像大家道歉,因?yàn)樵诘谝黄?,我犯了一個(gè)錯(cuò)誤。就是在公告的實(shí)體類(lèi)AnnounceInfo中少了一個(gè)屬性?,F(xiàn)在,我們?cè)贏nnounceInfo中添加一個(gè)叫Cateogry的屬性,類(lèi)型為int,它用來(lái)指明這個(gè)公告屬于哪個(gè)分類(lèi)。
對(duì)于這個(gè)錯(cuò)誤,我十分抱歉。建立輸入信息頁(yè)面 下面,正式開(kāi)始我們的工作。首先,我要建立一個(gè)頁(yè)面,用來(lái)讓用戶輸入公告信息。而我們知道,在ASP.NET MVC中不能直接請(qǐng)求aspx文件,任何請(qǐng)求都要通過(guò)Controller,所以,我們首先在Controllers目錄下建立一個(gè)新的Controller類(lèi),名叫AnnounceController。刪除其中自動(dòng)生成的Index方法,新建一個(gè)名叫Release的Action方法,具體代碼如下。AnnounceController.cs:
1using System; 2using System.Collections.Generic; 3using System.Linq; 4using System.Web; 5using System.Web.Mvc; 6using System.Web.Mvc.Ajax; 7using MVCDemo.Models; 8using MVCDemo.Models.Interfaces; 9using MVCDemo.Models.Entities;1011namespace MVCDemo.Controllers12{13 public class AnnounceController : Controller14 {15 public ActionResult Release()16 {17 ICategoryService cServ = ServiceBuilder.BuildCategoryService();18 List<CategoryInfo> categories = cServ.GetAll();19 ViewData["Categories"] = new SelectList(categories, "ID", "Name");20 return View("Release");21 }22 }23}
這個(gè)就是要呈現(xiàn)表單頁(yè)的Action方法,看看它做了什么:它首先取出所有的分類(lèi),然后將它們轉(zhuǎn)成SelectList類(lèi)型存入ViewData,后呈現(xiàn)Release視圖。 為什么要取出所有分類(lèi)呢?因?yàn)槲覀冊(cè)诎l(fā)布公告時(shí)希望有個(gè)下拉列表框列出所有公告名稱,讓用戶可以選擇要發(fā)布的公告屬于哪個(gè)分類(lèi)。而SelectList是ASP.NET MVC中用于綁定到下拉列表的類(lèi)型。它有很多重載的構(gòu)造方法,其中我使用的是三個(gè)參數(shù)的,它們分別表示:生成數(shù)據(jù)的枚舉,綁定到value的字段名,綁定到列表名稱的字段名。這里,將把所有分類(lèi)實(shí)體集合綁定到下拉列表,而ID屬性作為值,Name屬性作為顯示在列表框中的名字。 如果我們不需要下拉列表框來(lái)顯示所有分類(lèi),那么Release方法只需一行return View("Release");就可以了。 Action方法做完了,我們還需要視圖。在Views目錄下建立Announce目錄,再在這個(gè)Announce目錄下建立Release.aspx視圖。代碼如下。Release.aspx:
1<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Release.aspx.cs" Inherits="MVCDemo.Views.Announce.Release" %> 2<%@ Import Namespace="MVCDemo.Models.Entities" %> 3 4<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 5 6<html xmlns="http://www.w3.org/1999/xhtml" > 7<head runat="server"> 8 <title></title> 9</head>10<body>11 <% SelectList categories = ViewData["Categories"] as SelectList; %>12 <div>13 <h1>MVC公告發(fā)布系統(tǒng)——發(fā)布公告</h1>14 <% Html.BeginForm("DoRelease","Announce",FormMethod.Post); %>15 <dl>16 <dt>標(biāo)題:</dt>17 <dd><%= Html.TextBox("Title") %></dd>18 <dt>分類(lèi):</dt>19 <dd><%= Html.DropDownList("Category",categories) %></dd>20 <dt>內(nèi)容:</dt>21 <dd><%= Html.TextArea("Content") %></dd>22 </dl>23 <input type="submit" value="發(fā)布" />24 <% Html.EndForm(); %>25 </div>26</body>27</html>
代碼不復(fù)雜,但是要注意幾個(gè)地方。categories不多說(shuō)了,這是剛才我們傳遞過(guò)來(lái)的所有分類(lèi)組成的列表項(xiàng)。我覺(jué)得大家迷惑的可能是那些Html.***的東西,其實(shí),Html是ViewPage的中的一個(gè)對(duì)象(ViewPage是所有視圖的基類(lèi)),它主要的左右就是產(chǎn)生各種表單項(xiàng)(先這么認(rèn)為吧,其實(shí)它還有其他功能),例如Html.BeginForm就是說(shuō)這里開(kāi)始一個(gè)form標(biāo)簽,而Html.EndForm當(dāng)然是form標(biāo)簽結(jié)束。其他幾個(gè),看名字相信大家也猜出來(lái)了。
至于為什么這么做,也不直接使用原始的HTML標(biāo)簽,我先不多說(shuō),以后大家做多了自然就理解了,目前大家只要知道,這樣做可以避免一個(gè)url問(wèn)題以及讓url更靈活就行了。^_^ 回到這個(gè)頁(yè)面,BeginForm有三個(gè)參數(shù),分別是提交請(qǐng)求的Action名,提交請(qǐng)求的Controller名和請(qǐng)求方式。所以,這個(gè)頁(yè)面的意思就是使用post方法請(qǐng)求http://localhost/Announce/DoRelease這個(gè)Action來(lái)處理我們的請(qǐng)求。 頁(yè)面中有三個(gè)輸入表單和一個(gè)提交按鈕。三個(gè)輸入表單分別是:名叫Title的文本框,名叫Content的文本域和名叫Category的下拉列表框。注意下拉列表是怎么綁定的,只要將含有數(shù)據(jù)的SelectList作為第二個(gè)參數(shù)就行了。完成后,頁(yè)面是這樣子的:
處理請(qǐng)求
現(xiàn)在我們可以輸入信息了,但是如果你輸入后點(diǎn)提交,你會(huì)發(fā)現(xiàn)產(chǎn)生了經(jīng)典的404錯(cuò)誤。剛才我們說(shuō)了,表單提交到的Action是Announce下的DoRelease,但是現(xiàn)在沒(méi)有這個(gè)Action,當(dāng)然會(huì)404了。下面,我們來(lái)建立這個(gè)處理程序。 回到AnnounceController,新建Action方法DoRelease,具體代碼如下。AnnounceController.cs:
1using System; 2using System.Collections.Generic; 3using System.Linq; 4using System.Web; 5using System.Web.Mvc; 6using System.Web.Mvc.Ajax; 7using MVCDemo.Models; 8using MVCDemo.Models.Interfaces; 9using MVCDemo.Models.Entities;1011namespace MVCDemo.Controllers12{13 public class AnnounceController : Controller14 {15 public ActionResult Release()16 {17 ICategoryService cServ = ServiceBuilder.BuildCategoryService();18 List<CategoryInfo> categories = cServ.GetAll();19 ViewData["Categories"] = new SelectList(categories, "ID", "Name");20 return View("Release");21 }2223 public ActionResult DoRelease()24 {25 AnnounceInfo announce = new AnnounceInfo()26 {27 ID = 1,28 Title = Request.Form["Title"],29 Category = Int32.Parse(Request.Form["Category"]),30 Content = Request.Form["Content"],31 };3233 IAnnounceService aServ = ServiceBuilder.BuildAnnounceService();34 aServ.Release(announce);3536 ViewData["Announce"] = announce;37 return View("ReleaseSucceed");38 }39 }40}
我們看,它首先新建一個(gè)AnnounceInfo類(lèi)型的實(shí)體類(lèi),用來(lái)存貯這個(gè)新的公告的信息。注意它是怎么得到表單信息的,對(duì)了,用了Request.Form["表單名"],這就是獲得表單信息的一種方法,當(dāng)然還有其他方法,但是我推薦這一種。注意,這里的表單名就是我們使用Html.***方法生成表單時(shí)的名字。 OK,下面就是調(diào)用業(yè)務(wù)邏輯組件,完成發(fā)布公告功能。
但是這里有個(gè)問(wèn)題,我們的業(yè)務(wù)邏輯組件是Mock的,也就是說(shuō)其實(shí)什么都沒(méi)做啊。如果是真的業(yè)務(wù)邏輯組件,我們可以去數(shù)據(jù)庫(kù)看看有沒(méi)有添加公告信息成功,可是這里沒(méi)有,我們要怎么證明表單數(shù)據(jù)傳遞過(guò)來(lái)了呢?于是我想了一個(gè)辦法,有新加了一個(gè)ReleaseSucceed視圖,用來(lái)顯示新發(fā)布公告的信息,以此證明我們確實(shí)把表單信息傳過(guò)來(lái)了。ReleaseSucceed視圖如下:ReleaseSucceed.aspx:
1<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ReleaseSucceed.aspx.cs" Inherits="MVCDemo.Views.Announce.ReleaseSucceed" %> 2<%@ Import Namespace="MVCDemo.Models.Entities" %> 3 4<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 5 6<html xmlns="http://www.w3.org/1999/xhtml" > 7<head runat="server"> 8 <title></title> 9</head>10<body>11 <% AnnounceInfo announce = ViewData["Announce"] as AnnounceInfo; %>12 <div>13 <h1>MVC公告發(fā)布系統(tǒng)——發(fā)布公告成功</h1>14 <dl>15 <dt>ID:</dt>16 <dd><%= announce.ID %></dd>17 <dt>標(biāo)題:</dt>18 <dd><%= announce.Title %></dd>19 <dt>類(lèi)別ID:</dt>20 <dd><%= announce.Category %></dd>21 <dt>內(nèi)容:</dt>22 <dd><%= announce.Content %></dd>23 </dl>24 </div>25</body>26</html>
這些代碼就不用我過(guò)多解釋了。下面,我們輸入一些信息,提交看看:
看到?jīng)]有,我沒(méi)有騙你們,表單數(shù)據(jù)真的傳過(guò)來(lái)了!^_^|||小結(jié) 通過(guò)這四篇文章,我們已經(jīng)了解了ASP.NET MVC的基本原理,并且已經(jīng)會(huì)呈現(xiàn)數(shù)據(jù)頁(yè)面及傳遞表單數(shù)據(jù)處理了。會(huì)了這些,其實(shí)已經(jīng)可以應(yīng)付絕大多數(shù)主要開(kāi)發(fā)了。從下篇開(kāi)始,我們接觸一些高級(jí)點(diǎn)的內(nèi)容。下篇將說(shuō)一下ASP.NET MVC如何與ASP.NET AJAX及JQuery結(jié)合,再后面,會(huì)講到攔截器及與Silverlight結(jié)合的內(nèi)容。