- MVC 框架教程
- MVC 框架 - 首页
- MVC 框架 - 简介
- MVC 框架 - 架构
- MVC 框架 - ASP.NET 表单
- MVC 框架 - 第一个应用程序
- MVC 框架 - 文件夹
- MVC 框架 - 模型
- MVC 框架 - 控制器
- MVC 框架 - 视图
- MVC 框架 - 布局
- MVC 框架 - 路由引擎
- MVC 框架 - 操作过滤器
- 高级示例
- MVC 框架 - Ajax 支持
- MVC 框架 - 捆绑
- 异常处理
- MVC 框架有用资源
- 问题与解答
- MVC 框架 - 快速指南
- MVC 框架 - 资源
- MVC 框架 - 讨论
MVC 框架 - 快速指南
MVC 框架 - 简介
模型-视图-控制器 (MVC) 是一种架构模式,它将应用程序划分为三个主要的逻辑组件:模型、视图和控制器。每个组件都构建为处理应用程序的特定开发方面。MVC 是最常用的行业标准 Web 开发框架之一,用于创建可扩展的项目。
MVC 组件
以下是 MVC 的组件 -
模型
模型组件对应于用户使用的所有与数据相关的逻辑。这可以表示视图和控制器组件之间传输的数据,或任何其他与业务逻辑相关的数据。例如,Customer 对象将从数据库中检索客户信息,对其进行操作并将数据更新回数据库,或使用它来呈现数据。
视图
视图组件用于应用程序的所有 UI 逻辑。例如,Customer 视图将包含最终用户交互的所有 UI 组件,例如文本框、下拉列表等。
控制器
控制器充当模型和视图组件之间的接口,以处理所有业务逻辑和传入请求,使用模型组件操作数据并与视图交互以呈现最终输出。例如,Customer 控制器将处理来自 Customer 视图的所有交互和输入,并使用 Customer 模型更新数据库。同一个控制器将用于查看 Customer 数据。
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 - 现在,我们将向 Home 控制器添加一个新的视图。要添加新的视图,请右键单击视图文件夹并单击添加 → 视图。
步骤 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() 语句相应地返回 Good Morning/Afternoon 消息。请注意,这里的 Greeting 只是我们与 ViewBag 对象一起使用的示例属性。您可以使用任何其他属性名称来代替 Greeting。
步骤 9 - 打开 Index.cshtml 并将以下代码复制到主体部分。
<body> <div> @ViewBag.Greeting (<b>From Index View</b>) </div> </body>
在上面的代码中,我们正在使用 @ 访问 ViewBag 对象的 Greeting 属性的值(它将从控制器设置)。
步骤 10 - 现在再次运行应用程序。这次我们的代码将首先运行控制器,设置 ViewBag,然后使用 View 代码呈现它。以下是输出。
MVC 框架 - 文件夹
既然我们已经创建了一个示例 MVC 应用程序,让我们了解一下 MVC 项目的文件夹结构。我们将创建一个新的 MVC 项目来学习这一点。
在您的 Visual Studio 中,打开文件 → 新建 → 项目并选择 ASP.NET MVC 应用程序。将其命名为MVCFolderDemo。
单击确定。在下一个窗口中,选择 Internet 应用程序作为项目模板并单击确定。
这将创建一个示例 MVC 应用程序,如下面的屏幕截图所示。
注意 - 此项目中存在的文件来自我们选择的默认模板。根据不同版本,这些文件可能会略有变化。
Controllers 文件夹
此文件夹将包含所有控制器类。MVC 要求所有控制器文件的名称以 Controller 结尾。
在我们的示例中,Controllers 文件夹包含两个类文件:AccountController 和 HomeController。
Models 文件夹
此文件夹将包含所有模型类,这些类用于处理应用程序数据。
在我们的示例中,Models 文件夹包含 AccountModels。您可以打开并查看此文件中的代码,以了解如何创建用于管理我们示例中帐户的数据模型。
Views 文件夹
此文件夹存储与应用程序显示和用户界面相关的 HTML 文件。它为每个控制器包含一个文件夹。
在我们的示例中,您将在 Views 下看到三个子文件夹,即 Account、Home 和 Shared,其中包含特定于该视图区域的 html 文件。
App_Start 文件夹
此文件夹包含应用程序加载期间需要的所有文件。
例如,RouteConfig 文件用于将传入的 URL 路由到正确的控制器和操作。
Content 文件夹
此文件夹包含所有静态文件,例如 css、图像、图标等。
此文件夹中的 Site.css 文件是应用程序应用的默认样式。
Scripts 文件夹
此文件夹存储项目中的所有 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 框架通过读取路由数据生成的 controller 属性的值来了解哪个控制器类已成为请求的目标。
步骤 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 代码嵌入到网页中。此服务器端代码可用于在加载网页时创建动态内容。与 ASPX 引擎相比,Razor 是一个高级引擎,并在 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 的 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 模型添加到视图中。此外,您也无法使用 IntelliSense,因为这次绑定将在运行时完成。
强类型视图被认为是一种更好的方法,因为我们已经知道作为模型传递的数据是什么,这与动态类型视图不同,在动态类型视图中,数据在运行时绑定,如果链接模型中发生任何更改,可能会导致运行时错误。
MVC 框架 - 布局
布局用于在 MVC 中为应用程序的所有页面提供一致的外观和感觉。这与定义母版页相同,但 MVC 提供了一些额外的功能。
创建 MVC 布局
步骤 1 - 使用“Internet 应用程序”作为模板创建一个示例 MVC 应用程序,并在 Web 应用程序的根目录下创建一个 Content 文件夹。
步骤 2 - 在 CONTENT 文件夹下创建一个名为 MyStyleSheet.css 的样式表文件。此 CSS 文件将包含 Web 应用程序页面一致设计所需的所有 CSS 类。
步骤 3 - 在 View 文件夹下创建一个 Shared 文件夹。
步骤 4 - 在 Shared 文件夹下创建一个 MasterLayout.cshtml 文件。MasterLayout.cshtml 文件表示应用程序中每个页面的布局。右键单击解决方案资源管理器中的 Shared 文件夹,然后转到“添加项”并单击“视图”。复制以下布局代码。
布局代码
<!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() - 此方法指定我们在 View 代码中使用的任何文件的路径。它以虚拟路径作为输入,并返回绝对路径。
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,这对应于 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 框架会自动理解控制器后缀。
创建简单路由
路由定义在 RouteConfig.cs 文件中,该文件位于 App_Start 项目文件夹下。
您将在该文件中看到以下代码:
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 } ); } }
此 RegisterRoutes 方法在应用程序启动时由 Global.ascx 调用。Global.ascx 下的 Application_Start 方法调用此 MapRoute 函数,该函数设置默认控制器及其操作(控制器类中的方法)。
要根据我们的示例修改上述默认映射,请更改以下代码行:
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 - 添加一个新的模型,它将定义用户数据的结构。右键单击 Models 文件夹,然后单击添加 → 类。将其命名为 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 并单击添加 → 类。将其命名为 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
此视图将在索引页面上显示系统中存在的所有用户。
@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 文件夹,然后单击添加 → 控制器。将其命名为 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 - 右键单击 Index 方法,然后选择创建视图以创建索引页面的视图(它将列出所有用户并提供创建新用户的选项)。
步骤 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 文件并将默认控制器更改为 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 - 现在创建一个名为 GetUser 的视图,并使用以下代码。此视图将异步从之前创建的控制器的 GetUserData 操作获取数据。
@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 条目以启动 User 控制器。
defaults: new { controller = "User", action = "GetUser", id = UrlParameter.Optional }
步骤 6 - 运行应用程序,它将如下面的屏幕截图所示。
如果您从下拉列表中选择管理员,它将获取所有类型为管理员的用户。这是通过 AJAX 完成的,并且不会重新加载整个页面。
MVC 框架 - 捆绑
捆绑和压缩是两种性能改进技术,可提高应用程序的请求加载时间。大多数当前的主流浏览器将每个主机名的同时连接数限制为六个。这意味着,一次,浏览器将对所有其他请求进行排队。
启用捆绑和压缩
要在您的 MVC 应用程序中启用捆绑和压缩,请打开解决方案中的 Web.config 文件。在此文件中,搜索 system.web 下的编译设置 -
<system.web> <compilation debug = "true" /> </system.web>
默认情况下,您将看到调试参数设置为 true,这意味着捆绑和压缩已禁用。将此参数设置为 false。
捆绑
为了提高应用程序的性能,ASP.NET MVC 提供了内置功能,可以将多个文件捆绑到一个文件中,这反过来又可以提高页面加载性能,因为 HTTP 请求更少。
捆绑是文件的简单逻辑组,可以通过唯一名称引用并使用单个 HTTP 请求加载。
默认情况下,MVC 应用程序的 BundleConfig(位于 App_Start 文件夹中)带有以下代码 -
public static void RegisterBundles(BundleCollection bundles) { // Following is the sample code to bundle all the css files in the project // The code to bundle other javascript files will also be similar to this 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 方法
当我们希望在控制器级别处理所有操作方法中的所有异常时,使用此方法。
要了解此方法,请创建一个 MVC 应用程序(按照前面章节中介绍的步骤)。现在添加一个新的控制器类并添加以下代码,该代码覆盖 onException 方法并在我们的操作方法中显式抛出错误 -
现在让我们创建一个名为Error的通用视图,当应用程序中发生任何异常时,该视图将显示给用户。在 Views 文件夹中,创建一个名为 Shared 的新文件夹,并添加一个名为 Error 的新视图。
将以下代码复制到新创建的 Error.cshtml 中 -
如果您现在尝试运行应用程序,它将给出以下结果。以上代码在该控制器中的任何操作方法中发生任何异常时,都会呈现 Error 视图。
此方法的优点是同一个控制器中的多个操作可以共享此错误处理逻辑。但是,缺点是我们无法在多个控制器中使用相同的错误处理逻辑。
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 可以用于任何级别和跨控制器来处理此类错误。