Asp.Net MVC(理解模型、视图和控制器) - Part.2

原文链接:http://www.asp.net/learn/mvc/tutorial-02-cs.aspx

这篇教程将为你提供ASP.NET MVC模型、视图、控制器的高层次概览。换言之,它解释了ASP.NET MVC中的“M”、“V”和“C”。

在读完本教程之后,你应该能够理解ASP.NET MVC应用程序中的各个不同部分是如何一起工作的。你也应该能够理解ASP.NET MVC应用程序与ASP.NET Web窗体应用程序和动态服务器页面应用程序在构架上有何不同。

1. 范例ASP.NET MVC应用程序

Visual Studio用于创建ASP.NET MVC Web应用程序的默认模板包括了一个极其简单的范例应用程序,可以使用它来理解ASP.NET MVC应用程序的各个部分。我们将会在这篇教程中利用这个简单的应用程序。

你可以通过启动Visual Studio2008,并且在菜单中选择“File(文件)”、“New Project(新建项目)”来使用MVC模板创建一个新的ASP.NET MVC应用程序(如图1)。在“新建项目”对话框,在项目类型下选择你喜欢的编程语言(Visual Basic或者C#),并且在模板下选择ASP.NET MVC Web应用程序。点击“确定”按钮。

图1 - 新建项目对话框

当你创建一个新的ASP.NET MVC应用程序时,将会出现“创建单元测试项目(Create Unit Test Project)”对话框(如图2)。这个对话框允许你在解决方案下创建一个独立的项目用于测试你的ASP.NET MVC应用程序。选择选项“No, do not create a unit test project(否,不要创建单元测试项目)”,并且点击“OK(确定)”按钮。

图2 - 创建单元测试对话框

在新的ASP.NET MVC应用程序创建好之后。你将会在解决方案浏览器窗口中看到几个文件夹和文件。特别地,你将会看到三个文件夹,名字是Models、Views和Controllers。正如你从文件夹的名称可以推测出的,这三个文件夹包含了实现了模型、视图和控制器的文件。

如果你展开Controller文件夹,你应该会看到一个命名为HomeController.cs的文件。如果你展开Views文件夹,你应该看到两个子文件夹,名称是Home和Shared。如果你展开Home文件夹,你将会再次看到两个文件,名称是About.aspx和Home.aspx(见图3)。这些文件组成了这个包含在默认ASP.NET MVC模板中的范例应用程序。

图3 - 解决方案浏览器窗口

你可以通过选择菜单项“Debug(调试)”、“Start Debugging(启动调试)”来运行这个范例应用程序。除此以外,你可以点击F5键。

当你第一次运行ASP.NET应用程序,将会出现图4中的对话框,建议你开启调试模式。点击“确定”按钮将会运行应用程序。

图4 - 未开启调试对话框

当你运行一个ASP.NET MVC应用程序,Visual Studio会在你的web浏览器中运行应用程序。这个范例应用程序只含有两个页面:Index页面和About页面。当应用程序第一次启动时,将会显示Index页面(见图5)。你可以通过点击应用程序右上角的菜单链接导航到About页面。

图5 - Index页面

注意一下你浏览器地址栏中的URL。当你点击Home菜单链接,浏览器地址栏的URL将变为/Home。当你点击About菜单链接,浏览器地址栏的URL变为/About

2. 一个URL并不等同于一个页面

当你创建一个传统的ASP.NET Web窗体应用程序,或者是一个动态服务器页面(ASP)应用程序,在URL与页面之间存在一对一的对应。如果你请求服务器上的一个名为SomePage.aspx的页面,那么最好在磁盘上有一个SomePage.aspx页面。如果SomePage.aspx文件并不存在,你将会获得一个丑陋的404-页面不存在错误

当创建一个ASP.NET MVC应用程序时则大不相同,你键入到浏览器地址栏的URL与你应用程序中的文件之间并没有一个对应关系。在一个ASP.NET MVC应用程序中,一个URL与一个控制器的动作相对应,而不是磁盘上的页面。

对于一个传统的ASP.NET或者ASP应用程序,浏览器请求被映射到了页面。在ASP.NET MVC应用程序中,浏览器请求被映射到了控制器动作。一个ASP.NET Web窗体应用程序是以内容为中心的。而一个ASP.NET MVC应用程序则以是应用程序逻辑为中心的。

3. 理解URL路由

一个浏览器请求通过名叫URL路由(URL Routing)的ASP.NET MVC功能被映射到了一个控制器动作。URL路由将即将到来的请求发送到了控制器动作。

URL路由使用一张路由表来处理来到的请求。这个路由表在你的Web应用程序首次启动时创建。这个路由表建立在Global.asax文件中。代码清单1包含了这个默认的MVC Global.asax文件。

代码清单1 - Glabal.asax

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace MvcApplication1
{
     public class GlobalApplication : System.Web.HttpApplication
     {
          public static void RegisterRoutes(RouteCollection routes)
          {
               routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
               routes.MapRoute(
               "Default",
               "{controller}/{action}/{id}",
               new { controller = "Home", action = "Index", id = ""}
               );
          }

          protected void Application_Start()
          {
               RegisterRoutes(RouteTable.Routes);
          }
     }
}

当ASP.NET应用程序第一次启动时,将调用Application_Start()方法。在代码清单1中,这个方法调用了RegisterRoutes()方法,并且RegisterRoutes()方法创建了默认的路由表。

默认的路由表只含有一个路由。这个默认的路由将所有到来的请求分为了三个分段(一个URL分段是正斜杠之间的任何东西)。第一个分段映射到了控制器名称,第二个分段映射到了动作名称,最后一个分段映射到了传递给动作的名为Id的参数。

例如,考虑下面的URL:

/Product/Details/3

这个URL将会被解析为像这样的三个部分:

Controller = ProductController

Action = Details

Id = 3

注意到Controller后缀被添加到了控制器参数的末尾。这只是MVC的一个怪癖而已。

默认的路由包含所有三个分段的默认值。默认的控制器是HomeController,默认的动作是Index,默认的Id是一个空字符串。脑子里记下这三个默认值,考虑下面的URL是如何被解析的:

/Employee

这个URL将被解析为像这样的三个参数:

Controller = EmployeeController

Action = Index

Id = ""

最后,如果你打开一个ASP.NET MVC应用程序而不提供任何的URL(例如,http://localhost),然后这个URL将会被解析成这样:

Controller = HomeController

Action = Index

Id = ""

这个请求被发送到了HomeController类的Index()动作。

4. 理解控制器

控制器负责用户与MVC应用程序交互的方式。当用户发出浏览器请求时,控制器决定向用户发回什么样的响应。

控制器不过是一个类(例如,一个Visual Basic或者C#类)。这个范例ASP.NET MVC应用程序包含一个名为HomeController.cs的控制器,它位于Controllers文件夹下。HomeController.cs的内容再次显示在了代码清单2中。

代码清单2 - HomeConroller.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
   
namespace MvcApplication1.Controllers
{
     public class HomeController : Controller
     {
          public ActionResult Index()
          {
               ViewData["Title"] = "Home Page";
               ViewData["Message"] = "Welcome to ASP.NET MVC!";
               return View();
          }

          public ActionResult About()
          {
               ViewData["Title"] = "About Page";
               return View();
          }
     }
}

注意到HomeController拥有两个方法,名为Index()和About()。这两个方法对应于控制器暴露出的两个动作。URL /Home/Index将会调用HomeController.Index()方法,而URL /Home/About会调用HomeController.About()方法。

控制器中的任何公共方法都被暴露为一个控制器动作。对此你需要多加小心。这就意味着包含在控制器中的任何公共方法都可以由任何可以访问互联网的人调用,通过在浏览器中输入正确的URL。

5. 理解视图

由HomeController类暴露出的两个控制器动作,Index()和About(),都返回了一个视图。视图含有将会发送给浏览器HTML标记和内容。当使用ASP.NET MVC应用程序时,一个视图等同于一个页面。

你必须在正确的位置创建你的视图。HomeController.Index()动作返回了一个位于以下路径的视图:

\Views\Home\Index.aspx

HomeController.About()动作返回一个位于以下路径的视图:

\Views\Home\About.aspx

一般而言,如果你想为一个控制器动作返回一个视图,那么你需要在Views文件夹下创建一个子文件夹,这个文件夹与你的控制器同名。在子文件夹下,你必须创建一个.aspx文件,它的名字与控制器动作相同。

代码清单3中的文件含有About.aspx视图。

代码清单3 - About.aspx

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
AutoEventWireup="true" CodeBehind="About.aspx.cs" Inherits="MvcApplication1.Views.Home.About"%>

<asp:Content ID="aboutContent" ContentPlaceHolderID="MainContent" runat="server">
     <h2>About Us</h2>
     <p>
          TODO: Put <em>about</em> content here.
     </p>
</asp:Content>

如果你忽略代码清单中的第一行,视图剩余的大部分是由标准的HTML构成的。你可以在这里输入任何你想要的HTML来修改视图的内容。

视图非常类似于动态服务器页面(ASP)中的页面,或者ASP.NET的Web窗体。视图可以含有HTML内容和脚本。你可以使用你所喜爱的.NET语言(例如,C#或者Visual Basic .Net)编写脚本。你使用脚本显示动态的内容,例如数据库数据。

6. 理解模型

我们已经讨论了控制器,我们也讨论了视图。我们需要讨论的最后一个话题是模型。MVC模型是什么呢?

MVC的模型包含了你应用程序中的所有逻辑,这些逻辑没有包含在视图或者控制器中。模型应该包含你的应用程序中的所有业务逻辑和数据库访问逻辑。例如,如果你使用LINQ to SQL访问数据库,那么你可以在Models文件夹中创建你的LINQ to SQL类(你的dbml文件)。

视图应该仅包含与生成用户界面有关的逻辑。控制器应该仅仅只包含最少量的逻辑,用于返回正确的视图或者将用户重定向到另一个动作。任何其他的事情都应该包含在模型中。

通常,你应该竭尽全力创建一个丰富的模型以及一个瘦小的控制器。你的控制器方法应该只包含几行代码。如果一个控制器动作变得太丰富,那么你应该考虑将这些逻辑抽取出来放置到Models文件夹的新类中。

7. 总结

这篇教程为你提供了ASP.NET MVC Web应用程序各个不同部分的一个高层次的概览。你学习了URL路由如何将即将到来的浏览器请求发往特定的控制器动作。你还学习了控制器是如何协调视图怎样返回浏览器的。最后,你学习了模型是怎样包含应用程序的业务和数据库访问逻辑的。