65.9K
CodeProject 正在变化。 阅读更多。
Home

ASP.NET MVC 模式应用开发简易教程

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.82/5 (41投票s)

2010年5月6日

CPOL

17分钟阅读

viewsIcon

413521

downloadIcon

18107

本文提供了一个关于使用 MVC 模式开发 ASP.NET 应用程序的简单教程。

引言

本文提供了一个关于使用 MVC 模式开发 ASP.NET 应用程序的简单教程。

背景

ASP.NET 最新的发展之一就是 MVC(Model–View–Controller)设计模式。MVC 模式将用户界面的输入和表示(GUI)与应用程序逻辑隔离开来。

根据 Scott Guthrie 的说法,MVC 模式具有以下优点:

  • 使用 MVC 方法论的好处之一是,它有助于在应用程序中强制实现模型、视图和控制器之间清晰的关注点分离。保持清晰的关注点分离使得应用程序的测试更加容易,因为不同应用程序组件之间的约定被更清晰地定义和阐述。
  • MVC 模式还可以帮助实现红/绿测试驱动开发(TDD)——即你首先实现自动化单元测试,这些测试定义和验证新代码的要求,然后再编写代码本身。

下图摘自 Wikipedia,展示了 MVC 模式。

MVCDiagram.jpg

MVC 将应用程序分为三个关注点:

  • 模型 - 封装核心应用程序数据和功能(领域逻辑)。
  • 视图 - 从模型获取数据并将其呈现给用户。
  • 控制器 - 接收输入并将其翻译成对模型或视图的请求。

Scott Guthrie 在他的 博客 中对如何将 MVC 模式应用于 ASP.NET 项目进行了非常精彩且详细的介绍。出于显而易见的原因,他的介绍非常全面且权威。对于想要理解 ASP.NET MVC 的应用程序开发人员来说,这应该是首要的参考资料。

本文旨在提供一个在 Microsoft Visual Studio 环境下开发 ASP.NET MVC 应用程序的更简单的教程,以帮助应用程序开发人员快速入门。

在处理 ASP.NET MVC 网站时,你首先会注意到访问网页的 URL 不再是熟悉的“https://codeproject.org.cn/info/search.aspx”样式。取而代之的是,URL 将看起来像 https:///VirtualDirectoryName/Controller/Action

阅读完本文后,希望你能够快速在 Visual Studio 中开发自己的 ASP.NET MVC 网站。本文旨在回答以下问题:

  • ASP.NET MVC 的 URL 如何与 Web 服务器上的资源关联?
  • 在 ASP.NET 中,模型、视图和控制器分别是什么?它们是如何实现的?
  • 模型、视图和控制器之间是如何传递信息的?
  • 服务器上的应用程序代码如何访问浏览器通过 URL 参数和表单提交传递给服务器的数据?
  • 如何在 ASP.NET MVC 中访问会话数据?
  • 在实现视图时如何使用代码隐藏文件?

本教程应用程序是在 Visual Studio 2008 中开发的,使用的语言是 C#。如果你有 Visual Studio 2010,你的环境可能会有所不同。

本文附带了本教程的源代码。最好先下载源代码并在 Visual Studio 中运行它,然后再开始阅读本教程。这样你就能更好地了解本简单教程 ASP.NET MVC 应用程序中实现的功能。这将使你阅读本文更容易。如果你无法在 Visual Studio 中加载源代码,则可能需要先设置你的开发环境。

让我们从设置开发环境开始。

设置开发环境

为了开发 MVC ASP.NET 应用程序,你需要安装 Visual Studio ASP.NET MVC 插件。如果你还没有这样做,可以访问 Microsoft 网站 下载插件并将其安装到你的计算机上。

在 Visual Studio 中创建空的 ASP.NET MVC 项目

安装 ASP.NET MVC 插件后,我们就可以开始在 Visual Studio 中创建 ASP.NET MVC 项目了。

CreateEmptyProject.jpg

我们可以创建两种类型的 ASP.NET MVC 应用程序。在本教程中,我们将创建一个“ASP.NET MVC 2 空 Web 应用程序”。将项目命名为“ASPNetMVCTutorial”,然后浏览一个你想要保存 Visual Studio 将要生成的文件所在的文件夹,并单击“OK”按钮。

项目创建后,解决方案资源管理器将包含以下内容:

SolutionExplorerBeforeCleaning.jpg

为了更好地在本 ASP.NET 开发中关注 MVC 模式,我将限制使用 JavaScript 和 CSS 样式表。让我们删除与 MVC 无关的文件夹,并添加一个名为“Utilities”的文件夹。“Utilities”文件夹稍后将用于向项目中添加一些实用程序类。清理后,解决方案资源管理器将包含以下内容:

SolutionExplorerAfterCleaningUtil.jpg

在此项目中,我们可以看到“ASP.NET MVC 2 空 Web 应用程序”模板生成的三个文件夹:

  • 模型
  • 视图
  • 控制器

模型、视图和控制器(MVC)将在本教程稍后添加到相应的文件夹中。

你还会注意到项目中存在两个“Web.config”文件。大多数配置信息将位于根文件夹中的“Web.config”文件中,而“Views”文件夹中的那个文件用于阻止直接访问视图“aspx”页面。对于大多数 ASP.NET MVC 应用程序,我们不需要更改此“Web.config”文件。

向根目录的“Web.config”文件添加一些配置

在着手创建模型、视图和控制器之前,让我们先将根目录“Web.config”文件中的“<AppSettings />”部分更改为以下内容:

<appSettings>
    <add key="ApplicationName"
            value="A Simple Tutorial on How to Develop ASP.NET
		 Web Projects in MVC Pattern"/>
    <add key="Author" value="Song Li"/>
    <add key="DevelopmentTime" value="5/4/2010"/>
    <add key="DeploymentVirtualDirectory" value=""/>
</appSettings>

此配置信息将在 ASP.NET MVC 应用程序稍后使用。

将模型类添加到“Models”文件夹

MVC 模式中的模型代表应用程序数据。在本教程中,我们将开发一个用于管理学生列表的应用程序。该应用程序将允许用户显示、添加和删除学生。右键单击“Models”文件夹并选择添加类。将类文件命名为“StudentsModel.cs”。

添加类后,我们可以按以下方式实现该类:

using System;
using System.Data;
 
namespace ASPNetMVCTutorial.Models
{
    public class StudentsModel
    {
        private DataTable Students;
 
        public StudentsModel()
        {
            Students = new DataTable();
            DataColumn IDColumn = Students.Columns.Add
				("ID", Type.GetType("System.Int32"));
            IDColumn.AutoIncrement = true;
            IDColumn.AutoIncrementSeed = 1;
            IDColumn.AutoIncrementStep = 1;
 
            Students.Columns.Add("Name", Type.GetType("System.String"));
            Students.Columns.Add("Score", Type.GetType("System.Int32"));
            Students.Columns.Add("Time Added", Type.GetType("System.DateTime"));
 
            DataColumn[] keys = new DataColumn[1];
            keys[0] = IDColumn;
            Students.PrimaryKey = keys;
 
            Random rd = new Random();
            for (int Idex = 1; Idex <= 5; Idex++)
            {
                DataRow row = Students.NewRow();
                Students.Rows.Add(row);
                row["Name"] = "Student Name No. " + Idex.ToString();
                row["Score"] = 60 + rd.NextDouble() * 40;
                row["Time Added"] = System.DateTime.Now;
            }
        }
 
        public void AddStudent(string Name, int Score)
        {
            DataRow row = Students.NewRow();
            Students.Rows.Add(row);
            row["Name"] = Name;
            row["Score"] = Score;
            row["Time Added"] = System.DateTime.Now;
        }
 
        public void DeleteStudent(int ID)
        {
            DataRow RowToDelete = Students.Rows.Find(ID);
            if (RowToDelete != null)
            {
                Students.Rows.Remove(RowToDelete);
            }
        }
 
        public DataTable GetStudents()
        {
            return Students;
        }
    }
}

此类有一个 `private` 变量“Students”。其数据类型为“DataTable”。学生信息存储在此“DataTable”中。除了构造函数外,它还公开了添加和删除学生的方法。“GetSudents”方法返回包含所有学生信息的“DataTable”给调用者。当此类的对象首次创建时,构造函数将初始化“DataTable”并向其中插入 5 个随机生成的学生。

为了让此 ASP.NET MVC 应用程序能够使用我们添加到“Web.config”文件中的配置信息,我们将添加另一个名为“ApplicationInformation.cs”的模型类文件。

using System;
using System.Configuration;
 
namespace ASPNetMVCTutorial.Models
{
    public class ApplicationInformation
    {
        private static ApplicationInformation _thisInstance = null;
        private static object _threadLock = new Object();
 
        public string ApplicationName { get; private set; }
        public string Author { get; private set; }
        public string DevelopmentTime { get; private set; }
        public string DeploymentVirtualDirectory { get; private set; }
 
        public ApplicationInformation()
        {
            ApplicationName = ConfigurationManager.AppSettings["ApplicationName"];
            Author = ConfigurationManager.AppSettings["Author"];
            DevelopmentTime = ConfigurationManager.AppSettings["DevelopmentTime"];
            DeploymentVirtualDirectory = 
		ConfigurationManager.AppSettings["DeploymentVirtualDirectory"];
        }
 
        public static ApplicationInformation GetInstance()
        {
            lock (_threadLock)
            {
                if (_thisInstance == null)
                {
                    _thisInstance = new ApplicationInformation();
                }
            }
 
            return _thisInstance;
        }
    }
}

ASP.NET MVC 项目将使用“ApplicationInformation”类来访问配置。

向“Utilities”文件夹添加一个实用程序类

为了使后续开发工作更轻松,我们将向“Utilities”文件夹添加一个名为“ApplicationUtility”的类。右键单击“Utilities”文件夹,然后选择添加类。将类文件命名为“ApplicationUtility.cs”并按以下方式实现该类:

using System;
using System.Text;
using ASPNetMVCTutorial.Models;
 
namespace ASPNetMVCTutorial.Utilities
{
    public static class ApplicationUtility
    {
        public static string FormatURL(string PathWithoutVirtualDirectoryName)
        {
            ApplicationInformation appInfomation 
                = ApplicationInformation.GetInstance();
            string DeploymentVirtualDirectory 
                = appInfomation.DeploymentVirtualDirectory;
 
            if (DeploymentVirtualDirectory == "")
            {
                return PathWithoutVirtualDirectoryName;
            }
 
            StringBuilder SB = new StringBuilder();
            SB.Append("/");
            SB.Append(appInfomation.DeploymentVirtualDirectory);
            SB.Append("/");
            SB.Append(PathWithoutVirtualDirectoryName);
 
            return SB.ToString();
        }
    }
}

静态方法“FormatURL”用于根据部署时的虚拟目录名称将 ASP.NET MVC 相对 URL 转换为绝对 URL。虚拟目录名称在“Web.config”文件中配置。在开发时,我们需要将其配置为空字符串。在部署时,我们必须在“Web.config”文件中放入正确的虚拟目录名称。

为 ASP.NET MVC 项目添加主页面

在添加视图之前,我们将先为这个 ASP.NET 项目添加一个主页面。默认情况下,ASP.NET MVC 应用程序会在 Visual Studio 中使用主页面,所以让我们先创建一个主页面。主页面将被添加到“Views\Shared”文件夹中。

右键单击“Views\Shared”文件夹并选择添加新项。

AddMasterPage.jpg

选择“Master Page”模板,将主页面命名为“Site.Master”,然后单击“Add”按钮,主页面将被添加到项目中。

我们将按以下方式实现“Site.Master”文件:

<%@ Master Language="C#" 
    CodeBehind="~/Views/Shared/Site.Master.cs"
    Inherits="ASPNetMVCTutorial.Views.Shared.Site" %>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title><asp:Literal id="litAppTitle" runat="server" /></title>
    <style type="text/css">
        .ApplicationDefault {font-family: Verdana; font-size: 10px;}
        .Title {text-align: center; font-size: 12px; color:Maroon; font-family: 
                        Verdana; font-weight: bold;}
        .AuthorInformation {text-align: center; color:green; margin-top: 5px}
        .MainContent {margin-top: 10px; background-color: #F1FFFF; height: 600px; 
                              overflow: auto; width: 95%; text-align: center;
                              margin-left:auto; margin-right:auto;}
        .Copyright {margin-top: 10px; color: Gray; font-weight:bold; width: 100%; 
                            float: left; text-align: center;}
        .ErrorText {font-family: Verdana; font-weight: bold; color:Maroon;}
        .BoldText {font-family: Verdana; font-weight: bold;}
    </style>
</head>
 
<body class="ApplicationDefault">
    <div class="Title">
        <asp:Literal id="litApplicationName" runat="server" />
    </div>
    <div class="AuthorInformation">
        <asp:Literal id="litAuthorInformation" runat="server" />
    </div>
    
    <div id="MainContent" class="MainContent">
        <asp:ContentPlaceHolder id="ApplicationContent" runat="server" />
    </div>
    <div class="Copyright">Copy right: The Code Project Open License (CPOL)</div>
</body>
</html>

我们将按以下方式实现代码隐藏文件“Site.Master.cs”:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Text;
using System.Web.UI.WebControls;
using ASPNetMVCTutorial.Models;
using ASPNetMVCTutorial.Utilities;
 
namespace ASPNetMVCTutorial.Views.Shared
{
    public partial class Site : System.Web.Mvc.ViewMasterPage
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            ApplicationInformation appInfomation = ApplicationInformation.GetInstance();
            litAppTitle.Text = appInfomation.ApplicationName;
            litApplicationName.Text = appInfomation.ApplicationName;
 
            StringBuilder SB = new StringBuilder();
            SB.Append("Developed by ");
            SB.Append(appInfomation.Author);
            SB.Append(" on ");
            SB.Append(appInfomation.DevelopmentTime);
            litAuthorInformation.Text = SB.ToString();
        }
    }
}

主页面将用于整个项目,以控制显示样式并显示有关应用程序的一些通用信息。

将视图添加到“Views”文件夹

ASP.NET MVC 中的视图实际上是特殊的“aspx”页面。在此项目中,我们将添加三个视图:

  • StudentList.aspx
  • AddStudent.aspx
  • Error.aspx

StudentList.aspx”用于列出所有学生,并提供用户交互以导航到“AddStudent.aspx”视图来添加学生。它还提供删除学生的交互功能。“Error.aspx”视图用于显示操作过程中可能发生的任何错误。

StudentList.aspx”和“AddStudent.aspx”视图将添加到“Views\Students”文件夹中,“Error.aspx”将添加到“Views\Shared”文件夹中。右键单击“Views”文件夹并向其中添加一个“Students”文件夹。然后我们可以添加“StudentList.aspx”视图。右键单击“Views\Students”文件夹并添加视图。

AddView.jpg

将视图命名为“StudentList”,选择主页面“Site.Master”,将 `ContentPlaceHolderID` 输入为“ApplicationContent”,然后单击“Add”按钮。在解决方案资源管理器中,视图作为“StudentList.aspx”文件创建在“Views\Students”文件夹中。

AddViewWithoutCodeBehind.jpg

你可能会惊讶地发现“StudentList.aspx”视图没有熟悉的代码隐藏文件。关于是否应该在 ASP.NET MVC 视图中使用代码隐藏文件,这是一个热门的讨论。有些人称在视图中使用代码隐藏文件是“邪恶的”,而另一些人则认为它“并非邪恶”。我不会深入讨论这个话题。我只是觉得如果应用程序开发人员选择使用代码隐藏文件,他们应该有使用的选项。我们将手动为“StudentList.aspx”添加代码隐藏文件。

右键单击“Views\Students”文件夹并添加一个名为“StudentList.aspx.cs”的类文件。“StudentList.aspx.cs”文件将自动实现一个名为“StudentList”的类。使“SudentList”类继承自“System.Web.Mvc.ViewPage”。在“StudentList.aspx”文件中,添加指向“StudentList.aspx.cs”的“CodeBehind”引用,并将“Inherits”值更改为“StudentList”类。通过这样做,代码隐藏文件将被手动添加到解决方案资源管理器中。

AddViewWithCodeBehind.jpg

添加代码隐藏文件后,我们将按以下方式实现“StudentList.aspx”:

<%@ Page Language="C#"
    MasterPageFile="~/Views/Shared/Site.Master"
    CodeBehind="~/Views/Students/StudentList.aspx.cs"
    Inherits="ASPNetMVCTutorial.Views.Students.StudentList" %>
 
<asp:Content id="IndexContent" ContentPlaceHolderID="ApplicationContent" runat="server">
    <div style="float: right; margin-right: 10px">
        <asp:HyperLink id="linkAddStudent" runat="server" 
		Text="Click to add a student to the list" />
    </div>
    <br />
    <div style="margin-top: 5px">
        <asp:Literal id="litStudentDetail" runat="server" />
    </div>
</asp:Content>

代码隐藏文件“StudentList.aspx”将按以下方式实现:

using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Data;
using System.Web.UI.WebControls;
using ASPNetMVCTutorial.Models;
using ASPNetMVCTutorial.Utilities;
 
namespace ASPNetMVCTutorial.Views.Students
{
    public class StudentList : System.Web.Mvc.ViewPage
    {
        protected Literal litStudentDetail;
        protected HyperLink linkAddStudent;
 
        protected void Page_Load(object sender, EventArgs e)
        {
            Response.Cache.SetCacheability(HttpCacheability.NoCache);
 
            linkAddStudent.NavigateUrl = 
                ApplicationUtility.FormatURL("/Students/AddStudent");
 
            DataTable StudentsTable = (DataTable)ViewData["Students"];
            DataView StudentsView = StudentsTable.DefaultView;
            StudentsView.Sort = "ID Desc";
 
            StringBuilder SB = new StringBuilder();
 
            SB.Append("<table style=\"width: 99%;\" ");
            SB.Append("rules=\"all\" border=\"1px\" ");
            SB.Append("cellspacing=\"0px\" cellpadding=\"4px\">");
 
            SB.Append("<tr style=\"background-color: Silver; color: white; ");
            SB.Append("font-weight: bold\">");
            foreach (DataColumn aColumn in StudentsTable.Columns)
            {
                SB.Append("<td>");
                SB.Append(aColumn.ColumnName);
                SB.Append("</td>");
            }
            SB.Append("<td>&nbsp;</td>");
            SB.Append("</tr>");
 
            foreach (DataRowView aRowView in StudentsView)
            {
                SB.Append("<tr>");
                foreach (DataColumn aColumn in StudentsTable.Columns)
                {
                    SB.Append("<td>");
                    SB.Append(aRowView[aColumn.ColumnName].ToString());
                    SB.Append("</td>");
                }
 
                string ID = aRowView["ID"].ToString();
                SB.Append("<td>");
                SB.Append("<a href=\"");
                SB.Append(ApplicationUtility.FormatURL("/Students/DeleteStudent"));
                SB.Append("?ID=");
                SB.Append(ID);
                SB.Append("\">Delete this student</a>");
                SB.Append("</td>");
                SB.Append("</tr>");
            }
 
            SB.Append("</table>");
 
            litStudentDetail.Text = SB.ToString();
        }
    }
}

同样,我们将按以下方式将“AddStudent.aspx”实现到“Views\Students”文件夹中:

<%@ Page Language="C#"
    MasterPageFile="~/Views/Shared/Site.Master"
    CodeBehind="~/Views/Students/AddStudent.aspx.cs"
    Inherits="ASPNetMVCTutorial.Views.Students.AddStudent" %>
 
<asp:Content ID="AddStudentContent" 
    ContentPlaceHolderID="ApplicationContent" runat="server">
<script language="javascript" type="text/javascript">
    function SubmitForm() {
        frmAddStudent.action = hidAddstudentActionURL.value;
        frmAddStudent.submit();
    }
</script>
 
<asp:Literal ID="litAddStudentActionHidden" runat="server" />
<form id="frmAddStudent" method="post" action="">
<div style="text-align: center">
    <table cellspacing="5px" cellpadding="0px" style="text-align: 
        center; margin-left:auto; margin-right:auto;">
        <tr>
            <td class="BoldText" style="text-align: left">
                Please provide the following information to add the student:
            </td>
        </tr>
        <tr><td style="height: 10px"></td></tr>
        <tr>
            <td>
                Name&nbsp;<input type="text" id="textName" name="textName" />
                &nbsp;&nbsp;
                Score&nbsp;<input type="text" id="txtScore" name="txtScore" />
            </td>
        </tr>
        
        <tr>
            <td>
                <asp:HyperLink ID="linkCancelAddStudent" 
                    Text="Cancel add student and 
			return to the main page" runat="server" />
                <input type="button" value="Add student" onclick="return SubmitForm()" />
            </td>
        </tr>
    </table>
</div>
</form>
</asp:Content>

AddStudent.aspx”视图的代码隐藏文件将按以下方式实现:

using System;
using System.Text;
using System.Web;
using System.Web.UI.WebControls;
using ASPNetMVCTutorial.Models;
using ASPNetMVCTutorial.Utilities;
 
namespace ASPNetMVCTutorial.Views.Students
{
    public class AddStudent : System.Web.Mvc.ViewPage
    {
        protected HyperLink linkCancelAddStudent;
        protected Literal litAddStudentActionHidden;
        protected void Page_Load(object sender, EventArgs e)
        {
            Response.Cache.SetCacheability(HttpCacheability.NoCache);
 
            StringBuilder SB = new StringBuilder();
            SB.Append("<input type=\"hidden\" id=\"hidAddstudentActionURL\" value=\"");
            SB.Append(ApplicationUtility.FormatURL("/Students/AddStudentAction"));
            SB.Append("\" />");
            linkCancelAddStudent.NavigateUrl
                = ApplicationUtility.FormatURL("/Students/StudentList");
            litAddStudentActionHidden.Text = SB.ToString();
        }
     }
}

Error.aspx”视图将在“Views\Shared”文件夹中按以下方式实现:

<%@ Page Language="C#"
    CodeBehind="~/Views/Shared/Error.aspx.cs"
    MasterPageFile="~/Views/Shared/Site.Master" 
    Inherits="ASPNetMVCTutorial.Views.Shared.Error" %>
 
<asp:Content ID="ErrorContent" ContentPlaceHolderID="ApplicationContent" runat="server">
<div style="margin-top: 10px; text-align: center">
    <table cellpadding="4px" cellspacing="4px" style="margin-left:auto; 
	margin-right:auto;">
        <tr><td class="ErrorText"><asp:Literal ID="litErrorMessage" 
		runat="server" /></td></tr>
        <tr><td style="text-align: right">
            <asp:HyperLink ID="linkBackToMainPage" Text="Go back to main page" 
		runat="server" />
        </td></tr>
    </table>
</div>
</asp:Content>

Error.aspx”的代码隐藏文件将按以下方式实现:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI.WebControls;
using ASPNetMVCTutorial.Models;
using ASPNetMVCTutorial.Utilities;
 
namespace ASPNetMVCTutorial.Views.Shared
{
    public class Error : System.Web.Mvc.ViewPage
    {
        protected Literal litErrorMessage;
        protected HyperLink linkBackToMainPage;
 
        protected void Page_Load(object sender, EventArgs e)
        {
            Response.Cache.SetCacheability(HttpCacheability.NoCache);
 
            linkBackToMainPage.NavigateUrl
                = ApplicationUtility.FormatURL("/Students/StudentList");
            string ErrorMessage = ViewData["ERROR"].ToString();
            litErrorMessage.Text = ErrorMessage;
        }
    }
}

ASP.NET MVC 视图是专门的 ASP.NET 页面。“System.Web.Mvc.ViewPage”类是类继承层次结构中“System.Web.UI.Page”类的直接子类。在开发视图时,为了更好地遵循 MVC 方法论,避免对应用程序数据进行任何修改非常重要。

将控制器添加到“Controllers”文件夹

现在我们可以为这个 ASP.NET MVC 项目添加控制器了。右键单击“Controllers”文件夹以添加控制器类,并将类命名为“StudentsController”,并按以下方式实现此 `controller` 类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using ASPNetMVCTutorial.Models;
 
namespace ASPNetMVCTutorial.Controllers
{
    public class StudentsController : Controller
    {
        private StudentsModel GetStudentModelFromSession()
        {
            StudentsModel theModel = (StudentsModel)Session["Students"];
            if (theModel == null)
            {
                theModel = new StudentsModel();
                Session["Students"] = theModel;
            }
 
            return theModel;
        }
 
        public ActionResult StudentList()
        {
            StudentsModel theModel = GetStudentModelFromSession();
 
            ViewData["Students"] = theModel.GetStudents();
            return View();
        }
 
        public ActionResult AddStudent()
        {
            return View();
        }
 
        public ActionResult AddStudentAction()
        {
            string Name = Request.Form["textName"];
            string Score = Request.Form["txtScore"];
 
            if ((Name == null) || (Name.Trim() == ""))
            {
                ViewData["ERROR"] = "Please provide a name for the student to add";
                return View("../Shared/Error");
            }
 
            if (Name.Length < 6)
            {
                ViewData["ERROR"]
                    = "The student's name should not be less than 6 characters.";
                return View("../Shared/Error");
            }
  
            int intScore;
            if (!Int32.TryParse(Score, out intScore))
            {
                ViewData["ERROR"]
                    = "Please provide a valid score to the student to add.";
                return View("../Shared/Error");
            } 
 
            if ((intScore < 60) || (intScore > 100))
            {
                ViewData["ERROR"]
                    = "We only accept students with scores between 60 and 100.";
                return View("../Shared/Error");
            }
 
            StudentsModel theModel = GetStudentModelFromSession();
            theModel.AddStudent(Name, intScore);
 
            ViewData["Students"] = theModel.GetStudents();
            return View("StudentList");
        }
 
        public ActionResult DeleteStudent()
        {
            string ID = Request.QueryString["ID"];
            int intID;
 
            if (!Int32.TryParse(ID, out intID))
            {
                ViewData["ERROR"] = "Please provide a valid student ID";
                return View("../Shared/Error");
            }
 
            StudentsModel theModel = GetStudentModelFromSession();
            theModel.DeleteStudent(intID);
 
            return RedirectToAction("StudentList");
        }
    }
}

此控制器名为“StudentsController”。它实现了 5 个方法。

私有方法“GetStudentModelFromSession”用于演示在此 ASP.NET MVC 项目中如何使用 Web 会话。它返回“StudentsModel”类型的对象,该对象在“Models”文件夹中实现。该方法首先尝试从 Web 会话中获取此对象。如果无法获取,它将创建一个新对象并将其添加到 Web 会话中。此对象将用作本教程 Web 应用程序中的数据存储。

四个 `public` 方法在 ASP.NET MVC 术语中称为“`actions`”(操作):

  • StudentList
  • AddStudent
  • AddStudentAction
  • DeleteStudent

这些方法用于对 Web 会话中保存的应用程序数据执行某些操作。当应用程序数据操作完成后,每个方法将选择一个在“Views”文件夹中实现的视图来向用户显示数据。如果所选视图的名称与“action”的名称相同,则可以省略视图的名称。要访问用户从浏览器输入的输入,这些方法可以使用熟悉的“Request.QueryString”和“Request.Form”方法。

操作方法通过“ViewData”字典传递要显示给视图的数据。

"Global.asax" - 魔术发生的地方

当我们创建 ASP.NET MVC 项目时,Visual Studio 会为我们生成一个默认的“Global.asax”文件。现在我们将对此文件进行如下更改:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
 
namespace ASPNetMVCTutorial
{
    public class MvcApplication : System.Web.HttpApplication
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
 
            routes.MapRoute(
                "Default",
                "{controller}/{action}/{id}",
                new { controller = "Students", 
                    action = "StudentList", 
                    id = UrlParameter.Optional }
            );
        }
 
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
 
            RegisterRoutes(RouteTable.Routes);
        }
    }
}

访问 ASP.NET MVC 项目中开发的网页的 URL 格式为“https:///VirtualDirectoryName/Controller/Action”。在“Global.asax”文件中调用“routes.MapRoute”方法确保了正确控制器和操作的定位。如果 URL 未指定控制器和操作,则将默认使用“Student”控制器和“StudentList”操作。

当 Web 应用程序接收到 URL 时,它首先会找到控制器。如果 URL 中的控制器是“Student”,Web 应用程序将尝试在“Controllers”文件夹中查找名为“StudentController”的类。在找到控制器类之后,将调用与操作同名的方法,例如“StudentList”。控制器类中选定的操作方法将执行应用程序数据上的所有操作,并选择一个视图来显示给用户。操作方法通过“ViewData”字典传递要显示给视图的数据。

如果你想在同一个 ASP.NET 项目中混合使用常规的“aspx”页面和 MVC 视图,可以在映射 ASP.NET MVC 路由之前添加以下代码:

routes.IgnoreRoute("{resource}.aspx/{*pathInfo}");  

这样,路由将忽略指向常规“aspx”页面的 URL。这些页面将直接加载,而无需经过控制器-操作-视图模式。

解决方案资源管理器中显示的已完成项目

现在我们完成了本教程 ASP.NET MVC 应用程序的开发。下图显示了解决方案资源管理器中包含代码隐藏文件的所有文件:

SolutionExplorerComplete.jpg

运行 ASP.NET MVC 应用程序

当 Visual Studio 获得焦点时按下“F5”,我们可以开始调试运行本教程应用程序。下图显示了应用程序在“Google Chrome”中运行的样子:

RunApplicationList.jpg

单击其中一个“Delete this student”(删除该学生)链接,我们可以从列表中删除该学生。单击“Click to add a student to the list”(点击添加学生到列表)链接,网页将导航到以下内容:

RunApplicationAdd.jpg

输入学生姓名并为其评分,然后单击“Add student”(添加学生)按钮,我们就可以看到学生已被添加。

RunApplicationComplete.jpg

关注点

  • 本教程旨在帮助读者在 Visual Studio 中快速入门 ASP.NET MVC 应用程序的开发。它可能不完全遵循 Scott Guthrie 的方法,甚至不完全遵循通用的 MVC。如果存在任何差异,你应始终以 Scott Guthrie 的为准。
  • 关于视图是否应使用代码隐藏文件,我不想深入讨论。我认为最好将此选择留给应用程序开发人员。如果 MVC 模式是为了分离应用程序开发中的关注点,为什么我们不进一步分离视图开发中的关注点呢?在本教程中,所有视图都有代码隐藏文件。
  • 值得注意的是,ASP.NET MVC 模式与 WPF 开发中的 MVVM 模式不同。在 MVVM 中,我们有更成熟的双向数据绑定,这使得 MVVM 能够最大限度地减少 XAML 文件的代码隐藏文件使用。但在 ASP.NET MVC 模式中,控制器通过“ViewData”字典将数据传递给视图进行显示。在视图中,如果我们不使用代码隐藏文件,我们将需要使用“aspx”文件中的内联服务器脚本,这使得视图的单元测试几乎不可能。
  • 本 MVC 教程中的“Model”部分是一个存储在 Web 会话中的“DataTable”。通过这样做,读者只需 Visual Studio 即可完成本教程。对于任何实际的 ASP.NET MVC 应用程序,都需要持久数据存储。
  • 实用程序类“ApplicationUtility”中的“FormatURL”方法是为了确保即使在部署时虚拟目录名称发生更改,我们也能始终获得正确的 ASP.NET MVC 模式 URL。有许多方法可以达到相同的目标。如果你不喜欢此方法,可以随时实现自己的方法。
  • 开发在浏览器中运行的应用程序本质上是一项综合性任务。结合所有可用的技术,如 CSS 样式表、JavaScript、Ajax、jQuery、Silverlight 以及 MVC 模式,以提供最佳的性能和用户体验,总是更好的。

结论

为了完成本教程,我们将回答文章开头列出的问题:

  • ASP.NET MVC 的 URL 如何与 Web 服务器上的资源关联?
    • ASP.NET MVC 应用程序的 URL 包含控制器部分和操作部分,应用程序将使用控制器部分来定位控制器类,并使用操作部分来定位控制器类中实现的操作方法。当操作方法完成应用程序数据的操作后,它将选择一个视图来显示应用程序数据。
  • 在 ASP.NET 中,模型、视图和控制器分别是什么?它们是如何实现的?
    • 在 Visual Studio 创建的标准 ASP.NET MVC 应用程序中,有三个名为“Models”、“Views”和“Controllers”的文件夹。模型、视图和控制器将在相应的文件夹中实现。
    • 模型代表应用程序数据。在本教程中,它是一个存储在应用程序 Web 会话中的“DataTable”。
    • 视图是特殊的 ASP.NET“aspx”页面,视图的开发与“System.Web.UI.Page”类型的“aspx”页面的开发非常相似。
    • 控制器是实现操作的类。每个操作将可选地对应用程序数据执行一些操作,并选择一个视图来显示数据。
  • 模型、视图和控制器之间是如何传递信息的?
    • 控制器如何访问模型中实现的应用数据应是一个设计问题,应由应用程序开发人员根据业务需求决定。
    • 控制器可以通过“ViewData”字典传递要显示给视图的数据。
  • 服务器上的应用程序代码如何访问浏览器通过 URL 参数和表单提交传递给服务器的数据?
    • 本教程演示了应用程序可以使用熟悉的“Request.QueryString”和“Request.Form”来访问用户输入数据。为了遵循 MVC 方法论,用户输入数据应在控制器中访问,而不是在视图中。
  • 如何在 ASP.NET MVC 中访问会话数据?
    • 本教程演示了在开发“System.Web.UI.Page”类型的“aspx”页面时,Web 会话的使用方式与平常相同。为了遵循 MVC 方法论,会话数据应在控制器中访问,而不是在视图中。
  • 如何在实现视图时使用代码隐藏文件?
    • 在 Visual Studio 中,可以通过手动添加视图的代码隐藏文件。关于是否应该为视图使用代码隐藏文件,存在一个热门的讨论,但如果你喜欢使用代码隐藏文件,也可以添加它们。如果我们不使用代码隐藏文件,我们将在视图中使用内联服务器脚本。

历史

这是本文的第一个修订版。

© . All rights reserved.