MVC 框架 - 快速指南
MVC 框架 - 简介
模型-视图-控制器 (MVC)是一种架构模式,它将应用程序分为三个主要逻辑组件:模型、视图和控制器。这些组件中的每一个都是为了处理应用程序的特定开发方面而构建的。MVC 是最常用的行业标准 Web 开发框架之一,用于创建可扩展和可扩展的项目。
MVC组件
以下是 MVC 的组件 -
模型
模型组件对应于用户使用的所有与数据相关的逻辑。这可以表示在视图和控制器组件之间传输的数据或任何其他与业务逻辑相关的数据。例如,客户对象将从数据库中检索客户信息,对其进行操作并将其数据更新回数据库或使用它来呈现数据。
看法
View 组件用于应用程序的所有 UI 逻辑。例如,客户视图将包括最终用户交互的所有 UI 组件,例如文本框、下拉列表等。
控制器
控制器充当模型和视图组件之间的接口,用于处理所有业务逻辑和传入请求、使用模型组件操作数据并与视图交互以呈现最终输出。例如,客户控制器将处理来自客户视图的所有交互和输入,并使用客户模型更新数据库。同一控制器将用于查看客户数据。
ASP.NET MVC
ASP.NET支持三种主要的开发模型:网页、Web窗体和MVC(模型视图控制器)。ASP.NET MVC 框架是一个轻量级、高度可测试的表示框架,它与现有的 ASP.NET 功能(例如母版页、身份验证等)集成。在 .NET 中,该框架在 System.Web.Mvc 程序集中定义。MVC框架的最新版本是5.0。我们使用 Visual Studio 创建 ASP.NET MVC 应用程序,该应用程序可以作为模板添加到 Visual Studio 中。
ASP.NET MVC 功能
ASP.NET MVC 提供以下功能 -
非常适合开发复杂但轻量级的应用程序。
提供可扩展、可插拔的框架,可以轻松替换和定制。例如,如果您不想使用内置的 Razor 或 ASPX 视图引擎,那么您可以使用任何其他第三方视图引擎,甚至可以自定义现有的引擎。
通过将应用程序逻辑地划分为模型、视图和控制器组件,利用应用程序的基于组件的设计。这使开发人员能够管理大型项目的复杂性并处理各个组件。
MVC 结构增强了应用程序的测试驱动开发和可测试性,因为所有组件都可以基于接口进行设计并使用模拟对象进行测试。因此,ASP.NET MVC 框架非常适合拥有大型 Web 开发团队的项目。
支持所有现有的大量 ASP.NET 功能,例如授权和身份验证、母版页、数据绑定、用户控件、成员资格、ASP.NET 路由等。
不使用视图状态的概念(ASP.NET 中存在)。这有助于构建轻量级的应用程序,并为开发人员提供完全的控制权。
因此,您可以将 MVC 框架视为构建在 ASP.NET 之上的主要框架,提供大量侧重于基于组件的开发和测试的附加功能。
MVC 框架 - 架构
在上一章中,我们研究了MVC框架的高层架构流程。现在让我们看一下当客户端发出某个请求时,MVC 应用程序是如何执行的。下图说明了该流程。
MVC 流程图
流程步骤
步骤 1 - 客户端浏览器向 MVC 应用程序发送请求。
步骤 2 - Global.ascx 接收此请求,并使用 RouteTable、RouteData、UrlRoutingModule 和 MvcRouteHandler 对象根据传入请求的 URL 执行路由。
步骤 3 - 此路由操作调用适当的控制器并使用 IControllerFactory 对象和 MvcHandler 对象的 Execute 方法执行它。
步骤 4 - 控制器使用模型处理数据并使用 ControllerActionInvoker 对象调用适当的方法
步骤 5 - 然后将处理后的模型传递给视图,视图又呈现最终输出。
MVC 框架 - ASP.NET 表单
MVC 和 ASP.NET Web 窗体是相互关联但不同的开发模型,具体取决于应用程序的要求和其他因素。从较高的层面来看,您可以认为 MVC 是一个先进且复杂的 Web 应用程序框架,其设计时考虑了关注点分离和可测试性。根据具体要求,这两种框架都有其优点和缺点。这个概念可以使用下图来形象化 -
MVC 和 ASP.NET 图
比较表
MVC 框架 - 第一个应用程序
让我们开始使用视图和控制器创建我们的第一个 MVC 应用程序。一旦我们对基本 MVC 应用程序的工作原理有了一定的实践经验,我们将在接下来的章节中学习所有单独的组件和概念。
创建第一个 MVC 应用程序
步骤 1 - 启动 Visual Studio 并选择文件 → 新建 → 项目。选择 Web → ASP.NET MVC Web 应用程序,并将该项目命名为FirstMVCApplicatio。选择位置C:\MVC。单击“确定”。
步骤 2 - 这将打开“项目模板”选项。选择空模板并将 View Engine 选择为 Razor。单击“确定”。
现在,Visual Studio 将创建我们的第一个 MVC 项目,如以下屏幕截图所示。
步骤 3 - 现在我们将在应用程序中创建第一个控制器。控制器只是简单的 C# 类,其中包含多个公共方法,称为操作方法。要添加新控制器,请右键单击项目中的 Controllers 文件夹,然后选择添加 → 控制器。将控制器命名为 HomeController 并单击添加。
这将在 Controllers 文件夹下创建一个类文件HomeController.cs,其中包含以下默认代码。
using System; using System.Web.Mvc; namespace FirstMVCApplication.Controllers { public class HomeController : Controller { public ViewResult Index() { return View(); } } }
上面的代码基本上在我们的 HomeController 中定义了一个公共方法 Index 并返回一个 ViewResult 对象。在接下来的步骤中,我们将学习如何使用 ViewResult 对象返回视图。
步骤 4 - 现在我们将向家庭控制器添加一个新视图。要添加新视图,请右键单击视图文件夹,然后单击添加 → 视图。
步骤 5 - 将新视图命名为 Index,将视图引擎命名为 Razor (SCHTML)。单击添加。
这将使用以下代码在 Views/Home 文件夹中添加一个新的cshtml文件 -
@{ Layout = null; } <html> <head> <meta name = "viewport" content = "width = device-width" /> <title>Index</title> </head> <body> <div> </div> </body> </html>
步骤 6 - 使用以下代码修改上述视图的正文内容 -
<body> <div> Welcome to My First MVC Application (<b>From Index View</b>) </div> </body>
步骤 7 - 现在运行应用程序。这将在浏览器中提供以下输出。此输出是根据视图文件中的内容呈现的。应用程序首先调用控制器,控制器又调用此视图并生成输出。
在第 7 步中,我们收到的输出基于视图文件的内容,并且与控制器没有交互。向前迈出一步,我们现在将创建一个小示例,使用视图和控制器的交互来显示带有当前时间的欢迎消息。
步骤 8 - MVC 使用 ViewBag 对象在控制器和视图之间传递数据。打开 HomeController.cs 并将 Index 函数编辑为以下代码。
public ViewResult Index() { int hour = DateTime.Now.Hour; ViewBag.Greeting = hour < 12 ? "Good Morning. Time is" + DateTime.Now.ToShortTimeString() : "Good Afternoon. Time is " + DateTime.Now.ToShortTimeString(); return View(); }
在上面的代码中,我们设置了ViewBag对象的Greeting属性的值。该代码检查当前时间并使用 return View() 语句相应地返回早安/下午消息。请注意,这里的 Greeting 只是我们与 ViewBag 对象一起使用的示例属性。您可以使用任何其他属性名称来代替 Greeting。
步骤 9 - 打开 Index.cshtml 并将以下代码复制到正文部分。
<body> <div> @ViewBag.Greeting (<b>From Index View</b>) </div> </body>
在上面的代码中,我们使用 @ 访问 ViewBag 对象的 Greeting 属性的值(将从控制器设置)。
步骤 10 - 现在再次运行应用程序。这次我们的代码将首先运行Controller,设置ViewBag,然后使用View代码渲染它。以下将是输出。
MVC 框架 - 文件夹
现在我们已经创建了一个示例 MVC 应用程序,让我们了解 MVC 项目的文件夹结构。我们将创建一个新的 MVC 项目来学习这一点。
在 Visual Studio 中,打开文件 → 新建 → 项目并选择 ASP.NET MVC 应用程序。将其命名为MCFolderDemo。
单击“确定”。在下一个窗口中,选择“Internet 应用程序”作为“项目模板”,然后单击“确定”。
这将创建一个示例 MVC 应用程序,如以下屏幕截图所示。
注意- 该项目中存在的文件来自我们选择的默认模板。根据不同的版本,这些可能会略有变化。
控制器文件夹
该文件夹将包含所有控制器类。MVC 要求所有控制器文件的名称以 Controller 结尾。
在我们的示例中,Controllers 文件夹包含两个类文件:AccountController 和 HomeController。
模型文件夹
该文件夹将包含所有用于处理应用程序数据的模型类。
在我们的示例中,Models 文件夹包含 AccountModels。您可以打开并查看此文件中的代码,以了解如何在我们的示例中创建用于管理帐户的数据模型。
视图文件夹
该文件夹存储与应用程序显示和用户界面相关的 HTML 文件。它包含每个控制器的一个文件夹。
在我们的示例中,您将在 Views 下看到三个子文件夹,即 Account、Home 和 Shared,其中包含特定于该视图区域的 html 文件。
应用程序_启动文件夹
该文件夹包含应用程序加载期间所需的所有文件。
例如,RouteConfig 文件用于将传入的 URL 路由到正确的控制器和操作。
内容文件夹
该文件夹包含所有静态文件,例如 css、图像、图标等。
此文件夹内的 Site.css 文件是应用程序应用的默认样式。
脚本文件夹
该文件夹存放了项目中所有的JS文件。默认情况下,Visual Studio 添加了 MVC、jQuery 和其他标准 JS 库。
MVC 框架 - 模型
组件“模型”负责管理应用程序的数据。它响应来自视图的请求,还响应来自控制器的指令来更新自身。
模型类可以手动创建,也可以从数据库实体生成。在接下来的章节中,我们将看到很多手动创建模型的示例。因此,在本章中,我们将尝试另一个选项,即从数据库生成,以便您对这两种方法都有实践经验。
创建数据库实体
连接到 SQL Server 并创建一个新数据库。
现在运行以下查询来创建新表。
CREATE TABLE [dbo].[Student]( [StudentID] INT IDENTITY (1,1) NOT NULL, [LastName] NVARCHAR (50) NULL, [FirstName] NVARCHAR (50) NULL, [EnrollmentDate] DATETIME NULL, PRIMARY KEY CLUSTERED ([StudentID] ASC) ) CREATE TABLE [dbo].[Course]( [CourseID] INT IDENTITY (1,1) NOT NULL, [Title] NVARCHAR (50) NULL, [Credits] INT NULL, PRIMARY KEY CLUSTERED ([CourseID] ASC) ) CREATE TABLE [dbo].[Enrollment]( [EnrollmentID] INT IDENTITY (1,1) NOT NULL, [Grade] DECIMAL(3,2) NULL, [CourseID] INT NOT NULL, [StudentID] INT NOT NULL, PRIMARY KEY CLUSTERED ([EnrollmentID] ASC), CONSTRAINT [FK_dbo.Enrollment_dbo.Course_CourseID] FOREIGN KEY ([CourseID]) REFERENCES [dbo].[Course]([CourseID]) ON DELETE CASCADE, CONSTRAINT [FK_dbo.Enrollment_dbo.Student_StudentID] FOREIGN KEY ([StudentID]) REFERENCES [dbo].[Student]([StudentID]) ON DELETE CASCADE )
使用数据库实体生成模型
创建数据库并设置表后,您可以继续创建一个新的 MVC 空应用程序。右键单击项目中的 Models 文件夹,然后选择添加 → 新项目。然后,选择 ADO.NET 实体数据模型。
在下一个向导中,选择从数据库生成并单击下一步。设置与 SQL 数据库的连接。
选择您的数据库并单击测试连接。随后将出现类似于以下内容的屏幕。点击下一步。
选择表、视图以及存储过程和函数。单击“完成”。您将看到创建的模型视图,如以下屏幕截图所示。
上述操作将自动为所有数据库实体创建一个模型文件。例如,我们创建的 Student 表将生成一个包含以下代码的模型文件 Student.cs -
namespace MvcModelExample.Models { using System; using System.Collections.Generic; public partial class Student { public Student() { this.Enrollments = new HashSet(); } public int StudentID { get; set; } public string LastName { get; set; } public string FirstName { get; set; } public Nullable EnrollmentDate { get; set; } public virtual ICollection Enrollments { get; set; } } }
MVC 框架 - 控制器
Asp.net MVC 控制器负责控制应用程序执行的流程。当您向 MVC 应用程序发出请求(意味着请求页面)时,控制器负责返回对该请求的响应。控制器可以执行一项或多项操作。控制器操作可以向特定请求返回不同类型的操作结果。
控制器负责控制应用程序逻辑,并充当视图和模型之间的协调器。控制器通过视图接收用户的输入,然后在模型的帮助下处理用户的数据并将结果传递回视图。
创建控制器
创建一个控制器 -
步骤 1 - 创建一个 MVC 空应用程序,然后右键单击 MVC 应用程序中的 Controller 文件夹。
步骤 2 - 选择菜单选项添加 → 控制器。选择后,将显示“添加控制器”对话框。将控制器命名为DemoController。
将创建一个控制器类文件,如以下屏幕截图所示。
使用 IController 创建控制器
在 MVC 框架中,控制器类必须实现 System.Web.Mvc 命名空间中的 IController 接口。
public interface IController { void Execute(RequestContext requestContext); }
这是一个非常简单的界面。当请求针对控制器类时,将调用唯一的方法 Execute。MVC 框架通过读取路由数据生成的控制器属性值来了解请求中的目标控制器类。
步骤 1 - 添加一个新的类文件并将其命名为 DemoCustomController。现在修改这个类来继承IController接口。
步骤 2 - 将以下代码复制到此类中。
public class DemoCustomController:IController { public void Execute(System.Web.Routing.RequestContext requestContext) { var controller = (string)requestContext.RouteData.Values["controller"]; var action = (string)requestContext.RouteData.Values["action"]; requestContext.HttpContext.Response.Write( string.Format("Controller: {0}, Action: {1}", controller, action)); } }
步骤 3 - 运行应用程序,您将收到以下输出。
MVC 框架 - 视图
正如在最初的介绍性章节中所看到的,视图是与应用程序的用户界面相关的组件。这些视图通常从模型数据绑定,并具有 html、aspx、cshtml、vbhtml 等扩展名。在我们的第一个 MVC 应用程序中,我们使用带有控制器的视图来向最终用户显示数据。为了将这些静态和动态内容渲染到浏览器,MVC 框架利用视图引擎。视图引擎基本上是标记语法实现,负责将最终的 HTML 渲染到浏览器。
MVC 框架带有两个内置视图引擎 -
Razor Engine - Razor 是一种标记语法,可将服务器端 C# 或 VB 代码添加到网页中。此服务器端代码可用于在加载网页时创建动态内容。Razor 相对于 ASPX 引擎来说是一个先进的引擎,在 MVC 的后续版本中推出。
ASPX 引擎- ASPX 或 Web 表单引擎是默认视图引擎,从一开始就包含在 MVC 框架中。使用此引擎编写代码类似于在 ASP.NET Web 窗体中编写代码。
以下是比较 Razor 和 ASPX 引擎的小代码片段。
剃刀
@Html.ActionLink("Create New", "UserAdd")
ASPX
<% Html.ActionLink("SignUp", "SignUp") %>
在这两者中,Razor 是一种先进的视图引擎,因为它具有紧凑的语法、测试驱动的开发方法和更好的安全功能。我们将在所有示例中使用 Razor 引擎,因为它是最常用的视图引擎。
这些视图引擎可以通过以下两种类型进行编码和实现:
- 强类型
- 动态类型
这些方法分别类似于早期绑定和后期绑定,其中模型将强烈或动态地绑定到视图。
强类型视图
为了理解这个概念,让我们创建一个示例 MVC 应用程序(按照前面章节中的步骤操作)并添加一个名为ViewDemoController的控制器类文件。
现在,将以下代码复制到控制器文件中 -
using System.Collections.Generic; using System.Web.Mvc; namespace ViewsInMVC.Controllers { public class ViewDemoController : Controller { public class Blog { public string Name; public string URL; } private readonly List topBlogs = new List { new Blog { Name = "Joe Delage", URL = "http://tutorialspoint/joe/"}, new Blog {Name = "Mark Dsouza", URL = "http://tutorialspoint/mark"}, new Blog {Name = "Michael Shawn", URL = "http://tutorialspoint/michael"} }; public ActionResult StonglyTypedIndex() { return View(topBlogs); } public ActionResult IndexNotStonglyTyped() { return View(topBlogs); } } }
在上面的代码中,我们定义了两个操作方法:StronglyTypedIndex和IndexNotStonglyTyped。我们现在将为这些操作方法添加视图。
右键单击 StonglyTypedIndex 操作方法,然后单击添加视图。在下一个窗口中,选中“创建强类型视图”复选框。这也将启用模型类和支架模板选项。从支架模板选项中选择列表。单击添加。
将创建类似于以下屏幕截图的视图文件。您可以注意到,它在顶部包含了 ViewDemoController 的 Blog 模型类。通过这种方法,您还可以在代码中使用 IntelliSense。
动态类型视图
要创建动态类型化视图,请右键单击 IndexNotStonglyTyped 操作,然后单击添加视图。
这次,不要选中“创建强类型视图”复选框。
结果视图将具有以下代码 -
@model dynamic @{ ViewBag.Title = "IndexNotStonglyTyped"; } <h2>Index Not Stongly Typed</h2> <p> <ul> @foreach (var blog in Model) { <li> <a href = "@blog.URL">@blog.Name</a> </li> } </ul> </p>
正如您在上面的代码中看到的,这次它没有像之前的情况一样将 Blog 模型添加到 View 中。另外,这次您将无法使用 IntelliSense,因为这次绑定将在运行时完成。
强类型视图被认为是一种更好的方法,因为我们已经知道什么数据作为模型传递,这与动态类型视图不同,在动态类型视图中,数据在运行时绑定,如果链接模型中发生某些变化,可能会导致运行时错误。
MVC 框架 - 布局
MVC 中使用布局来为应用程序的所有页面提供一致的外观和感觉。它与定义母版页相同,但 MVC 提供了更多功能。
创建 MVC 布局
步骤 1 - 创建一个以 Internet 应用程序为模板的示例 MVC 应用程序,并在 Web 应用程序的根目录中创建一个 Content 文件夹。
步骤 2 - 在 CONTENT 文件夹下创建一个名为 MyStyleSheet.css 的样式表文件。该 CSS 文件将包含一致的 Web 应用程序页面设计所需的所有 CSS 类。
步骤 3 - 在 View 文件夹下创建一个 Shared 文件夹。
步骤 4 - 在共享文件夹下创建 MasterLayout.cshtml 文件。文件 MasterLayout.cshtml 表示应用程序中每个页面的布局。右键单击解决方案资源管理器中的共享文件夹,然后转到添加项目并单击查看。复制以下布局代码。
布局代码
<!DOCTYPE html> <html lang = "en"> <head> <meta charset = "utf-8" /> <title>@ViewBag.Title - Tutorial Point</title> <link href = "~/favicon.ico" rel = "shortcut icon" type = "image/x-icon" /> <link rel = "stylesheet" href = "@Url.Content("~/Content/MyStyleSheet.css")" /> </head> <body> <header> <div class = "content-wrapper"> <div class = "float-left"> <p class = "site-title"> @Html.ActionLink("Tutorial Point", "Index", "Home") </p> </div> <div class = "float-right"> <nav> <ul id = "menu"> <li>@Html.ActionLink("Home", "Index", "Home")</li> <li>@Html.ActionLink("About", "About", "Home")</li> </ul> </nav> </div> </div> </header> <div id = "body"> @RenderSection("featured", required: false) <section class = "content-wrapper main-content clear-fix"> @RenderBody() </section> </div> <footer> <div class = "content-wrapper"> <div class = "float-left"> <p>© @DateTime.Now.Year - Tutorial Point</p> </div> </div> </footer> </body> </html>
在这个布局中,我们使用了 HTML 帮助器方法和其他一些系统定义的方法,因此让我们一一看看这些方法。
Url.Content() - 此方法指定我们在视图代码中使用的任何文件的路径。它将虚拟路径作为输入并返回绝对路径。
Html.ActionLink() - 此方法呈现链接到某些控制器操作的 HTML 链接。第一个参数指定显示名称,第二个参数指定操作名称,第三个参数指定控制器名称。
RenderSection() - 指定我们想要在模板中的该位置显示的部分的名称。
RenderBody() - 渲染关联视图的实际主体。
步骤 5 - 最后,打开 Views 文件夹内的 _ViewStart.cshtml 文件并添加以下代码 -
@{ Layout = "~/Views/Shared/_Layout.cshtml"; }
如果该文件不存在,您可以使用该名称创建文件。
步骤 6 - 现在运行应用程序以查看修改后的主页。
MVC框架-路由引擎
ASP.NET MVC 路由允许使用描述用户操作并且更容易被用户理解的 URL。同时,路由可用于隐藏不打算向最终用户显示的数据。
例如,在不使用路由的应用程序中,用户将看到 URL http://myapplication/Users.aspx?id=1,该 URL 对应于 myapplication 路径内的文件 Users.aspx 并发送 ID 为 1 ,通常,我们不希望向最终用户显示此类文件名。
为了处理 MVC URL,ASP.NET 平台使用路由系统,它允许您创建所需的任何 URL 模式,并以清晰简洁的方式表达它们。MVC 中的每个路由都包含特定的 URL 模式。将此 URL 模式与传入请求 URL 进行比较,如果 URL 与此模式匹配,则路由引擎将使用它来进一步处理请求。
MVC 路由 URL 格式
要了解 MVC 路由,请考虑以下 URL -
http://servername/Products/Phones
在上面的 URL 中,Products 是第一段,Phone 是第二段,可以用以下格式表示 -
{controller}/{action}
MVC 框架自动将第一段视为控制器名称,将第二段视为该控制器内的操作之一。
注意- 如果您的控制器的名称是 ProductsController,则您只需在路由 URL 中提及产品。MVC 框架自动识别 Controller 后缀。
创建一个简单的路线
路由在 App_Start 项目文件夹下的 RouteConfig.cs 文件中定义。
您将在此文件中看到以下代码 -
public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } }
当应用程序启动时,Global.ascx 会调用此 RegisterRoutes 方法。Global.ascx 下的 Application_Start 方法调用此 MapRoute 函数,该函数设置默认控制器及其操作(控制器类内部的方法)。
要根据我们的示例修改上述默认映射,请更改以下代码行 -
defaults: new { controller = "Products", action = "Phones", id = UrlParameter.Optional }
此设置将选择 ProductsController 并调用其中的 Phone 方法。同样,如果您有另一种方法,例如 ProductsController 中的 Electronics,则它的 URL 将为 -
http://服务器名称/产品/电子产品
MVC 框架 - 操作过滤器
在 ASP.NET MVC 中,控制器定义了操作方法,这些操作方法通常与 UI 控件具有一对一的关系,例如单击按钮或链接等。例如,在我们前面的一个示例中,UserController类包含 UserAdd、UserDelete 等方法。
然而,很多时候我们希望在特定操作之前或之后执行某些操作。为了实现此功能,ASP.NET MVC 提供了在控制器的操作方法上添加操作前和操作后Behave的功能。
过滤器的类型
ASP.NET MVC 框架支持以下操作过滤器 -
操作过滤器- 操作过滤器用于实现在控制器操作执行之前和之后执行的逻辑。我们将在本章中详细了解操作过滤器。
授权过滤器- 授权过滤器用于实现控制器操作的身份验证和授权。
结果过滤器- 结果过滤器包含在执行视图结果之前和之后执行的逻辑。例如,您可能希望在视图呈现到浏览器之前修改视图结果。
异常过滤器- 异常过滤器是最后运行的过滤器类型。您可以使用异常过滤器来处理由控制器操作或控制器操作结果引发的错误。您还可以使用异常过滤器来记录错误。
操作过滤器是最常用的过滤器之一,用于执行额外的数据处理,或操作返回值或取消操作的执行或在运行时修改视图结构。
动作过滤器
操作过滤器是附加属性,可以应用于控制器部分或整个控制器以修改操作的执行方式。这些属性是从 System.Attribute 派生的特殊 .NET 类,可以附加到类、方法、属性和字段。
ASP.NET MVC 提供以下操作过滤器 -
输出缓存- 此操作过滤器将控制器操作的输出缓存指定的时间。
处理错误- 此操作过滤器处理控制器操作执行时引发的错误。
授权- 此操作过滤器使您能够限制对特定用户或角色的访问。
现在,我们将看到在示例控制器 ActionFilterDemoController 上应用这些过滤器的代码示例。(ActionFilterDemoController 仅用作示例。您可以在任何控制器上使用这些过滤器。)
输出缓存
示例- 指定要缓存 10 秒的返回值。
public class ActionFilterDemoController : Controller { [HttpGet] OutputCache(Duration = 10)] public string Index() { return DateTime.Now.ToString("T"); } }
处理错误
示例- 当控制器触发错误时,将应用程序重定向到自定义错误页面。
[HandleError] public class ActionFilterDemoController : Controller { public ActionResult Index() { throw new NullReferenceException(); } public ActionResult About() { return View(); } }
通过上面的代码,如果在操作执行过程中发生任何错误,它将在 Views 文件夹中查找名为 Error 的视图并将该页面呈现给用户。
授权
示例- 仅允许授权用户登录应用程序。
public class ActionFilterDemoController: Controller { [Authorize] public ActionResult Index() { ViewBag.Message = "This can be viewed only by authenticated users only"; return View(); } [Authorize(Roles="admin")] public ActionResult AdminIndex() { ViewBag.Message = "This can be viewed only by users in Admin role only"; return View(); } }
使用上面的代码,如果您尝试在不登录的情况下访问该应用程序,它将引发类似于以下屏幕截图中所示的错误。
MVC 框架 - 高级示例
在第一章中,我们学习了 MVC 中控制器和视图如何交互。在本教程中,我们将向前迈出一步,学习如何使用模型并创建一个高级应用程序来创建、编辑、删除。并查看我们应用程序中的用户列表。
创建高级 MVC 应用程序
步骤 1 - 选择文件 → 新建 → 项目 → ASP.NET MVC Web 应用程序。将其命名为 AdvancedMVCApplication。单击“确定”。在下一个窗口中,选择“模板”作为“Internet 应用程序”,选择“查看引擎”作为“Razor”。请注意,我们这次使用的是模板而不是空应用程序。
这将创建一个新的解决方案项目,如以下屏幕截图所示。由于我们使用默认的 ASP.NET 主题,因此它附带了示例视图、控制器、模型和其他文件。
步骤 2 - 构建解决方案并运行应用程序以查看其默认输出,如以下屏幕截图所示。
步骤 3 - 添加一个新模型来定义用户数据的结构。右键单击“模型”文件夹,然后单击“添加”→“类”。将其命名为 UserModel 并单击“添加”。
步骤 4 - 将以下代码复制到新创建的 UserModel.cs 中。
using System; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Web.Mvc.Html; namespace AdvancedMVCApplication.Models { public class UserModels { [Required] public int Id { get; set; } [DisplayName("First Name")] [Required(ErrorMessage = "First name is required")] public string FirstName { get; set; } [Required] public string LastName { get; set; } public string Address { get; set; } [Required] [StringLength(50)] public string Email { get; set; } [DataType(DataType.Date)] public DateTime DOB { get; set; } [Range(100,1000000)] public decimal Salary { get; set; } } }
在上面的代码中,我们指定了用户模型具有的所有参数、它们的数据类型和验证,例如必需的字段和长度。
现在我们已经准备好保存数据的用户模型,我们将创建一个类文件 Users.cs,其中包含用于查看用户、添加、编辑和删除用户的方法。
步骤 5 - 右键单击模型,然后单击添加 → 类。将其命名为“用户”。这将在模型中创建 users.cs 类。将以下代码复制到 users.cs 类中。
using System; using System.Collections.Generic; using System.EnterpriseServices; namespace AdvancedMVCApplication.Models { public class Users { public List UserList = new List(); //action to get user details public UserModels GetUser(int id) { UserModels usrMdl = null; foreach (UserModels um in UserList) if (um.Id == id) usrMdl = um; return usrMdl; } //action to create new user public void CreateUser(UserModels userModel) { UserList.Add(userModel); } //action to udpate existing user public void UpdateUser(UserModels userModel) { foreach (UserModels usrlst in UserList) { if (usrlst.Id == userModel.Id) { usrlst.Address = userModel.Address; usrlst.DOB = userModel.DOB; usrlst.Email = userModel.Email; usrlst.FirstName = userModel.FirstName; usrlst.LastName = userModel.LastName; usrlst.Salary = userModel.Salary; break; } } } //action to delete exising user public void DeleteUser(UserModels userModel) { foreach (UserModels usrlst in UserList) { if (usrlst.Id == userModel.Id) { UserList.Remove(usrlst); break; } } } } }
一旦我们有了 UserModel.cs 和 Users.cs,我们将向模型添加视图以用于查看用户、添加、编辑和删除用户。首先让我们创建一个视图来创建用户。
步骤 6 - 右键单击“视图”文件夹,然后单击“添加”→“视图”。
步骤 7 - 在下一个窗口中,选择视图名称为 UserAdd,将视图引擎选择为 Razor,然后选择创建强类型视图复选框。
步骤 8 - 单击添加。默认情况下,这将创建以下 CSHML 代码,如下所示 -
@model AdvancedMVCApplication.Models.UserModels @{ ViewBag.Title = "UserAdd"; } <h2>UserAdd</h2> @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>UserModels</legend> <div class = "editor-label"> @Html.LabelFor(model => model.FirstName) </div> <div class = "editor-field"> @Html.EditorFor(model => model.FirstName) @Html.ValidationMessageFor(model => model.FirstName) </div> <div class = "editor-label"> @Html.LabelFor(model => model.LastName) </div> <div class = "editor-field"> @Html.EditorFor(model => model.LastName) @Html.ValidationMessageFor(model => model.LastName) </div> <div class = "editor-label"> @Html.LabelFor(model => model.Address) </div> <div class = "editor-field"> @Html.EditorFor(model => model.Address) @Html.ValidationMessageFor(model => model.Address) </div> <div class = "editor-label"> @Html.LabelFor(model => model.Email) </div> <div class = "editor-field"> @Html.EditorFor(model => model.Email) @Html.ValidationMessageFor(model => model.Email) </div> <div class = "editor-label"> @Html.LabelFor(model => model.DOB) </div> <div class = "editor-field"> @Html.EditorFor(model => model.DOB) @Html.ValidationMessageFor(model => model.DOB) </div> <div class = "editor-label"> @Html.LabelFor(model => model.Salary) </div> <div class = "editor-field"> @Html.EditorFor(model => model.Salary) @Html.ValidationMessageFor(model => model.Salary) </div> <p> <input type = "submit" value = "Create" /> </p> </fieldset> } <div> @Html.ActionLink("Back to List", "Index") </div> @section Scripts { @Scripts.Render("~/bundles/jqueryval") }
如您所见,此视图包含字段所有属性的视图详细信息,包括其验证消息、标签等。此视图在我们的最终应用程序中如下所示。
与 UserAdd 类似,现在我们将使用给定的代码添加下面给出的另外四个视图 -
索引.cshtml
此视图将在索引页面上显示我们系统中存在的所有用户。
@model IEnumerable<AdvancedMVCApplication.Models.UserModels> @{ ViewBag.Title = "Index"; } <h2>Index</h2> <p> @Html.ActionLink("Create New", "UserAdd") </p> <table> <tr> <th> @Html.DisplayNameFor(model => model.FirstName) </th> <th> @Html.DisplayNameFor(model => model.LastName) </th> <th> @Html.DisplayNameFor(model => model.Address) </th> <th> @Html.DisplayNameFor(model => model.Email) </th> <th> @Html.DisplayNameFor(model => model.DOB) </th> <th> @Html.DisplayNameFor(model => model.Salary) </th> <th></th> </tr> @foreach (var item in Model) { <tr> <td> @Html.DisplayFor(modelItem => item.FirstName) </td> <td> @Html.DisplayFor(modelItem => item.LastName) </td> <td> @Html.DisplayFor(modelItem => item.Address) </td> <td> @Html.DisplayFor(modelItem => item.Email) </td> <td> @Html.DisplayFor(modelItem => item.DOB) </td> <td> @Html.DisplayFor(modelItem => item.Salary) </td> <td> @Html.ActionLink("Edit", "Edit", new { id = item.Id }) | @Html.ActionLink("Details", "Details", new { id = item.Id }) | @Html.ActionLink("Delete", "Delete", new { id = item.Id }) </td> </tr> } </table>
在我们的最终应用程序中,该视图将如下所示。
详情.cshtml
当我们点击用户记录时,该View将显示特定用户的详细信息。
@model AdvancedMVCApplication.Models.UserModels @{ ViewBag.Title = "Details"; } <h2>Details</h2> <fieldset> <legend>UserModels</legend> <div class = "display-label"> @Html.DisplayNameFor(model => model.FirstName) </div> <div class = "display-field"> @Html.DisplayFor(model => model.FirstName) </div> <div class = "display-label"> @Html.DisplayNameFor(model => model.LastName) </div> <div class = "display-field"> @Html.DisplayFor(model => model.LastName) </div> <div class = "display-label"> @Html.DisplayNameFor(model => model.Address) </div> <div class = "display-field"> @Html.DisplayFor(model => model.Address) </div> <div class = "display-label"> @Html.DisplayNameFor(model => model.Email) </div> <div class = "display-field"> @Html.DisplayFor(model => model.Email) </div> <div class = "display-label"> @Html.DisplayNameFor(model => model.DOB) </div> <div class = "display-field"> @Html.DisplayFor(model => model.DOB) </div> <div class = "display-label"> @Html.DisplayNameFor(model => model.Salary) </div> <div class = "display-field"> @Html.DisplayFor(model => model.Salary) </div> </fieldset> <p> @Html.ActionLink("Edit", "Edit", new { id = Model.Id }) | @Html.ActionLink("Back to List", "Index") </p>
在我们的最终应用程序中,该视图将如下所示。
编辑.cshtml
此视图将显示编辑表单以编辑现有用户的详细信息。
@model AdvancedMVCApplication.Models.UserModels @{ ViewBag.Title = "Edit"; } <h2>Edit</h2> @using (Html.BeginForm()) { @Html.AntiForgeryToken() @Html.ValidationSummary(true) <fieldset> <legend>UserModels</legend> @Html.HiddenFor(model => model.Id) <div class = "editor-label"> @Html.LabelFor(model => model.FirstName) </div> <div class = "editor-field"> @Html.EditorFor(model => model.FirstName) @Html.ValidationMessageFor(model => model.FirstName) </div> <div class = "editor-label"> @Html.LabelFor(model => model.LastName) </div> <div class = "editor-field"> @Html.EditorFor(model => model.LastName) @Html.ValidationMessageFor(model => model.LastName) </div> <div class = "editor-label"> @Html.LabelFor(model => model.Address) </div> <div class = "editor-field"> @Html.EditorFor(model => model.Address) @Html.ValidationMessageFor(model => model.Address) </div> <div class = "editor-label"> @Html.LabelFor(model => model.Email) </div> <div class = "editor-field"> @Html.EditorFor(model => model.Email) @Html.ValidationMessageFor(model => model.Email) </div> <div class = "editor-label"> @Html.LabelFor(model => model.DOB) </div> <div class = "editor-field"> @Html.EditorFor(model => model.DOB) @Html.ValidationMessageFor(model => model.DOB) </div> <div class = "editor-label"> @Html.LabelFor(model => model.Salary) </div> <div class = "editor-field"> @Html.EditorFor(model => model.Salary) @Html.ValidationMessageFor(model => model.Salary) </div> <p> <input type = "submit" value = "Save" /> </p> </fieldset> } <div> @Html.ActionLink("Back to List", "Index") </div> @section Scripts { @Scripts.Render("~/bundles/jqueryval") }
该视图在我们的应用程序中如下所示。
删除.cshtml
该视图将显示删除现有用户的表单。
@model AdvancedMVCApplication.Models.UserModels @{ ViewBag.Title = "Delete"; } <h2>Delete</h2> <h3>Are you sure you want to delete this?</h3> <fieldset> <legend>UserModels</legend> <div class = "display-label"> @Html.DisplayNameFor(model => model.FirstName) </div> <div class = "display-field"> @Html.DisplayFor(model => model.FirstName) </div> <div class = "display-label"> @Html.DisplayNameFor(model => model.LastName) </div> <div class = "display-field"> @Html.DisplayFor(model => model.LastName) </div> <div class = "display-label"> @Html.DisplayNameFor(model => model.Address) </div> <div class = "display-field"> @Html.DisplayFor(model => model.Address) </div> <div class = "display-label"> @Html.DisplayNameFor(model => model.Email) </div> <div class = "display-field"> @Html.DisplayFor(model => model.Email) </div> <div class = "display-label"> @Html.DisplayNameFor(model => model.DOB) </div> <div class = "display-field"> @Html.DisplayFor(model => model.DOB) </div> <div class = "display-label"> @Html.DisplayNameFor(model => model.Salary) </div> <div class = "display-field"> @Html.DisplayFor(model => model.Salary) </div> </fieldset> @using (Html.BeginForm()) { @Html.AntiForgeryToken() <p> <input type = "submit" value = "Delete" /> | @Html.ActionLink("Back to List", "Index") </p> }
在我们的最终应用程序中,该视图将如下所示。
步骤 9 - 我们已经在应用程序中添加了模型和视图。现在最后我们将为我们的视图添加一个控制器。右键单击 Controllers 文件夹,然后单击添加 → 控制器。将其命名为 UserController。
默认情况下,您的控制器类将使用以下代码创建 -
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using AdvancedMVCApplication.Models; namespace AdvancedMVCApplication.Controllers { public class UserController : Controller { private static Users _users = new Users(); public ActionResult Index() { return View(_users.UserList); } } }
在上面的代码中,在索引页面上呈现用户列表时将使用 Index 方法。
步骤 10 - 右键单击索引方法并选择创建视图为我们的索引页面创建一个视图(它将列出所有用户并提供创建新用户的选项)。
步骤 11 - 现在在 UserController.cs 中添加以下代码。在此代码中,我们为不同的用户操作创建操作方法,并返回我们之前创建的相应视图。
我们将为每个操作添加两个方法:GET 和 POST。HttpGet 将在获取数据并渲染数据时使用。HttpPost 将用于创建/更新数据。例如,当我们添加一个新用户时,我们需要一个表单来添加用户,这是一个GET操作。填写表单并提交这些值后,我们将需要 POST 方法。
//Action for Index View public ActionResult Index() { return View(_users.UserList); } //Action for UserAdd View [HttpGet] public ActionResult UserAdd() { return View(); } [HttpPost] public ActionResult UserAdd(UserModels userModel) { _users.CreateUser(userModel); return View("Index", _users.UserList); } //Action for Details View [HttpGet] public ActionResult Details(int id) { return View(_users.UserList.FirstOrDefault(x => x.Id == id)); } [HttpPost] public ActionResult Details() { return View("Index", _users.UserList); } //Action for Edit View [HttpGet] public ActionResult Edit(int id) { return View(_users.UserList.FirstOrDefault(x=>x.Id==id)); } [HttpPost] public ActionResult Edit(UserModels userModel) { _users.UpdateUser(userModel); return View("Index", _users.UserList); } //Action for Delete View [HttpGet] public ActionResult Delete(int id) { return View(_users.UserList.FirstOrDefault(x => x.Id == id)); } [HttpPost] public ActionResult Delete(UserModels userModel) { _users.DeleteUser(userModel); return View("Index", _users.UserList); } sers.UserList);
步骤 12 - 最后要做的事情是转到 App_Start 文件夹中的 RouteConfig.cs 文件并将默认控制器更改为用户。
defaults: new { controller = "User", action = "Index", id = UrlParameter.Optional }
这就是我们启动并运行高级应用程序所需的全部内容。
步骤 13 - 现在运行应用程序。您将能够看到一个应用程序,如以下屏幕截图所示。您可以执行添加、查看、编辑和删除用户的所有功能,如我们在前面的屏幕截图中看到的那样。
MVC 框架 - Ajax 支持
您可能知道,Ajax 是异步 JavaScript 和 XML 的简写。MVC 框架包含对不显眼的 Ajax 的内置支持。您可以使用辅助方法来定义 Ajax 功能,而无需在所有视图中添加代码。MVC 中的此功能基于 jQuery 功能。
要在 MVC 应用程序中启用不显眼的 AJAX 支持,请打开 Web.Config 文件并使用以下代码在 appSettings 部分中设置 UnobtrusiveJavaScriptEnabled 属性。如果您的应用程序中已存在该密钥,则可以忽略此步骤。
<add key = "UnobtrusiveJavaScriptEnabled" value = "true" />
之后,打开位于Views/Shared文件夹下的通用布局文件_Layout.cshtml文件。我们将使用以下代码在此处添加对 jQuery 库的引用 -
<script src = "~/Scripts/jquery-ui-1.8.24.min.js" type = "text/javascript"> </script> <script src = "~/Scripts/jquery.unobtrusive-ajax.min.js" type = "text/javascript"> </script>
创建一个不显眼的 Ajax 应用程序
在下面的示例中,我们将创建一个表单来显示系统中的用户列表。我们将放置一个包含三个选项的下拉菜单:管理员、普通和访客。当您选择这些值之一时,它将使用不显眼的 AJAX 设置显示属于此类别的用户列表。
步骤 1 - 创建模型文件 Model.cs 并复制以下代码。
using System; namespace MVCAjaxSupportExample.Models { public class User { public int UserId { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public DateTime BirthDate { get; set; } public Role Role { get; set; } } public enum Role { Admin, Normal, Guest } }
步骤 2 - 创建一个名为 UserController.cs 的控制器文件,并使用以下代码在其中创建两个操作方法。
using System; using System.Collections.Generic; using System.Linq; using System.Web.Mvc; using MVCAjaxSupportExample.Models; namespace MVCAjaxSupportExample.Controllers { public class UserController : Controller { private readonly User[] userData = { new User {FirstName = "Edy", LastName = "Clooney", Role = Role.Admin}, new User {FirstName = "David", LastName = "Sanderson", Role = Role.Admin}, new User {FirstName = "Pandy", LastName = "Griffyth", Role = Role.Normal}, new User {FirstName = "Joe", LastName = "Gubbins", Role = Role.Normal}, new User {FirstName = "Mike", LastName = "Smith", Role = Role.Guest} }; public ActionResult Index() { return View(userData); } public PartialViewResult GetUserData(string selectedRole = "All") { IEnumerable data = userData; if (selectedRole != "All") { var selected = (Role) Enum.Parse(typeof (Role), selectedRole); data = userData.Where(p => p.Role == selected); } return PartialView(data); } public ActionResult GetUser(string selectedRole = "All") { return View((object) selectedRole); } } }
步骤 3 - 现在使用以下代码创建一个名为 GetUserData 的部分视图。该视图将用于根据从下拉列表中选择的角色呈现用户列表。
@model IEnumerable<MVCAjaxSupportExample.Models.User> <table> <tr> <th> @Html.DisplayNameFor(model => model.FirstName) </th> <th> @Html.DisplayNameFor(model => model.LastName) </th> <th> @Html.DisplayNameFor(model => model.BirthDate) </th> <th></th> </tr> @foreach (var item in Model) { <tr> <td> @Html.DisplayFor(modelItem => item.FirstName) </td> <td> @Html.DisplayFor(modelItem =>