MVC 框架 - 快速指南
MVC 框架 - 简介
模型-视图-控制器 (MVC) 是一种架构模式,它将应用程序分为三个主要逻辑组件:模型、视图和控制器。每个组件都用于处理应用程序的特定开发方面。MVC 是用于创建可扩展和可扩展项目的最常用的行业标准 Web 开发框架之一。
MVC 组件
以下是 MVC 的组件 −
模型
模型组件对应于用户使用的所有与数据相关的逻辑。这可以表示在视图和控制器组件之间传输的数据或任何其他与业务逻辑相关的数据。例如,客户对象将从数据库中检索客户信息,对其进行操作并将其数据更新回数据库或使用它来呈现数据。
视图
视图组件用于应用程序的所有 UI 逻辑。例如,客户视图将包括最终用户与之交互的所有 UI 组件,如文本框、下拉菜单等。
控制器
控制器充当模型和视图组件之间的接口,以处理所有业务逻辑和传入请求,使用模型组件操作数据并与视图交互以呈现最终输出。例如,客户控制器将处理来自客户视图的所有交互和输入,并使用客户模型更新数据库。将使用相同的控制器来查看客户数据。
ASP.NET MVC
ASP.NET 支持三种主要开发模型:Web 页面、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 − 这将打开"项目模板"选项。选择"空模板"并将"查看引擎"选择为"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 步 − 使用以下代码修改上述 View 的 body 内容 −
<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>
在上面的代码中,我们使用 @(将从 Controller 设置)访问 ViewBag 对象的 Greeting 属性的值。
步骤 10 − 现在再次运行应用程序。这次我们的代码将首先运行 Controller,设置 ViewBag,然后使用 View 代码呈现它。以下是输出。
MVC 框架 - 文件夹
现在我们已经创建了一个示例 MVC 应用程序,让我们了解一下 MVC 项目的文件夹结构。我们将创建一个新的 MVC 项目来学习这一点。
在您的 Visual Studio 中,打开"文件"->"新建"->"项目",然后选择"ASP.NET MVC 应用程序"。将其命名为 MVCFolderDemo。
单击"确定"。在下一个窗口中,选择 Internet 应用程序作为项目模板,然后单击"确定"。
这将创建一个示例 MVC 应用程序,如以下屏幕截图所示。
注意 − 此项目中的文件来自我们选择的默认模板。这些文件可能会根据不同版本略有变化。
控制器文件夹
此文件夹将包含所有控制器类。 MVC 要求所有控制器文件的名称都以 Controller 结尾。
在我们的示例中,Controllers 文件夹包含两个类文件:AccountController 和 HomeController。
Models 文件夹
此文件夹将包含所有用于处理应用程序数据的 Model 类。
在我们的示例中,Models 文件夹包含 AccountModels。您可以打开并查看此文件中的代码,以了解在我们的示例中如何创建用于管理帐户的数据模型。
Views 文件夹
此文件夹存储与应用程序显示和用户界面相关的 HTML 文件。它包含每个控制器的一个文件夹。
在我们的示例中,您将看到 Views 下的三个子文件夹,即 Account、Home 和 Shared,其中包含特定于该视图区域的 html 文件。
App_Start 文件夹
此文件夹包含应用程序加载期间所需的所有文件。
例如,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 空应用程序。右键单击项目中的"模型"文件夹,然后选择"添加"->"新项目"。然后,选择 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 应用程序中的控制器文件夹。
步骤 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 引擎 − Razor 是一种标记语法,可将服务器端 C# 或 VB 代码嵌入到网页中。此服务器端代码可用于在加载网页时创建动态内容。 Razor 是比 ASPX 引擎更先进的引擎,在 MVC 的后续版本中推出。
ASPX 引擎 − ASPX 或 Web 窗体引擎是从一开始就包含在 MVC 框架中的默认视图引擎。使用此引擎编写代码类似于在 ASP.NET Web 窗体中编写代码。
以下是比较 Razor 和 ASPX 引擎的小代码片段。
Razor
@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 的博客模型类。您还可以通过此方法在代码中使用 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 模型添加到视图中。此外,您这次将无法使用 IntelliSense,因为这次绑定将在运行时完成。
强类型视图被认为是一种更好的方法,因为我们已经知道作为模型传递的数据是什么,而不像动态类型视图,在动态类型视图中,数据在运行时绑定,如果链接模型中发生某些变化,可能会导致运行时错误。
MVC 框架 - 布局
布局在 MVC 中用于为应用程序的所有页面提供一致的外观和感觉。它与定义母版页相同,但 MVC 提供了更多功能。
创建 MVC 布局
步骤 1 − 以 Internet 应用程序为模板创建一个示例 MVC 应用程序,并在 Web 应用程序的根目录中创建一个内容文件夹。
步骤 2 − 在 CONTENT 文件夹下创建一个名为 MyStyleSheet.css 的样式表文件。此 CSS 文件将包含一致的 Web 应用程序页面设计所需的所有 CSS 类。
步骤 3 − 在 View 文件夹下创建一个 Shared 文件夹。
步骤 4 − 在 Shared 文件夹下创建一个 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 中提及 Products。 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 函数,该函数会设置默认的 Controller 及其操作(Controller 类中的方法)。
要按照我们的示例修改上述默认映射,请更改以下代码行 −
defaults: new { controller = "Products", action = "Phones", id = UrlParameter.Optional }
此设置将选择 ProductsController 并调用其中的 Phone 方法。同样,如果您在 ProductsController 中有其他方法(例如 Electronics),则其 URL 将是 −
http://servername/Products/Electronics
MVC 框架 - 动作过滤器
在 ASP.NET MVC 中,控制器定义动作方法,这些动作方法通常与 UI 控件具有一对一关系,例如单击按钮或链接等。例如,在我们之前的示例中,UserController 类包含方法 UserAdd、UserDelete 等。
但是,很多时候我们希望在特定操作之前或之后执行某些操作。为了实现此功能,ASP.NET MVC 提供了一项功能,可以在控制器的动作方法上添加操作前和操作后行为。
过滤器类型
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; } } }
在上面的代码中,我们指定了 User 模型具有的所有参数、它们的数据类型和验证,例如必填字段和长度。
现在我们的 User 模型已准备好保存数据,我们将创建一个类文件 Users.cs,其中包含查看用户、添加、编辑和删除用户的方法。
步骤 5 − 右键单击 Models,然后单击 Add → Class。将其命名为 Users。这将在 Models 中创建 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 − 右键单击 Views 文件夹,然后单击添加 → 视图。
步骤 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 类似,现在我们将使用给定的代码 − 添加下面给出的另外四个视图
Index.cshtml
此视图将在 Index 页面上显示我们系统中存在的所有用户。
@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>
此视图在我们的最终应用程序中将如下所示。
Details.cshtml
当我们单击用户记录时,此视图将显示特定用户的详细信息。
@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>
此视图在我们的最终应用程序中将如下所示。
Edit.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") }
此视图在我们的应用程序中将如下所示。
Delete.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 文件夹,然后单击 Add → Controller。将其命名为 UserController。
默认情况下,您的 Controller 类将使用以下代码创建 −
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 方法将在 Index 页面上呈现用户列表时使用。
步骤 10 − 右键单击 Index 方法并选择"创建视图"以创建 Index 页面的视图(它将列出所有用户并提供创建新用户的选项)。
步骤 11 − 现在在 UserController.cs 中添加以下代码。在此代码中,我们为不同的用户操作创建操作方法并返回我们之前创建的相应视图。
我们将为每个操作添加两种方法:GET 和 POST。HttpGet 将在获取数据并呈现数据时使用。HttpPost 将用于创建/更新数据。例如,当我们添加新用户时,我们需要一个表单来添加用户,这是一个 GET 操作。填写表单并提交这些值后,我们将需要 POST 方法。
//索引视图的操作 public ActionResult Index() { return View(_users.UserList); } //UserAdd 视图的操作 [HttpGet] public ActionResult UserAdd() { return View(); } [HttpPost] public ActionResult UserAdd(UserModels userModel) { _users.CreateUser(userModel); return View("Index", _users.UserList); } //Details 视图的操作 [HttpGet] public ActionResult Details(int id) { return View(_users.UserList.FirstOrDefault(x => x.Id == id)); } [HttpPost] public ActionResult Details() { return View("Index", _users.UserList); } //Edit 视图的操作 [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); } //删除视图的操作 [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 文件并将默认控制器更改为 User。
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 => item.LastName) </td> <td> @Html.DisplayFor(modelItem => item.BirthDate) </td> <td> </td> </tr> } </table>
步骤 4 − 现在使用以下代码创建一个 View GetUser。此视图将异步从先前创建的控制器的 GetUserData Action 获取数据。
@using MVCAjaxSupportExample.Models @model string @{ ViewBag.Title = "GetUser"; AjaxOptions ajaxOpts = new AjaxOptions { UpdateTargetId = "tableBody" }; } <h2>Get User</h2> <table> <thead> <tr> <th>First</th> <th>Last</th> <th>Role</th> </tr> </thead> <tbody id="tableBody"> @Html.Action("GetUserData", new {selectedRole = Model }) </tbody> </table> @using (Ajax.BeginForm("GetUser", ajaxOpts)) { <div> @Html.DropDownList("selectedRole", new SelectList( new [] {"All"}.Concat(Enum.GetNames(typeof(Role))))) <button type="submit">Submit</button> </div> }
步骤 5 − 最后,更改 Route.config 条目以启动用户控制器。
defaults: new { controller = "User", action = "GetUser", id = UrlParameter.Optional }
步骤 6 − 运行应用程序,其内容将类似于以下屏幕截图。
如果您从下拉列表中选择 Admin,它将获取所有具有 Admin 类型的用户。这是通过 AJAX 实现的,不会重新加载整个页面。
MVC 框架 - 捆绑
捆绑和压缩是两种性能改进技术,可改善应用程序的请求加载时间。目前大多数主流浏览器将每个主机名同时连接的数量限制为六个。这意味着,在同一时间,所有额外的请求都将由浏览器排队。
启用捆绑和压缩
要在 MVC 应用程序中启用捆绑和压缩,请打开解决方案中的 Web.config 文件。在此文件中,在 system.web − 下搜索编译设置
<system.web> <compilation debug = "true" /> </system.web>
默认情况下,您将看到 debug 参数设置为 true,这意味着捆绑和压缩被禁用。将此参数设置为 false。
捆绑
为了提高应用程序的性能,ASP.NET MVC 提供了内置功能,可将多个文件捆绑为一个文件,从而由于 HTTP 请求减少而提高页面加载性能。
捆绑是一组简单的逻辑文件,可以通过唯一名称引用并通过单个 HTTP 请求加载。
默认情况下,MVC 应用程序的 BundleConfig(位于 App_Start 文件夹中)附带以下代码 −
public static void RegisterBundles(BundleCollection bundles) { // 以下是捆绑项目中所有 css 文件的示例代码 // 捆绑其他 javascript 文件的代码也与此类似 bundles.Add(new StyleBundle("~/Content/themes/base/css").Include( "~/Content/themes/base/jquery.ui.core.css", "~/Content/themes/base/jquery.ui.tabs.css", "~/Content/themes/base/jquery.ui.datepicker.css", "~/Content/themes/base/jquery.ui.progressbar.css", "~/Content/themes/base/jquery.ui.theme.css")); }
上述代码基本上将 Content/themes/base 文件夹中的所有 CSS 文件捆绑到一个文件中。
压缩
压缩是另一种性能改进技术,它通过缩短变量名称、删除不必要的空格、换行符、注释等来优化 javascript、css 代码。这反过来又减小了文件大小并帮助应用程序更快地加载。
使用 Visual Studio 和 Web Essentials 扩展进行压缩
要使用此选项,您必须首先在 Visual Studio 中安装 Web Essentials 扩展。之后,当您右键单击任何 css 或 javascript 文件时,它将向您显示创建该文件的缩小版本的选项。
因此,如果您有一个名为 Site.css 的 css 文件,它将创建其缩小版本作为 Site.min.css。
现在,当您的应用程序下次在浏览器中运行时,它将捆绑并缩小所有 css 和 js 文件,从而提高应用程序性能。
MVC 框架 - 异常处理
在 ASP.NET 中,错误处理是使用标准 try catch 方法或使用应用程序事件完成的。ASP.NET MVC 内置了对异常处理的支持,使用称为异常过滤器的功能。我们将在这里学习两种方法:一种是覆盖 onException 方法,另一种是定义 HandleError 过滤器。
覆盖 OnException 方法
当我们想要在控制器级别处理 Action 方法中的所有异常时,使用此方法。
要了解这种方法,请创建一个 MVC 应用程序(按照前面章节中介绍的步骤进行操作)。现在添加一个新的 Controller 类,并添加以下代码,该代码将覆盖 onException 方法并在我们的 Action 方法中明确抛出错误 −
现在让我们创建一个名为 Error 的通用视图,当应用程序中发生任何异常时,它将显示给用户。在 Views 文件夹中,创建一个名为 Shared 的新文件夹,并添加一个名为 Error 的新视图。
将以下代码复制到新创建的 Error.cshtml 中 −
如果您现在尝试运行该应用程序,它将给出以下结果。当此控制器中的任何操作方法发生任何异常时,上述代码都会呈现错误视图。
这种方法的优点是同一控制器中的多个操作可以共享此错误处理逻辑。但是,缺点是我们不能在多个控制器中使用相同的错误处理逻辑。
HandleError 属性
HandleError 属性是我们在过滤器和操作过滤器一章中研究的操作过滤器之一。HandleErrorAttribute 是 IExceptionFilter 的默认实现。此过滤器处理控制器操作、过滤器和视图引发的所有异常。
要使用此功能,首先打开 web.config 中的 customErrors 部分。打开 web.config,将以下代码放入 system.web 中,并将其值设置为 On。
<customErrors mode = "On"/>
我们已经在 Views 下的 Shared 文件夹中创建了 Error View。这次将此 View 文件的代码更改为以下内容,使用 HandleErrorInfo 模型(位于 System.Web.MVC 下)对其进行强类型化。
@model System.Web.Mvc.HandleErrorInfo @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name = "viewport" content = "width = device-width" /> <title>Error</title> </head> <body> <h2> Sorry, an error occurred while processing your request. </h2> <h2>Exception details</h2> <p> Controller: @Model.ControllerName <br> Action: @Model.ActionName Exception: @Model.Exception </p> </body> </html>
现在将以下代码放入您的控制器文件中,该代码在控制器文件中指定 [HandleError] 属性。
using System; using System.Data.Common; using System.Web.Mvc; namespace ExceptionHandlingMVC.Controllers { [HandleError] public class ExceptionHandlingController : Controller { public ActionResult TestMethod() { throw new Exception("Test Exception"); return View(); } } }
如果您现在尝试运行该应用程序,您将收到类似于以下屏幕截图所示的错误。
如您所见,这次错误包含有关控制器和操作相关详细信息的更多信息。通过这种方式,HandleError 可以在任何级别和跨控制器使用来处理此类错误。