原文链接:http://www.asp.net/learn/mvc/tutorial-01-cs.aspx
这篇教程的目的是让你了解如何创建一个Asp.Net MVC应用程序。在教程中,我从头至尾快速地创建了一个完整的Asp.Net应用程序。我向你演示了如何创建一个简单的任务列表(Tasklist)应用程序。
如果你曾经使用过动态服务器页(ASP)或者ASP.NET,那么你应该会发现ASP.NET MVC非常熟悉。ASP.NET MVC的视图非常类似于ASP中的页面。并且,正如一个传统的ASP.NET Web窗体应用程序,ASP.NET MVC为你提供了对.NET框架所提供的丰富的语言和类集的完全访问。
我希望这篇教程将会给你这样一种感觉:创建一个ASP.NET MVC应用程序的过程与创建一个ASP或者ASP.NET Web窗体应用程序既相似又有所区别。
1. 任务列表应用程序
简单起见,我们将会创建一个非常简单的任务列表(TaskList)应用程序。我们的这个简单的任务列表应用程序将会允许我们做下面三件事:
- 列出任务集合
- 创建新任务
- 将一个任务标识为已完成
同样,简单起见,我们使用了创建应用程序所需的ASP.NET MVC框架的最少数量的功能。举个例子,我们不会利用测试驱动开发或者HTML帮助方法。
1.1 准备工作
为了创建一个ASP.NET MVC应用程序,你需要Visual Studio 2008或者是Visual Web Developer 2008 Express。你也需要下载ASP.NET MVC框架。如果你没有自己的Visual Studio 2008,那么你可以从这个站点下载一个Visual Studio 2008的90天试用版本:
http://msdn.microsoft.com/en-us/vs2008/products/cc268305.aspx
除此以外,你可以使用Visual Web Developer Express 2008创建ASP.NET MVC应用程序。如果你选择使用 Visual Web Developer Express,那么你必须安装Service Pack 1。你可以从下面的站点下载到Visual Web Developer Express 2008和Service Pack 1。
在你安装好Visual Studio 2008或者Visual Web Developer 2008之后,你需要安装ASP.NET MVC框架。你可以从下面的站点下载到ASP.NET MVC框架:
1.2 创建一个ASP.NET MVC Web应用程序项目
让我们在Visual Studio 2008中创建一个新的ASP.NET MVC Web应用程序项目作为开始。选择菜单选项,“文件(File)”、“新建项目(New Project)”,然后你将会看到新建项目对话框,如图1所示。选择你最喜欢的编程语言(Visual Basic或者Visual C#),并且选择ASP.NET MVC Web应用程序项目。将项目命名为TaskList,然后点击“确定(OK)”按钮。
图1. 新建项目对话框
不论何时创建一个MVC Web应用程序项目,Visual Studio都会询问你是否创建一个单独的单元测试项目。出现图2所示的对话框。因为时间限制,所以我们不想在这篇教程中创建测试项目(是的,我们应该为此感到一丝愧疚),选择“否(NO)”选项,然后点击“确定(OK)”按钮。
图2.创建单元测试项目的对话框
一个ASP.NET MVC应用程序拥有一系列标准的文件夹:一个Models、Views和Controllers文件夹。你可以在解决方案浏览器窗口中看到这些标准的文件夹。我们将需要向Models、Views和Controllers中添加文件来创建我们的TaskList应用程序。
当你使用Visual Studio创建一个新的MVC应用程序,将会获得一个范例应用程序。因为我们想从零做起,所以需要删除这个范例应用程序的内容。你需要删除下面的文件和文件夹:
- Controllers"HomeController.cs
- Views"Home
1.3 创建控制器
典型地,当我们创建一个ASP.NET MVC应用程序时,你将以创建一个控制器(Controller)作为开始。每一个对ASP.NET MVC应用程序的请求对会由一个控制器处理。一个控制器包含了响应一个请求的应用程序逻辑。
通过右键点击控制器文件夹,并且在菜单项中选择“添加(Add)”、“新建项(New Item)” ,向你的Visual Studio项目中添加一个新的控制器。选择“MVC Controller Class”模板。将你的新控制器命名为HomeController.cs并且点击“添加(Add)”按钮。
对于我们的任务列表应用程序,我们修改HomeController类,使它包含清单1中的代码。修改后的控制器含有四个方法,名为Index()、Create()、CreateNew()和Complete()。每一个方法对应于一个控制器的动作。
代码清单1 – HomeController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using TaskList.Models;
namespace TaskList.Controllers {
public class HomeController : Controller {
// 显示任务列表
public ActionResult Index() {
return View();
}
// 显示一个表单用于创建新任务
public ActionResult Create() {
return View();
}
// 向数据库中添加一个新任务
public ActionResult CreateNew() {
return RedirectToAction("Index");
}
// 将一个任务标识为已完成
public ActionResult Complete() {
// CODE:数据库逻辑
return RedirectToAction("Index");
}
}
}
这里是这些控制器动作背后的意图:
- Index() – 当你想要显示一个任务列表时被调用。
- Create() – 当你想要显示一个用于添加新任务的表单时被调用。
- CreateNew() – 当添加新任务的表单被提交时调用。这个控制器动作实际地将新任务添加到数据库中。
- Complete() – 当新任务被标识为完成时调用。
我们需要添加额外的逻辑到我们的控制器动作中,以使它们能够按照预期工作。
包含在控制器类中的任何公共方法,都被暴露为控制器动作。注意这里。一个控制器动作被暴露给了全世界。任何人都可以通过在Web浏览器的地址栏中输入正确的URL来调用控制器动作。因此,在你并不需要方法被调用时,不要随意地在控制器中创建公共方法。
注意到控制器动作返回一个ActionResult。ActionResult代表着动作将要完成的事情。前两个控制器动作,Index()和Create(),返回了一个MVC视图。第三个和第四个动作的结果是重定向用户到另一个控制器动作。
这便是这些控制器动作如何工作了。当你请求Create()控制器动作时,返回了一个视图,该视图含有用于创建新任务的表单。当你提交这个表单,将会调用CreateNew()控制器动作。CreateNew控制器动作将新任务添加到了数据库中,并且将用户重定向到了Index()控制器动作。Index()控制器动作返回了一个视图,这个视图显示了完整的任务列表。最后,如果你将一个任务标识为已完成,会调用Compete()控制器动作,并更新数据库。Complete()控制器将用户重定向回Index()动作,并且显示已更新的任务列表。
1.4 创建视图
视图含有发往浏览器的HTML标记和内容。在ASP.NET MVC应用程序中视图与页面最为相似。你可以通过创建一个后缀名为.aspx的文件来创建一个视图。
你必须将视图放置在正确的位置。如果你正在为HomeController的Index()动作方法创建视图,那么你必须将视图放置在符合如下路径的文件夹下:
"Views"Home"Index.aspx
如果你正在ProductController的Price()动作方法创建一个视图,那么视图必须被放置在下面的文件夹中:
"Views"Product"Price.aspx
默认情况下,视图应该和与其相应的控制器动作拥有相同的名称。视图同样应该被置于一个文件夹中,该文件夹与控制器的名称相对应。
通过在Views文件夹下的子文件夹上点击右键,并且选择菜单项“添加(Add)”,“新建项(New Item)”,可以创建一个视图。选择“MVC 视图页面(MVC View Page)” 模板来添加一个新的视图。我们需要按下面的路径创建两个视图:
"Views"Home"Index.aspx
"Views"Home"Create.aspx
在你创建好这两个视图以后,你的解决方案浏览器窗口应该含有如图3所示的文件:
图3. Index.aspx和Create.aspx视图
一个视图可以包含HTML内容和脚本。Index.aspx视图将会被用于显示所有任务的列表。为了说明这个视图的目的,在Index.aspx视图中添加清单2中的代码。
代码清单2 – Index.aspx
<%@ Page Language="C#" AutoEventWireup="false" CodeBehind="Index.aspx.cs" Inherits="TaskList.Views.Home.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="C#" AutoEventWireup="false" CodeBehind="Create.aspx.cs" Inherits="TaskList.Views.Home.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="description">Task:</label>
<input type="text" name="description" />
<br />
<input type="submit" value="Add Task" />
</form>
</div>
</body>
</html>
注意到清单3中包含的表单提交到了下面的URL:
/Home/CreateNew.aspx
这个URL对应于HomeController控制器中的CreateNew()动作。代表着新任务的表单数据将会提交到这个动作。
1.5 创建数据库
下一步是创建含有任务的数据库。你可以通过在App_Data文件夹上点击右键,并且选择菜单项,“添加(Add)”、“新建项(New Item)”来创建数据库。选择“SQL Server数据库”模板项,将数据库命名为TaskListDB.mdf,并且点击“添加(Add)”按钮。
接下来,我们需要向数据库中添加一张含有任务的表。在解决方案浏览器窗口中双击TaskListDB.mdf以打开服务器浏览器窗口。右键点击“表”文件夹,并且选择“添加新表(Add New Table)”菜单项。选择这个菜单项将会打开数据库表设计器。创建下面的数据库列:
列名 | 数据类型 | 是否允许NULL |
Id | Int | False |
Task | NVarchar(300) | False |
IsCompleted | Bit | False |
EntryDate | DateTime | False |
第一列,Id列,有两个特殊的属性。首先,你需要将Id标记为主键列。在选择Id列之后,点击“设置主键(Set Primary Key)”按钮(这是一个看上去像钥匙的图标)。第二步,你需要将Id列标记为标识列(Identity Column)。在列属性窗口,向下滚动到“标识详细信息(Identity Specification)”一节并展开它。将“是否为标识(Is Identity)”值改为Yes。当你做完这些以后,表格将会如图4所示。
图4. Tasks表格
最后一步是保存这个新的表格。点击“保存(Save)”按钮(软盘的图标)并且将新表格命名为Tasks。
1.6 创建模型
一个MVC模型包含了你的应用程序和数据库访问的大部分逻辑。通常,你可以将包含在MVC应用程序中的大部分类都放在Models文件夹中。你的应用程序中所有没有包含在视图或者控制器的逻辑都被推向了Models文件夹。
在这篇教程中,我们将会使用LINQ to SQL来与我们上一小节创建的数据库通信。就我自己而言,我喜欢LINQ to SQL。然而,并不要求你一定在ASP.NET MVC应用程序中使用LINQ to SQL。如果你愿意,你可以使用其他的技术,例如NHibernate或者Entity Framework来与数据库进行通信。
为了使用LINQ to SQL,我们必须首先在Models文件夹中创建我们的LINQ to SQL类。右键点击Models文件夹,选择“添加”、“新建项”菜单项,并且选择“LINQ to SQL Classes”模板项。将你新建的LINQ to SQL类命名为TaskList.dbml并且点击“添加(Add)”按钮。在你完成这一步骤之后,将会显示对象关系设计器(Object Relational Designer)。
我们需要创建一个LINQ to SQL实体类,它代表了我们的Tasks数据库表。将Tasks数据库表从解决方案浏览器窗口拖曳到对象关系设计器中。执行完最后这一个动作,将会创建一个新的名为Task的LINQ to SQL实体类(参看图5)。点击“保存(Save)”按钮(软盘的图标)以保存这个新的实体。
图5 - Task实体
1.7 向控制器方法中添加数据库逻辑
现在我们已经拥有了数据库,我们可以修改我们的控制器动作,以便从数据库中存储和获取任务。修改后的HomeController包含在清单4中。
清单4 - HomeController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using TaskList.Models;
namespace TaskList.Controllers {
public class HomeController : Controller {
private TaskListDataContext db = new TaskListDataContext();
// 显示任务列表
public ActionResult Index() {
var tasks = from t in db.Tasks
orderby t.EntryDate
descending select t;
return View(tasks.ToList());
}
// 显示创建新任务的表单
public ActionResult Create() {
return View();
}
// 向数据库中添加一个新任务
public ActionResult CreateNew(string description) {
Task newTask = new Task();
newTask.Description = description;
newTask.IsCompleted = false;
newTask.EntryDate = DateTime.Now;
db.Tasks.InsertOnSubmit(newTask);
db.SubmitChanges();
return RedirectToAction("Index");
}
// 将任务标记为任务
public ActionResult Complete(int Id) {
// 数据库逻辑
var tasks = from t in db.Tasks where t.Id == Id select t;
foreach (Task match in tasks)
match.IsCompleted = true;
db.SubmitChanges();
return RedirectToAction("Index");
}
}
}
注意到清单4中的HomeController含有一个类级(class-level)的私有字段,名为db。这个db字段是一个TaskListDataContext类的实例。HomeController类使用db字段来代表TaskListDB数据库。
Index()控制器的动作已经被修改为获得所有来自Tasks数据库表的记录。tasks被传递到了Index视图中。
CreateNew()方法被修改为在Tasks数据库表中创建一个新的任务。注意到CreateNew()方法已经被修改为接受一个名为description的字符串参数。这个参数代表着由Create视图传递进来的description文本表单字段。ASP.NET MVC框架自动将表单字段作为参数传递给控制器动作。
最后,Complete()方法被修改为更改Tasks数据库表的IsComplete列的值。当你将一个任务标记为已完成,任务的Id被传递给Complete()动作,并更新数据库。
1.7 修改Index视图
为了完成我们的TaskList应用程序,我们还必须再做最后一件事。我们必须修改Index视图,以便它能够显示所有任务的列表,并且允许我们将某一任务标记为已完成。修改过的Index视图包含在了清单5中。
清单5 - Index.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="TaskList.Views.Home.Index" %>
<%@ Import Namespace="TaskList.Models" %>
<!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>Index</title>
</head>
<body>
<div>
<h1>My Tasks</h1>
<ul>
<% foreach (Task task in (IEnumerable)ViewData.Model) { %>
<li>
<% if (task.IsCompleted) {%>
<del>
<%= task.EntryDate.ToShortDateString() %>
-- <%=task.Description%>
</del>
<% } else {%>
<a href="/Home/Complete/<%= task.Id.ToString() %>">Complete</a>
<%= task.EntryDate.ToShortDateString() %>
-- <%=task.Description%>
<% }%>
</li>
<% } %>
</ul>
<br /><br />
<a href="/Home/Create">Add new Task</a>
</div>
</body>
</html>
在清单5中的Index视图含有一个C# foreach循环,它遍历了所有的任务。这些任务由ViewData.Model属性所表示。概括来讲,你使用ViewData来将数据从控制器传递到视图。
在循环体内部,有一个条件判断用来检查任务是否已完成。一个已完成的任务使用一个穿过它的横线(删除线)来表示。HTML的<del>标签用来创建横穿已完成任务的横线。如果这个任务还没有完成,将在任务旁边显示一个标记为Complete的链接。这个链接由下面的脚本创建:
<a href="/Home/Complete/<%= task.Id.ToString() %>">Complete</a>
注意到任务的Id被包含在由链接所表示的URL中。当你点击链接时,这个任务Id将会传递到HomeController类的Complete()动作中。通过这种方式,当你点击Complete链接时,将会更新正确的数据库记录。
Index视图的最终版本所显示的页面位于图6中。
图6 - Index视图
1.8 总结
这篇教程的目的是让你体验一下创建一个ASP.NET MVC应用程序的经过。我希望你会发现创建一个ASP.NET MVC Web应用程序与创建一个动态服务器页面(ASP)或者ASP.NET应用程序的经历非常类似。
在这篇教程中,我们只考察了ASP.NET MVC框架中最基本的一些功能。在后续的教程中,我们将会更加深入到一些主题,例如控制器、控制器动作、视图、视图数据和HTML helper中。