我希望通过本文让你感受到构建ASP.NET MVC应用程序的过程和构建ASP应用程序或ASP.NET Web窗体应用程序的相似之处和不同之处。
任务列表应用程序
为了保持简洁,我只创建一个非常简单的任务列表应用程序,通过这个程序可以做下面三件事情:
1.列出一套任务
2.创建新的任务
3.标记任务已完成
还是那句话,为了保持简洁,在构建任务列表应用程序时我只使用ASP.NET MVC框架的少部分特性,如我不会使用测试驱动开发方法或HTML辅助方法。
预备
要构建ASP.NET MVC应用程序,要使用到Visual Studio 2008 或Visual Web Developer 2008 Express,同时还需要下载ASP.NET MVC框架,下载地址是http://www.asp.net/mvc/。可以从http://msdn.microsoft.com/en-us/vs2008/products/cc268305.aspx下载90天试用期的Visual Studio 2008。如果你决定使用Visual Web Developer 2008 Express,必须得安装SP1,可以从http://www.microsoft.com/downloads/details.aspx?FamilyId=BDB6391C-05CA-4036-9154-6DF4F6DEBD14&displaylang=en下载Visual Web Developer 2008 Express的SP1包。
我们从在Visual Studio 2008中创建一个ASP.NET MVC Web应用程序项目开始,选择菜单项文件(File) > 新建项目(New Project),你就会看到如图1所示的一个新建项目对话框,选择你熟悉的编程语言(Visual Basic 或Visual C#),然后选择ASP.NET MVC Web应用程序项目,项目名称命名为Tasklist,然后点击保存按钮。
图1 新建项目对话框
无论你什么时候创建ASP.NET MVC Web应用程序项目,Visual Studio都会提示你附带创建一个独立的单元测试项目,如图2所示,因为时间限制,我们在本文中就不创建测试项目了,因此选项No选项,点击确定(Ok)按钮。
图2 创建单元测试项目对话框
ASP.NET MVC应用程序也有标准的文件夹:模块(Models)、视图(Views)和控制器(Controllers)文件夹。在方案浏览器(Solution Explorer)窗口,你应该可以看到这些文件夹,我们也需要向models、Views和Controllers文件夹中条件文件来完成我们的Tasklist应用程序。
当你用Visual Studio创建一个新的ASP.NET MVC应用程序时,你会得到一个示例应用程序,因为我们希望从零开始,因此需要删除这些示例应用程序内容,要将下面的文件和文件夹删除:
ControllersHomeController.cs
ViewsHome
创建控制器
在构建ASP.NET MVC应用程序时,通常是从创建控制器开始的,浏览器对ASP.NET MVC应用程序的请求由控制器处理,控制器包括应用程序逻辑,负责响应对应的请求。
在控制器文件夹上点右键,选择“添加” > “新项目”,再选项“MVC控制器类”模板,将控制器命名为HomeController.vb,点击添加按钮,这样就在Visual Studio中添加了一个控制器。
对于我们的Tasklist应用程序,我们需要修改HomeController类,让它包括清单1中的代码,修改后的控制器包括四个函数:Index(), Create(), CreateNew(), and Complete(),每个函数对应一个控制器行为。
清单1 HomeController.vb
Public Class HomeController
Inherits System.Web.Mvc.Controller
' Display a list of tasks
Function Index() As ActionResult
Return View()
End Function
' Display a form for creating a new task Function
Create() As ActionResult
Return View()
End Function
' Add a new task to the database Function CreateNew() As
ActionResult
' Add the new task to database
Return
RedirectToAction("Index") End Function
' Mark a task as complete
Function Complete() As ActionResult
Return
RedirectToAction("Index") End Function End Class
下面是每个控制器行为的目的:
Index():当你想显示任务清单时调用。
Create():当你想显示创建一个新任务的窗体时显示调用。
CreateNew():当创建一个新任务的窗体被提交时调用,这个控制器行为真实地把新任务添加到数据库中。
Complete():当一个新任务被标记为完成时调用。
控制器类中包括的任何一个公共函数都被当做一个控制器行为暴露在外,注意,控制器行为是暴露给所有人的,任何人都可以在他们的浏览器地址栏中输入正确的URL来调用控制器行为,因此,当你不想让函数为公共调用就不要将其创建成公共函数。
控制器行为返回一个行为结果(ActionResult),一个行为结果代表行为所做的事情,前面的Index()和Create()行为返回一个MVC视图,CreateNew()和Complete()行为结果重定向到另一个控制器行为。
接下来说一说这些控制器行为如何工作,当你请求Create()控制器行为时,返回一个包括创建新任务的窗体的视图,当你提交这个窗体时会调用CreateNew()控制器行为,CreateNew()控制器行为将新任务添加到数据库中,并将用户重定向到Index()控制器行为,Index()控制器行为返回一个任务清单列表的视图,最后,如果你标记任务完成,就会调用Complete()控制器行为,并更新数据库,Complete()控制器行为将用户重定向回Index()控制器行为,并更新显示的任务清单列表。
创建视图
视图包括HTML标记和返回给浏览器的内容,在ASP.NET MVC应用程序中视图是最接近页面的事物,通过创建一个扩展名为.aspx的文件来创建一个视图。
你必须将视图放在正确的位置,如果你给HomeController的Index()行为方法创建了一个视图,你必须将这个视图放在ViewsHomeIndex.aspx。
如果你正在为ProductController的Price() 行为方法创建视图,视图就必须放在ViewsProductPrice.aspx。
默认情况下,视图的名字和它对应的控制器行为的名字一样,视图必须放在与它名字对应的控制器文件夹下。
在视图文件夹下的子文件夹上点右键,选择“添加” > “新项目”,再选择“MVC视图”模板创建一个新的视图,我们需要在下面的路径中创建两个视图:
ViewsHomeIndex.aspx
ViewsHomeCreate.aspx
当你创建好这些视图后,你的方案浏览器窗口应该包括如图3所示的文件:
图3 Index.aspx和Create.aspx视图
清单2 Index.aspx
<%@
Page Language="VB" AutoEventWireup="false" CodeBehind="Index.aspx.vb"
Inherits="TaskList.Index" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0
Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title></title>
</head>
<body>
<div>
<h1>My
Tasks</h1>
...
displaying all tasks
<a
href="/Home/Create">Add new Task</a>>
</div>
</body> </html>
Index.aspx视图目前还不能显示任何任务清单,它只不过声称要显示而已,本文后面我们将添加显示任务清单的代码到Index.aspx视图中。
注意Index.aspx视图中包括一个链接“Add new Task”,这个链接指向 /Home/Create,当你点击这个链接时,就会调用HomeController类的Create()行为,Create方法返回Create视图。
Create.aspx视图包括创建新任务的窗体,这个视图的代码显示在清单3中。
清单3 Create.aspx
<%@
Page Language="VB" AutoEventWireup="false" CodeBehind="Create.aspx.vb"
Inherits="TaskList.Create" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0
Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title></title>
</head>
<body>
<div>
<h1>Add
New Task</h1>
<form
method="post" action="/Home/CreateNew">
<label
for="task">Task:</label>
<input
type="text" name="task" />
<br
/>
<input
type="submit" value="Add Task" />
</form>
</div>
</body> </html>
注意清单3中的代码会post 下面的URL:
/Home/CreateNew.aspx
这个URL对应HomeController控制器的CreateNew()行为,窗体数据代表将要发送给这个行为的新任务。
创建数据库
接下来是创建存储任务的数据库,在App_Data文件夹上点右键,选择“添加” > “新项目”,再选择“SQL SERVER”数据库模板,将数据库命名为TaskListDB.mdf,点击添加按钮。
下面就要添加表在数据库中,在方案浏览窗口中双击TaskListDB.mdf,打开服务器浏览窗口,在Tables文件夹上点右键,选择“添加新表”,打开数据库表设计器,创建下面的数据库列:
列名 | 数据类型 | 允许为空 |
Id | Int | 不允许 |
Task | Nvarchar(300) | 不允许 |
IsCompleted | Bit | 不允许 |
EntryDate | DateTime | 不允许 |
第一列Id,有两个特殊的属性,首先需要标记Id列作为主键列,选择Id列后,然后选择“设置为主键”按钮,接下来需要将Id列标记为标识列,在列属性窗口,向下滚动到“Identity Specification”,展开,然后将“Is Identity”的值设为yes,如图4所示。
图4 task表
最后一步是保存新创建的表,点击保存按钮,将表命名为tasks。
创建模型
MVC模型包括应用程序的主体和数据库访问逻辑,正常情况下,你应该将你主要的类放在MVC应用程序的Models文件夹下,所有不在视图或控制器下的应用程序逻辑都应该放在Models文件夹下。
在本文中,我们将 使用LINQ和SQL与数据库通信,就我个人而言,我更喜欢LINQ,但这里不需要使用LINQ,如果你喜欢LINQ,你应该要使用另一个技术如Nhibernate或实体框架(Entity Framework)与数据库通信。
若要使用LINQ和SQL,我们必须先在Models文件夹下创建我们的LINQ和SQL类,在Models文件夹上点右键,选择“添加”> “新项目”,再选择“LINQ to SQL Class”模板,将新创建的LINQ to SQL类命名为TaskList.dbml,点击添加按钮,完成这些步骤后,将会显示对象关系设计器(Object Relational Designer)。
我们需要创建一个LINQ to SQL实体类表示我们的Tasks数据库表,从方案浏览窗口拖动Tasks数据库表到对象关系设计器中,执行这一行为将会创建一个新的LINQ to SQL的实体类,命名为Task(如图5所示),点击保存按钮(软盘图标)保存新的实体。
图5 Task实体类
将数据库逻辑添加到控制器方法
现在我们已经有数据库了,我们可以修改我们的控制器行为以便我们可以从数据库存储和检索任务,修改好的HomeController包括在清单4中。
清单4 HomeController.vb
Public Class HomeController
Inherits System.Web.Mvc.Controller
Private db As New TaskListDataContext()
' Display a list of tasks
Function Index() As ActionResult
Dim tasks = From t In db.Tasks Order By t.EntryDate Descending
Return View(tasks.ToList())
End Function
' Display a form for creating a new task
Function Create() As ActionResult
Return View()
End Function
' Adding a new task to the database
Function CreateNew(ByVal task As String) As ActionResult
' Add the new task to database
Dim newTask As New Task()
newTask.Task = task
newTask.IsCompleted = False
newTask.EntryDate = DateTime.Now
db.Tasks.InsertOnSubmit(newTask)
db.SubmitChanges()
Return RedirectToAction("Index")
End Function
' Mark a task as complete
Function Complete(ByVal Id As Integer) As ActionResult
' database logic
Dim tasks = From t In db.Tasks Where t.Id = Id
For Each Match In tasks
Match.IsCompleted = True
Next
db.SubmitChanges()
Return RedirectToAction("Index")
End Function
End Class
注意清单4中的HomeController类包括一个私有类级别字段db,db字段是TaskListDataContext类的一个实体,HomeController类使用db字段表示TaskListDB数据库。
Index()控制器行为已经被修改,可以检索Tasks数据库表中的所有记录,任务都传递到Index视图中。
CreateNew()方法也被修改,可以在Tasks数据库表中创建一个新任务,注意CreateNew()方法修改后可以接受一个字符串参数命名任务,这个参数表示传递自Create视图的任务文本格式字段,ASP.NET MVC框架将这个格式字段作为一个参数自动传递给控制器行为。
最后,Complete()方法也被修改,可以改变Tasks表中IsComplete列的值,当你标记任务完成时,任务的Id会传递给Complete()行为,并更新数据库。
修改Index视图
最后我们还需要做一件事情以完成我们的Tasklist应用程序,那就是必须修改Index视图以便它可以显示所有任务清单,并允许我们标记任务完成,修改后的Index视图包括在清单5中。
清单5 Index.aspx
<%@ Page Language="VB" AutoEventWireup="false" CodeBehind="Index.
aspx.vb" Inherits="TaskList.Index" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org
/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>Index</title>
</head>
<body>
<div>
<h1>My Tasks</h1>
<ul>
<% For Each task As TaskList.Task In ViewData.Model%>
<li>
<% If task.IsCompleted Then%>
<del>
<%= task.EntryDate.ToShortDateString() %>
-- <%=task.Task%>
</del>
<% Else%>
<a href="/Home/Complete/<%= task.Id.To
String() %>">Complete</a>
<%= task.EntryDate.ToShortDateString() %>
-- <%=task.Task%>
<% End If%>
</li>
<% Next%>
</ul>
<br /><br />
<a href="/Home/Create">Add new Task</a>
</div>
</body>
</html>
清单5中的Index视图包括一个For….Each循环,反复检索所有具有ViewData.Model属性的任务,通常,你使用ViewDate将数据从一个控制器行为传递给一个视图。在循环内,使用了一个条件检查任务是否已经完成,一个完成的任务使用一根横线(删除线)显示,HTML标记<DEL>用于创建这根删除线,如果任务还没有完成,会有一个Complete的链接,这个链接是由下面的脚本构成的:
<a href="/Home/Complete/<%= task.Id.ToString() %>">Complete</a>
注意任务的Id包括在连接的Url中,当你点击这个链接时,任务Id传递给HomeController类的Complete()行为,数据库记录也跟着就改变了。
Index视图的最后版本显示如图6所示的页面。
图6 Index视图
小结
本文的目的是让你对构建一个ASP.NET MVC应用程序有所感性认识,我希望你仔细研究如何构建一个ASP.NET MVC Web应用程序,实际上它和构建一个asp或asp.net应用程序非常的类似。本文只分析了ASP.NET MVC框架的基本特性,在以后的文章中,我们将深入讲解控制器,控制器行为,视图,视图数据和HTML助手。
本文作者:未知