ASP.NET MVC 快速指南



ASP.NET MVC - 概述

ASP.NET MVC 本质上是微软的一个Web开发框架,它结合了MVC(模型-视图-控制器)架构的功能、敏捷开发的最新理念和技术,以及现有ASP.NET平台的最佳部分。

ASP.NET MVC并非从零开始构建的。它是传统ASP.NET Web Forms的完整替代方案。它构建在ASP.NET之上,因此开发人员在构建MVC应用程序时可以享受几乎所有ASP.NET功能。

Building MVC Application

历史

ASP.NET 1.0于2002年1月5日作为.Net Framework 1.0版的一部分发布。当时,很容易将ASP.NET和Web Forms视为同一事物。然而,ASP.NET始终支持两层抽象:

  • System.Web.UI - Web Forms层,包括服务器控件、ViewState等等。

  • System.Web - 它提供基本的web栈,包括模块、处理程序、HTTP栈等等。

到2007年ASP.NET MVC发布时,MVC模式正成为构建Web框架最流行的方式之一。

2009年4月,ASP.NET MVC源代码在微软公共许可证(MS-PL)下发布。“ASP.NET MVC框架是一个轻量级、高度可测试的表示框架,它与现有的ASP.NET功能集成在一起。”

其中一些集成功能包括母版页和基于成员身份的验证。MVC框架定义在System.Web.Mvc程序集中。

2012年3月,微软在其web栈(包括ASP.NET MVC、Razor和Web API)的一部分发布了一个开源许可证(Apache License 2.0)。ASP.NET Web Forms未包含在此计划中。

为什么选择ASP.NET MVC?

微软决定创建他们自己的MVC框架来构建Web应用程序。MVC框架只是构建在ASP.NET之上。当您使用ASP.NET MVC构建Web应用程序时,不会出现状态错觉,不会有诸如页面加载和页面生命周期之类的事情。

ASP.NET MVC的另一个设计目标是在框架的所有方面都是可扩展的。因此,当我们谈论视图时,视图必须由特定类型的视图引擎呈现。默认的视图引擎仍然是可以使用ASPX文件的引擎。但是,如果您不喜欢使用ASPX文件,您可以使用其他东西并插入您自己的视图引擎。

MVC框架内部有一个组件可以实例化您的控制器。您可能不喜欢MVC框架实例化控制器的方式,您可能希望自己处理这项工作。因此,在MVC中有很多地方可以注入您自己的自定义逻辑来处理任务。

使用模型视图控制器设计模式的整个想法是,您可以保持关注点分离。您的控制器不再受许多与ASP.NET运行时或ASPX页面的联系的限制,这很难进行测试。您现在只需要一个带有常规方法的类,您可以在单元测试中调用它,以了解该控制器是否会正确运行。

ASP.NET MVC 的优势

以下是使用ASP.NET MVC的优势:

  • 通过将应用程序划分为模型、视图和控制器,更容易管理复杂性。

  • 能够完全控制呈现的HTML,并提供清晰的关注点分离。

  • 直接控制HTML也意味着更好地访问实现对不断发展的Web标准的合规性。

  • 方便为现有应用程序添加更多交互性和响应能力。

  • 为测试驱动开发 (TDD) 提供更好的支持。

  • 非常适合由大型开发团队支持的Web应用程序,以及需要高度控制应用程序行为的Web设计师。

ASP.NET MVC - 模式

MVC(模型-视图-控制器)设计模式实际上已经存在了几十年,并且已在许多不同的技术中使用。从Smalltalk到C++再到Java,现在到C#和.NET都使用这种设计模式来构建用户界面。

以下是MVC模式的一些显著特征:

  • 最初它在1979年被称为Thing-Model-View-Editor,后来简化为Model-View-Controller。

  • 它是一种强大而优雅的分离应用程序内关注点的方法(例如,将数据访问逻辑与显示逻辑分开),并且非常适用于Web应用程序。

  • 它明确的关注点分离确实会增加应用程序设计的一点点额外复杂性,但非凡的好处超过了额外的努力。

MVC架构模式将应用程序的用户界面(UI)分成三个主要部分。

MVC Architectural Pattern
  • 模型 - 一组描述您正在处理的数据以及业务逻辑的类。

  • 视图 - 定义应用程序的UI将如何显示。它是一个纯HTML,决定UI的外观。

  • 控制器 - 一组处理来自用户、整体应用程序流程和特定于应用程序的逻辑的类。

MVC背后的理念

其理念是,您将有一个称为视图的组件,它唯一负责呈现此用户界面,无论是HTML还是桌面应用程序上的UI小部件。

视图与模型对话,该模型包含视图需要显示的所有数据。视图通常几乎没有任何逻辑。

在Web应用程序中,视图可能根本没有任何代码与其关联。它可能只包含HTML,然后是一些表达式,说明从模型中获取数据片段并将其插入到您在视图中构建的HTML模板中的正确位置。

组织一切的是控制器。当HTTP请求到达MVC应用程序时,该请求将被路由到控制器,然后由控制器与数据库、文件系统或模型对话。

ASP.NET MVC - 环境设置

MVC开发工具包含在Visual Studio 2012及更高版本中。它也可以安装在Visual Studio 2010 SP1/Visual Web Developer 2010 Express SP1上。如果您使用的是Visual Studio 2010,您可以使用Web平台安装程序安装MVC 4 http://www.microsoft.com

Microsoft 提供 Visual Studio 的免费版本,其中还包含 SQL Server,可以从 https://www.visualstudio.com 下载

安装

步骤1 - 下载完成后,运行安装程序。将显示以下对话框。

Run the Installer

步骤2 - 单击“安装”按钮,它将启动安装过程。

Installation Process

安装过程成功完成后,您将看到以下对话框。

Installation Process Completed

步骤3 - 关闭此对话框,如果需要,重新启动计算机。

步骤4 - 从“开始”菜单打开Visual Studio,将打开以下对话框。仅第一次准备时需要一段时间。

Open Visual Studio

完成后,您将看到如下屏幕截图所示的Visual Studio主窗口。

Visual Studio Main Window

您现在可以开始您的应用程序了。

ASP.NET MVC - 入门

在本章中,我们将研究ASP.NET MVC的一个简单的可运行示例。我们将在这里构建一个简单的Web应用程序。要创建ASP.NET MVC应用程序,我们将使用Visual Studio 2015,其中包含创建、测试和部署MVC框架应用程序所需的所有功能。

创建ASP.Net MVC应用程序

以下是使用Visual Studio中提供的项目模板创建项目步骤:

步骤1 - 打开Visual Studio。单击“文件”→“新建”→“项目”菜单选项。

将打开一个新的项目对话框。

Project Menu Option

步骤2 - 从左窗格中选择“模板”→“Visual C#”→“Web”。

步骤3 - 在中间窗格中,选择ASP.NET Web应用程序。

步骤4 - 在“名称”字段中输入项目名称MVCFirstApp,然后单击“确定”继续。您将看到以下对话框,要求您设置ASP.NET项目的初始内容。

Enter Project Name

步骤5 - 为简单起见,选择“空”选项,并在“添加文件夹和核心引用”部分中选中MVC复选框。单击“确定”。

它将创建一个具有最少预定义内容的基本MVC项目。

Visual Studio创建项目后,您将在解决方案资源管理器窗口中看到许多文件和文件夹。

Created ASP.Net MVC Project

正如您所知,我们是从空项目模板创建的ASP.Net MVC项目,因此目前应用程序没有任何可运行的内容。

步骤6 - 从“调试”→“启动调试”菜单选项运行此应用程序,您将看到404 未找到错误。

404 Not Found Error

默认浏览器是Internet Explorer,但您可以从工具栏中选择已安装的任何浏览器。

添加控制器

要删除404未找到错误,我们需要添加一个控制器来处理所有传入的请求。

步骤1 - 要添加控制器,请右键单击解决方案资源管理器中的控制器文件夹,然后选择“添加”→“控制器”。

Add Controller

它将显示“添加脚手架”对话框。

Controller Scaffold Dialog

步骤2 - 选择MVC 5控制器 - 空选项,然后单击“添加”按钮。

将出现“添加控制器”对话框。

Add Controller Dialog

步骤3 - 将名称设置为HomeController,然后单击“添加”按钮。

您将在Controllers文件夹中看到一个新的C#文件HomeController.cs,它也在Visual Studio中打开以进行编辑。

C# HomeController

步骤4 - 为此示例,让我们通过使用以下代码更改名为Index的操作方法来修改控制器类。

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

namespace MVCFirstApp.Controllers {
   public class HomeController : Controller {
      // GET: Home
      public string Index(){
         return "Hello World, this is ASP.Net MVC Tutorials";
      }
   }
}

步骤5 - 运行此应用程序,您将看到浏览器显示Index操作方法的结果。

Index Action Method

ASP.NET MVC - 生命周期

在本章中,我们将讨论整个MVC管道以及HTTP请求在其遍历ASP.NET中的MVC框架时的生命周期。从高层次来看,生命周期只是一个用于处理某种类型的请求或更改应用程序状态的一系列步骤或事件。您可能已经熟悉各种框架生命周期,这个概念并非MVC独有。

例如,ASP.NET Web窗体平台具有复杂页面生命周期。其他.NET平台,如Windows Phone应用程序,也有其自身的应用程序生命周期。所有这些平台都具有一个共同点,无论使用何种技术,理解处理管道都能帮助您更好地利用可用功能,MVC也不例外。

MVC 具有两个生命周期:

  • 应用程序生命周期
  • 请求生命周期
MVC Life Cycles

应用程序生命周期

应用程序生命周期是指应用程序进程实际开始运行IIS到停止运行的时间段。这由应用程序启动文件中的应用程序启动和结束事件标记。

请求生命周期

这是每次我们的应用程序处理HTTP请求时发生的一系列事件。

每个MVC应用程序的入口点都始于路由。ASP.NET平台接收到请求后,它通过URL路由模块确定如何处理该请求。

模块是可以连接到应用程序生命周期并添加功能的.NET组件。路由模块负责将传入的URL与我们在应用程序中定义的路由匹配。

所有路由都与一个关联的路由处理程序相关联,这是MVC框架的入口点。

Route Handler

MVC框架负责将路由数据转换为可以处理请求的具体控制器。创建控制器后,下一步是**动作执行**。一个名为**动作调用器**的组件查找并选择合适的动作方法来调用控制器。

准备我们的动作结果后,下一个阶段触发,即**结果执行**。MVC 将声明结果与执行结果分开。如果结果是视图类型,则将调用视图引擎,它负责查找和呈现我们的视图。

如果结果不是视图,则动作结果将自行执行。此结果执行将生成对原始HTTP请求的实际响应。

ASP.NET MVC - 路由

路由是将HTTP请求定向到控制器的过程,此处理的功能在System.Web.Routing中实现。此程序集不是ASP.NET MVC的一部分。它实际上是ASP.NET运行时的一部分,并随ASP.NET作为.NET 3.5 SP1正式发布。

MVC框架使用**System.Web.Routing**,但ASP.NET动态数据也使用它。MVC框架利用路由将请求定向到控制器。Global.asax文件是应用程序的一部分,您将在其中定义应用程序的路由。

这是我们之前章节中创建的MVC应用程序Global.asax中应用程序启动事件的代码。

using System;
using System.Collections.Generic;
using System.Linq;

using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace MVCFirstApp {
   public class MvcApplication : System.Web.HttpApplication {
      protected void Application_Start(){
         AreaRegistration.RegisterAllAreas();
         RouteConfig.RegisterRoutes(RouteTable.Routes);
      }
   }
}

以下是RouteConfig类的实现,其中包含一个方法RegisterRoutes。

using System;
using System.Collections.Generic;
using System.Linq;

using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace MVCFirstApp {
   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});
      }
   }
}

您将定义路由,这些路由将URL映射到特定的控制器操作。操作只是控制器上的一个方法。它还可以从该URL中提取参数并将它们作为参数传递到方法中。

因此,在应用程序中定义的此路由是默认路由。如上面的代码所示,当您看到一个表单为(something)/(something)/(something)的URL到达时,第一部分是控制器名称,第二部分是操作名称,第三部分是ID参数。

理解路由

MVC应用程序使用ASP.NET路由系统,该系统决定URL如何映射到控制器和操作。

当Visual Studio创建MVC项目时,它会添加一些默认路由以帮助我们开始。运行应用程序时,您会看到Visual Studio已将浏览器定向到端口63664。您几乎肯定会看到浏览器请求的URL中不同的端口号,因为Visual Studio在创建项目时会分配一个随机端口。

Localhost Home

在最后一个示例中,我们添加了一个HomeController,因此您还可以请求以下任何URL,它们将被定向到HomeController上的Index操作。

https://127.0.0.1:63664/Home/

https://127.0.0.1:63664/Home/Index

当浏览器请求http://mysite/或http://mysite/Home时,它会返回HomeController的Index方法的输出。

您也可以通过更改浏览器中的URL来尝试此操作。在此示例中,它是https://127.0.0.1:63664/,只是端口可能不同。

如果将/Home或/Home/Index附加到URL并按“Enter”按钮,您将看到MVC应用程序的相同结果。

Localhost Home Index

正如您在此案例中看到的那样,约定是:我们有一个名为HomeController的控制器,此HomeController将成为我们MVC应用程序的起点。

Visual Studio为新项目创建的默认路由假定您将遵循此约定。但是,如果您想遵循您自己的约定,则需要修改路由。

自定义约定

您当然可以添加您自己的路由。如果您不喜欢这些操作名称,如果您有不同的ID参数,或者您只是对站点的URL结构有所不同,那么您可以添加您自己的路由条目。

让我们来看一个简单的例子。假设我们有一个包含进程列表的页面。以下是将路由到进程页面的代码。

routes.MapRoute(
   "Process",
   "Process/{action}/{id}",
   defaults: new{
      controller = "Process", action = "List ", id = UrlParameter.Optional}
);

当有人进来寻找一个带有Process/Action/Id的URL时,他们将转到Process Controller。我们可以使操作略有不同,默认操作,我们可以将其设为List而不是Index。

现在到达的请求看起来像localhosts/process。路由引擎将使用此路由配置将其传递,因此它将使用List的默认操作。

以下是完整的类实现。

using System;
using System.Collections.Generic;
using System.Linq;

using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace MVCFirstApp{
   public class RouteConfig{
      public static void RegisterRoutes(RouteCollection routes){
         routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
			
         routes.MapRoute(
            "Process", "Process/{action}/{id}",
            defaults: new{
               controller = " Process", action = "List ", id =
               UrlParameter.Optional});
					
         routes.MapRoute(
            name: "Default", url: "{controller}/{action}/{id}",
            defaults: new{
               controller = "Home", action = "Index", id =
               UrlParameter.Optional});
      }
   }
}

**步骤1** - 运行此操作并使用以下URL请求进程页面 **https://127.0.0.1:63664/Process**

Localhost Process

您将看到HTTP 404,因为路由引擎正在查找ProcessController,但它不可用。

**步骤2** - 通过右键单击解决方案资源管理器中的Controllers文件夹并选择Add → Controller来创建ProcessController。

Create ProcessController

它将显示“添加脚手架”对话框。

ProcessController Scaffolding Dialog

**步骤3** - 选择MVC 5 Controller – Empty选项,然后单击“Add”按钮。

将出现“添加控制器”对话框。

Empty Option Add Button

**步骤4** - 将名称设置为ProcessController,然后单击“Add”按钮。

现在,您将在Controllers文件夹中看到一个新的C#文件ProcessController.cs,它也可以在Visual Studio中打开进行编辑。

Set ProcessController

现在我们的默认操作将是List,因此我们希望在这里使用List操作而不是Index。

**步骤5** - 将返回类型从ActionResult更改为string,并使用以下代码从此操作方法返回一些字符串。

using System;
using System.Collections.Generic;
using System.Linq;

using System.Web;
using System.Web.Mvc;

namespace MVCFirstApp.Controllers{
   public class ProcessController : Controller{
      // GET: Process
      public string List(){
         return "This is Process page";
      }
   }
}

**步骤6** - 当您再次运行此应用程序时,您将看到默认路由的结果。当您指定以下URL时,https://127.0.0.1:63664/Process/List,您将看到ProcessController的结果。

Localhost Process List

ASP.NET MVC - 控制器

控制器本质上是ASP.NET MVC应用程序的中心单元。它是第一个接收者,它与传入的HTTP请求交互。因此,控制器决定选择哪个模型,然后它从模型中获取数据并将其传递给相应的视图,之后渲染视图。实际上,控制器控制着应用程序的整体流程,接收输入并呈现正确的输出。

控制器是从System.Web.Mvc.Controller继承的C#类,它是内置的控制器基类。控制器中的每个公共方法都被称为操作方法,这意味着您可以通过某个URL从Web调用它来执行操作。

MVC约定是将控制器放在Visual Studio在设置项目时创建的Controllers文件夹中。

让我们通过创建一个新的ASP.Net MVC项目来看一个简单的控制器示例。

**步骤1** - 打开Visual Studio,然后单击“文件”→“新建”→“项目”菜单选项。

将打开一个新的项目对话框。

Visual Studio Project Menu

步骤2 - 从左窗格中选择“模板”→“Visual C#”→“Web”。

步骤3 - 在中间窗格中,选择ASP.NET Web应用程序。

**步骤4** - 在“名称”字段中输入项目名称“MVCControllerDemo”,然后单击“确定”继续。您将看到以下对话框,提示您设置ASP.NET项目的初始内容。

MVCControllerDemo

**步骤5** - 为简便起见,选择“Empty”选项,然后选中“Add folders and core references for”部分中的MVC复选框,然后单击“确定”。

它将创建一个具有最少预定义内容的基本MVC项目。

Visual Studio创建项目后,您将在解决方案资源管理器窗口中看到许多文件和文件夹。

由于我们是从空项目模板创建ASP.Net MVC项目的,因此目前应用程序没有任何内容可以运行。

**步骤6** - 通过右键单击解决方案资源管理器中的Controllers文件夹来添加EmployeeController。选择Add → Controller。

EmployeeController

它将显示“添加脚手架”对话框。

EmployeeController Scaffolding Dialog

**步骤7** - 选择MVC 5 Controller – Empty选项,然后单击“Add”按钮。

将出现“添加控制器”对话框。

MVC 5 Controller

**步骤8** - 将名称设置为EmployeeController,然后单击“Add”按钮。

您将在Controllers文件夹中看到一个新的C#文件EmployeeController.cs,它也可以在Visual Studio中打开进行编辑。

Custom Route Employee Controller

现在,在这个应用程序中,我们将为Employee控制器添加一个带有默认路由的自定义路由。

**步骤1** - 转到“App_Start”文件夹下的“RouteConfig.cs”文件,并添加以下路由。

routes.MapRoute(
   "Employee", "Employee/{name}", new{
      controller = "Employee", action = "Search", name =
      UrlParameter.Optional });

以下是RouteConfig.cs文件的完整实现。

using System;
using System.Collections.Generic;
using System.Linq;

using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace MVCControllerDemo {
   public class RouteConfig {
      public static void RegisterRoutes(RouteCollection routes){
         routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
			
         routes.MapRoute(
            "Employee", "Employee/{name}", new{
               controller = "Employee", action = "Search", name = UrlParameter.Optional });
					
         routes.MapRoute(
            name: "Default", url: "{controller}/{action}/{id}", defaults: new{
               controller = "Home", action = "Index", id = UrlParameter.Optional });
      }
   }
}

考虑这样一种情况:任何用户都来搜索员工,并指定URL“Employee/Mark”。在这种情况下,Mark将被视为参数名称,而不是操作方法。所以在这种情况下,我们的默认路由将无法正常工作。

为了在传递参数时从浏览器获取传入值,MVC框架提供了一种简单的解决此问题的方法。这是通过在Action方法中使用参数来实现的。

**步骤2** - 使用以下代码更改EmployeeController类。

using System;
using System.Collections.Generic;
using System.Linq;

using System.Web;
using System.Web.Mvc;

namespace MVCControllerDemo.Controllers  {
   public class EmployeeController : Controller {
      // GET: Employee
      public ActionResult Search(string name){
         var input = Server.HtmlEncode(name);
         return Content(input);
      }
   }
}

如果向操作方法添加参数,则MVC框架将查找与参数名称匹配的值。它将应用所有可能的组合来查找参数值。它将在路由数据、查询字符串等中搜索。

因此,如果您请求“/Employee/Mark”,则MVC框架将决定我需要一个名为“UserInput”的参数,然后将从URL中选择Mark,并将其自动传递。

Server.HtmlEncode 会简单地将任何类型的恶意脚本转换为纯文本。当编译并执行上述代码并请求以下 URL https://127.0.0.1:61465/Employee/Mark 时,您将获得以下输出。

Localhost Employee Mark

正如您在上面的屏幕截图中看到的,Mark 是从 URL 中获取的。

ASP.NET MVC - 操作

ASP.NET MVC Action 方法负责执行请求并生成响应。默认情况下,它以 ActionResult 的形式生成响应。操作通常与用户交互具有一对一映射关系。

例如,在浏览器中输入 URL,点击任何特定链接,提交表单等。每次用户交互都会向服务器发送请求。在每种情况下,请求的 URL 都包含 MVC 框架用于调用操作方法的信息。操作方法的一个限制是它们必须是实例方法,因此它们不能是静态方法。也没有返回值限制。因此您可以返回字符串、整数等。

请求处理

操作是 MVC 应用程序中最终的请求目标,它使用控制器基类。让我们来看看请求处理过程。

  • 当 URL 到达时,例如 /Home/index,UrlRoutingModule 会检查并理解路由表中配置的内容知道如何处理该 URL。

Request Processing
  • UrlRoutingModule 将我们在路由表中配置的信息组合在一起,并将控制权交给 MVC 路由处理程序。

  • MVC 路由处理程序将控制器传递给 MvcHandler,它是一个 HTTP 处理程序。

  • MvcHandler 使用控制器工厂实例化控制器,它知道要实例化哪个控制器,因为它在 RouteData 中查找该控制器值。

  • 一旦 MvcHandler 有了一个控制器,MvcHandler 只知道 IController 接口,因此它只是告诉控制器执行。

  • 当它告诉控制器执行时,它已从 MVC 的控制器基类派生。Execute 方法创建一个操作调用器并告诉该操作调用器去查找要调用的方法,查找要调用的操作。

  • 操作调用器再次查看 RouteData 并找到从路由引擎传递过来的 action 参数。

操作类型

操作基本上返回不同类型的操作结果。ActionResult 类是所有操作结果的基类。以下是不同类型的操作结果及其行为的列表。

序号 名称和行为
1

ContentResult

返回字符串

2

FileContentResult

返回文件内容

3

FilePathResult

返回文件内容

4

FileStreamResult

返回文件内容

5

EmptyResult

不返回任何内容

6

JavaScriptResult

返回要执行的脚本

7

JsonResult

返回 JSON 格式的数据

8

RedirectToResult

重定向到指定的 URL

9

HttpUnauthorizedResult

返回 403 HTTP 状态码

10

RedirectToRouteResult

重定向到不同的操作/不同的控制器操作

11

ViewResult

作为视图引擎的响应接收

12

PartialViewResult

作为视图引擎的响应接收

让我们来看一下上一章中我们创建的 EmployeeController 的一个简单示例。

using System;
using System.Collections.Generic;
using System.Linq;

using System.Web;
using System.Web.Mvc;

namespace MVCControllerDemo.Controllers {
   public class EmployeeController : Controller{
      // GET: Employee
      public ActionResult Search(string name){
         var input = Server.HtmlEncode(name);
         return Content(input);
      }
   }
}

当您请求以下 URL https://127.0.0.1:61465/Employee/Mark 时,您将收到以下输出作为操作。

Localhost Employee Mark Output

添加控制器

让我们添加另一个控制器。

步骤 1 - 右键单击 Controllers 文件夹并选择添加 → 控制器。

Add Another Controller

它将显示“添加脚手架”对话框。

Add Scaffolding Dialog

步骤2 - 选择MVC 5控制器 - 空选项,然后单击“添加”按钮。

将出现“添加控制器”对话框。

CustomerController

步骤 3 - 将名称设置为 CustomerController 并单击“添加”按钮。

现在您将在 Controllers 文件夹中看到一个新的 C# 文件“CustomerController.cs”,它也可以在 Visual Studio 中打开进行编辑。

set_name CustomerController

同样,添加另一个名为 HomeController 的控制器。以下是 HomeController.cs 类的实现。

using System;
using System.Collections.Generic;
using System.Linq;

using System.Web;
using System.Web.Mvc;

namespace MVCControllerDemo.Controllers {
   public class HomeController : Controller{
      // GET: Home
      public string Index(){
         return "This is Home Controller";
      }
   }
}

步骤 4 - 运行此应用程序,您将收到以下输出。

Home Controller Output

步骤 5 - 在我们上面创建的 Customer 控制器中添加以下代码。

public string GetAllCustomers(){
   return @"<ul>
      <li>Ali Raza</li>
      <li>Mark Upston</li>
      <li>Allan Bommer</li>
      <li>Greg Jerry</li>
   </ul>";
}

步骤 6 - 运行此应用程序并请求 https://127.0.0.1:61465/Customer/GetAllCustomers。您将看到以下输出。

Localhost GetAllCustomers

您还可以重定向到同一控制器的操作,甚至重定向到不同的控制器。

以下是一个简单的示例,我们将通过使用以下代码更改 HomeController 中的代码来从 HomeController 重定向到 Customer Controller。

using System;
using System.Collections.Generic;
using System.Linq;

using System.Web;
using System.Web.Mvc;

namespace MVCControllerDemo.Controllers{
   public class HomeController : Controller{
      // GET: Home
      public ActionResult Index(){
         return RedirectToAction("GetAllCustomers","Customer");
      }
   }
}

如您所见,我们使用了 RedirectToAction() 方法 ActionResult,它接受两个参数:操作名称和控制器名称。

运行此应用程序后,您将看到默认路由会将其重定向到 /Customer/GetAllCustomers

Localhost Customers GetAllCustomers

ASP.NET MVC - 过滤器

在 ASP.NET MVC 中,控制器定义的操作方法通常与可能的交互有一一对应的关系,但有时您希望在调用操作方法之前或运行操作方法之后执行逻辑。

为支持这一点,ASP.NET MVC 提供了过滤器。过滤器是自定义类,它们提供声明性和编程方式来向控制器操作方法添加操作前和操作后行为。

操作过滤器

操作过滤器是一个属性,您可以将其应用于控制器操作或整个控制器,以修改操作的执行方式。ASP.NET MVC 框架包含多个操作过滤器:

  • OutputCache - 将控制器操作的输出缓存指定时间。

  • HandleError - 处理执行控制器操作时引发的错误。

  • Authorize - 允许您限制对特定用户或角色的访问。

过滤器类型

ASP.NET MVC 框架支持四种不同类型的过滤器:

  • 授权过滤器 - 实现 IAuthorizationFilter 属性。

  • 操作过滤器 - 实现 IActionFilter 属性。

  • 结果过滤器 - 实现 IResultFilter 属性。

  • 异常过滤器 - 实现 IExceptionFilter 属性。

过滤器按上述顺序执行。例如,授权过滤器总是在操作过滤器之前执行,异常过滤器总是在所有其他类型的过滤器之后执行。

授权过滤器用于为控制器操作实现身份验证和授权。例如,Authorize 过滤器就是一个授权过滤器的示例。

让我们通过创建一个新的 ASP.Net MVC 项目来查看一个简单的示例。

步骤 1 - 打开 Visual Studio 并单击文件 → 新建 → 项目菜单选项。

将打开一个新的项目对话框。

New Project Menu Option

步骤2 - 从左窗格中选择“模板”→“Visual C#”→“Web”。

步骤3 - 在中间窗格中,选择ASP.NET Web应用程序。

步骤 4 - 在“名称”字段中输入项目名称 MVCFiltersDemo 并单击确定以继续,您将看到以下对话框,要求您设置 ASP.NET 项目的初始内容。

MVCFiltersDemo

**步骤5** - 为简便起见,选择“Empty”选项,然后选中“Add folders and core references for”部分中的MVC复选框,然后单击“确定”。

它将创建一个具有最少预定义内容的基本MVC项目。

步骤 6 - 要添加控制器,请右键单击解决方案资源管理器中的控制器文件夹,然后选择添加 → 控制器。

它将显示“添加脚手架”对话框。

Controller Add Scaffold Dialog

**步骤7** - 选择MVC 5 Controller – Empty选项,然后单击“Add”按钮。

将出现“添加控制器”对话框。

Add Controller Dialog

步骤 8 - 将名称设置为 HomeController 并单击“添加”按钮。

您将在 Controllers 文件夹中看到一个新的 C# 文件“HomeController.cs”,它也可以在 Visual Studio 中打开进行编辑。

应用操作过滤器

操作过滤器可以应用于单个控制器操作或整个控制器。例如,操作过滤器 OutputCache 应用于名为 Index() 的操作,该操作返回字符串。此过滤器导致操作返回的值被缓存 15 秒。

为了使这个例子能够工作,让我们通过使用以下代码更改名为 Index 的操作方法来修改控制器类。

using System;
using System.Collections.Generic;
using System.Linq;

using System.Web;
using System.Web.Mvc;

namespace MVCFiltersDemo.Controllers {
   public class HomeController : Controller{
      // GET: Home
      [OutputCache(Duration = 15)]
		
      public string Index(){
         return "This is ASP.Net MVC Filters Tutorial";
      }
   }
}

运行此应用程序后,您将看到浏览器显示 Index 操作方法的结果。

MVC Filters Tutorial

让我们添加另一个操作方法,它将显示当前时间。

namespace MVCFiltersDemo.Controllers{
   public class HomeController : Controller{
      // GET: Home
		
      [OutputCache(Duration = 15)]
      public string Index(){
         return "This is ASP.Net MVC Filters Tutorial";
      }
		
      [OutputCache(Duration = 20)]
      public string GetCurrentTime(){
         return DateTime.Now.ToString("T");
      }
   }
}

请求以下 URL,https://127.0.0.1:62833/Home/GetCurrentTime,您将收到以下输出。

Localhost GetCurrentTime

如果您刷新浏览器,您将看到相同的时间,因为操作被缓存了 20 秒。20 秒后刷新时,它将更新。

自定义过滤器

要创建您自己的自定义过滤器,ASP.NET MVC 框架提供了一个基类,称为 ActionFilterAttribute。此类同时实现 IActionFilter 和 IResultFilter 接口,两者都派生自 Filter 类。

让我们通过在您的项目中创建一个名为 ActionFilters 的新文件夹来查看自定义过滤器的简单示例。添加一个类,为此右键单击 ActionFilters 文件夹并选择添加 → 类。

Custom Filter

在名称字段中输入“MyLogActionFilter”并单击“添加”按钮。

此类将派生自 ActionFilterAttribute(这是一个基类)并覆盖以下方法。以下是 MyLogActionFilter 的完整实现。

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace MVCFiltersDemo.ActionFilters {
   public class MyLogActionFilter : ActionFilterAttribute{
      public override void OnActionExecuting(ActionExecutingContext filterContext){
         Log("OnActionExecuting", filterContext.RouteData);
      }
		
      public override void OnActionExecuted(ActionExecutedContext filterContext){
         Log("OnActionExecuted", filterContext.RouteData);
      }
		
      public override void OnResultExecuting(ResultExecutingContext filterContext){
         Log("OnResultExecuting", filterContext.RouteData);
      }
		
      public override void OnResultExecuted(ResultExecutedContext filterContext){
         Log("OnResultExecuted", filterContext.RouteData);
      }
		
      private void Log(string methodName, RouteData routeData){
         var controllerName = routeData.Values["controller"];
         var actionName = routeData.Values["action"];
			
         var message = String.Format(
            "{0} controller:{1} action:{2}", methodName, controllerName, actionName);
				
         Debug.WriteLine(message, "Action Filter Log");
      }
   }
}

现在让我们使用以下代码将日志过滤器应用于 HomeController。

using MVCFiltersDemo.ActionFilters;
using System;
using System.Collections.Generic;
using System.Linq;

using System.Web;
using System.Web.Mvc;

namespace MVCFiltersDemo.Controllers {
   [MyLogActionFilter]
   public class HomeController : Controller{
      // GET: Home
		
      [OutputCache(Duration = 10)]
      public string Index(){
         return "This is ASP.Net MVC Filters Tutorial";
      }
		
      [OutputCache(Duration = 10)]
      public string GetCurrentTime(){
         return DateTime.Now.ToString("T");
      }
   }
}

运行应用程序,然后观察输出窗口。

Output Window

如上面的屏幕截图所示,操作处理的各个阶段都记录到 Visual Studio 输出窗口中。

ASP.NET MVC - 选择器

操作选择器是可以应用于操作方法的属性,用于影响响应请求时调用哪个操作方法。它帮助路由引擎选择正确的操作方法来处理特定请求。

当您编写操作方法时,它扮演着非常重要的角色。这些选择器将根据操作方法前面给出的修改后的名称来决定方法调用的行为。它通常用于为操作方法的名称设置别名。

操作选择器属性有三种类型:

  • ActionName
  • NonAction
  • ActionVerbs

ActionName

此类表示一个属性,用于操作的名称。它还允许开发人员使用与方法名称不同的操作名称。

让我们来看一下上一章中包含两个操作方法的 HomeController 的一个简单示例。

using System;
using System.Collections.Generic;
using System.Linq;

using System.Web;
using System.Web.Mvc;

namespace MVCFiltersDemo.Controllers {
   public class HomeController : Controller{
      // GET: Home
      public string Index(){
         return "This is ASP.Net MVC Filters Tutorial";
      } 
		
      public string GetCurrentTime(){
         return DateTime.Now.ToString("T");
      }
   }
}

让我们通过在 GetCurrentTime() 上方编写 [ActionName("CurrentTime")] 来为 GetCurrentTime 应用 ActionName 选择器,如下面的代码所示。

using System;
using System.Collections.Generic;
using System.Linq;

using System.Web;
using System.Web.Mvc;

namespace MVCFiltersDemo.Controllers {
   public class HomeController : Controller{
      // GET: Home
      public string Index(){
         return "This is ASP.Net MVC Filters Tutorial";
      }
		
      [ActionName("CurrentTime")]
      public string GetCurrentTime(){
         return DateTime.Now.ToString("T");
      }
   }
}

现在运行此应用程序并在浏览器中输入以下 URL https://127.0.0.1:62833/Home/CurrentTime,您将收到以下输出。

Localhost CurrentTime

您可以看到我们在上面的 URL 中使用了 CurrentTime 代替原始操作名称 GetCurrentTime。

NonAction

NonAction 是另一个内置属性,它指示控制器的公共方法不是操作方法。当您希望某个方法不被视为操作方法时,可以使用它。

让我们通过在 HomeController 中添加另一个方法并应用 NonAction 属性来查看一个简单的示例,如下面的代码所示。

using MVCFiltersDemo.ActionFilters;
using System;
using System.Collections.Generic;
using System.Linq;

using System.Web;
using System.Web.Mvc;

namespace MVCFiltersDemo.Controllers {
   public class HomeController : Controller{
      // GET: Home
      public string Index(){
         return "This is ASP.Net MVC Filters Tutorial";
      }
		
      [ActionName("CurrentTime")]
      public string GetCurrentTime(){
         return TimeString();
      }
		
      [NonAction]
      public string TimeString(){
         return "Time is " + DateTime.Now.ToString("T");
      }
   }
}

新的方法 TimeString 从 GetCurrentTime() 调用,但您不能在 URL 中将其用作操作。

让我们运行此应用程序并在浏览器中指定以下 URL https://127.0.0.1:62833/Home/CurrentTime。您将收到以下输出。

Localhost Home CurrentTime

现在让我们检查 URL 中作为操作的 /TimeString 并看看会发生什么。

TimeString

您可以看到它给出了“404—未找到”错误。

ActionVerbs

您可以应用的另一个选择器过滤器是 ActionVerbs 属性。因此,这限制了特定操作对特定 HttpVerbs 的指示。您可以定义两个具有相同名称的不同操作方法,但一个操作方法响应 HTTP Get 请求,另一个操作方法响应 HTTP Post 请求。

MVC 框架支持以下 ActionVerbs。

  • HttpGet
  • HttpPost
  • HttpPut
  • HttpDelete
  • HttpOptions
  • HttpPatch

让我们来看一个简单的示例,我们将创建 EmployeeController。

using System;
using System.Collections.Generic;
using System.Linq;

using System.Web;
using System.Web.Mvc;

namespace MVCControllerDemo.Controllers {
   public class EmployeeController : Controller{
      // GET: Employee
      public ActionResult Search(string name = “No name Entered”){
         var input = Server.HtmlEncode(name);
         return Content(input);
      }
   }
}

现在让我们使用以下代码添加另一个具有相同名称的操作方法。

using System;
using System.Collections.Generic;
using System.Linq;

using System.Web;
using System.Web.Mvc;

namespace MVCControllerDemo.Controllers {
   public class EmployeeController : Controller{
      // GET: Employee
      //public ActionResult Index()
      //{
         // return View();
      //}
		
      public ActionResult Search(string name){
         var input = Server.HtmlEncode(name);
         return Content(input);
      }
		
      public ActionResult Search(){
         var input = "Another Search action";
         return Content(input);
      }
   }
}

运行此应用程序时,会报错,因为MVC框架无法确定为请求选择哪个操作方法。

让我们使用以下代码,为想要作为响应的操作指定HttpGet ActionVerb。

using System;
using System.Collections.Generic;
using System.Linq;

using System.Web;
using System.Web.Mvc;

namespace MVCControllerDemo.Controllers {
   public class EmployeeController : Controller{
      // GET: Employee
      //public ActionResult Index()
      //{
         // return View();
      //}
		
      public ActionResult Search(string name){
         var input = Server.HtmlEncode(name);
         return Content(input);
      }
		
      [HttpGet]
      public ActionResult Search(){
         var input = "Another Search action";
         return Content(input);
      }
   }
}

运行此应用程序后,您将收到以下输出。

Another Search Action

ASP.NET MVC - 视图

在ASP.NET MVC应用程序中,没有像页面这样的东西,并且在URL中指定路径时,它也不包含任何直接对应于页面的内容。在ASP.NET MVC应用程序中最接近页面的东西被称为视图

在ASP.NET MVC应用程序中,所有传入的浏览器请求都由控制器处理,这些请求被映射到控制器操作。控制器操作可能会返回一个视图,也可能会执行其他类型的操作,例如重定向到另一个控制器操作。

让我们通过创建一个新的ASP.NET MVC项目来看一个简单的视图示例。

步骤 1 - 打开 Visual Studio 并单击文件 → 新建 → 项目菜单选项。

将打开一个新的项目对话框。

Visual Studio

步骤2 - 从左窗格中选择“模板”→“Visual C#”→“Web”。

步骤3 - 在中间窗格中,选择ASP.NET Web应用程序。

步骤4 - 在“名称”字段中输入项目名称“MVCViewDemo”,然后单击“确定”继续。您将看到以下对话框,要求您为ASP.NET项目设置初始内容。

MVCViewDemo

**步骤5** - 为简便起见,选择“Empty”选项,然后选中“Add folders and core references for”部分中的MVC复选框,然后单击“确定”。

它将创建一个具有最少预定义内容的基本MVC项目。现在我们需要添加控制器。

步骤6 - 右键单击解决方案资源管理器中的控制器文件夹,然后选择“添加”→“控制器”。

它将显示“添加脚手架”对话框。

Controller Folder

**步骤7** - 选择MVC 5 Controller – Empty选项,然后单击“Add”按钮。

将出现“添加控制器”对话框。

Add Controller Dialog

步骤 8 - 将名称设置为 HomeController 并单击“添加”按钮。

您将在Controllers文件夹中看到一个新的C#文件“HomeController.cs”,它也可以在Visual Studio中打开进行编辑。

让我们更新HomeController.cs文件,其中包含两个操作方法,如下面的代码所示。

using System;
using System.Collections.Generic;
using System.Linq;

using System.Web;
using System.Web.Mvc;

namespace MVCViewDemo.Controllers {
   public class HomeController : Controller{
      // GET: Home
      public ActionResult Index(){
         return View();
      }
		
      public string Mycontroller(){
         return "Hi, I am a controller";
      }
   }
}

步骤9 - 运行此应用程序,并在浏览器中的URL后面附加/Home/MyController,然后按Enter键。您将收到以下输出。

MyController

由于MyController操作只是返回字符串,因此要从操作返回视图,我们需要先添加视图。

步骤10 - 在添加视图之前,让我们添加另一个操作,它将返回默认视图。

using System;
using System.Collections.Generic;
using System.Linq;

using System.Web;
using System.Web.Mvc;

namespace MVCViewDemo.Controllers {
   public class HomeController : Controller{
      // GET: Home
      public ActionResult Index(){
         return View();
      }
		
      public string Mycontroller(){
         return "Hi, I am a controller";
      }
		
      public ActionResult MyView(){
         return View();
      }
   }
}

步骤11 - 运行此应用程序,并在浏览器中的URL后面附加/Home/MyView,然后按Enter键。您将收到以下输出。

MyView View

您可以在这里看到一个错误,这个错误实际上非常具有描述性,它告诉我们找不到MyView视图。

步骤12 - 要添加视图,请右键单击MyView操作内部,然后选择“添加视图”。

MyView Action

它将显示“添加视图”对话框,并将添加默认名称。

Add View Dialog

步骤13 - 取消选中“使用布局页”复选框,然后单击“添加”按钮。

我们现在在视图中有了默认代码。

Use Layout Page

步骤14 - 使用以下代码在此视图中添加一些文本。

@{
   Layout = null;
}

<!DOCTYPE html>
<html>
   <head>
      <meta name = "viewport" content = "width = device-width" />
      <title>MyView</title>
   </head>
	
   <body>
      <div>
         Hi, I am a view
      </div>
   </body>
	
</html>

步骤15 - 运行此应用程序,并在浏览器中的URL后面附加/Home/MyView。按Enter键,您将收到以下输出。

I am View

您现在可以看到视图中的文本。

ASP.NET MVC - 数据模型

在本章中,我们将讨论在ASP.NET MVC框架应用程序中构建模型。一个模型存储根据控制器的命令检索到的数据,并在视图中显示。

模型是类的集合,您将在其中处理数据和业务逻辑。因此,基本上模型是特定于业务领域的容器。它用于与数据库交互。它还可以用于操作数据以实现业务逻辑。

让我们通过创建一个新的ASP.Net MVC项目来看一个简单的模型示例。

步骤1 - 打开Visual Studio。单击“文件”→“新建”→“项目”菜单选项。

将打开一个新的项目对话框。

Open the Visual Studio

步骤2 - 从左窗格中选择“模板”→“Visual C#”→“Web”。

步骤3 - 在中间窗格中,选择ASP.NET Web应用程序。

步骤4 - 在“名称”字段中输入项目名称“MVCSimpleApp”,然后单击“确定”继续。您将看到以下对话框,要求您为ASP.NET项目设置初始内容。

MVCSimpleApp

**步骤5** - 为简便起见,选择“Empty”选项,然后选中“Add folders and core references for”部分中的MVC复选框,然后单击“确定”。

它将创建一个具有最少预定义内容的基本MVC项目。

现在我们需要添加一个控制器。

步骤6 - 右键单击解决方案资源管理器中的控制器文件夹,然后选择“添加”→“控制器”。

它将显示“添加脚手架”对话框。

Right-click Controller Folder

步骤7 - 选择MVC 5控制器 - 带有读/写操作的选项。此模板将创建一个带有控制器默认操作的Index方法。这也将列出其他方法,如Edit/Delete/Create。

步骤8 - 单击“添加”按钮,将出现“添加控制器”对话框。

Add Employee Controller

步骤9 - 将名称设置为EmployeeController,然后单击“添加”按钮。

步骤10 - 您将在Controllers文件夹中看到一个新的C#文件“EmployeeController.cs”,它在Visual Studio中打开,并带有一些默认操作。

using System;
using System.Collections.Generic;
using System.Linq;

using System.Web;
using System.Web.Mvc;

namespace MVCSimpleApp.Controllers {
   public class EmployeeController : Controller{
      // GET: Employee
      public ActionResult Index(){
         return View();
      }
		
      // GET: Employee/Details/5
      public ActionResult Details(int id){
         return View();
      }
		
      // GET: Employee/Create
      public ActionResult Create(){
         return View();
      }
		
      // POST: Employee/Create
      [HttpPost]
      public ActionResult Create(FormCollection collection){
         try{
            // TODO: Add insert logic here
            return RedirectToAction("Index");
         }catch{
            return View();
         }
      }
		
      // GET: Employee/Edit/5
      public ActionResult Edit(int id){
         return View();
      }
		
      // POST: Employee/Edit/5
      [HttpPost]
      public ActionResult Edit(int id, FormCollection collection){
         try{
            // TODO: Add update logic here
            return RedirectToAction("Index");
         }catch{
            return View();
         }
      }
		
      // GET: Employee/Delete/5
      public ActionResult Delete(int id){
         return View();
      }
		
      // POST: Employee/Delete/5
      [HttpPost]
      public ActionResult Delete(int id, FormCollection collection){
         try{
            // TODO: Add delete logic here
            return RedirectToAction("Index");
         }catch{
            return View();
         }
      }
   }
}

让我们添加一个模型。

步骤11 - 右键单击解决方案资源管理器中的Models文件夹,然后选择“添加”→“类”。

Right-click Models Folder

您将看到“添加新项”对话框。

Add New Item Dialog

步骤12 - 在中间面板中选择“类”,并在名称字段中输入Employee.cs。

步骤13 - 使用以下代码向Employee类添加一些属性。

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

namespace MVCSimpleApp.Models {
   public class Employee{
      public int ID { get; set; }
      public string Name { get; set; }
      public DateTime JoiningDate { get; set; }
      public int Age { get; set; }
   }
}

让我们通过添加另一个方法来更新EmployeeController.cs文件,该方法将返回员工列表。

[NonAction]
public List<Employee> GetEmployeeList(){
   return new List<Employee>{
      new Employee{
         ID = 1,
         Name = "Allan",
         JoiningDate = DateTime.Parse(DateTime.Today.ToString()),
         Age = 23
      },
		
      new Employee{
         ID = 2,
         Name = "Carson",
         JoiningDate = DateTime.Parse(DateTime.Today.ToString()),
         Age = 45
      },
		
      new Employee{
         ID = 3,
         Name = "Carson",
         JoiningDate = DateTime.Parse(DateTime.Today.ToString()),
         Age = 37
      },
		
      new Employee{
         ID = 4,
         Name = "Laura",
         JoiningDate = DateTime.Parse(DateTime.Today.ToString()),
         Age = 26
      },
   };
}

步骤14 - 按以下代码所示更新index操作方法。

public ActionResult Index(){
   var employees = from e in GetEmployeeList()
   orderby e.ID
   select e;
   return View(employees);
}

步骤15 - 运行此应用程序,并在浏览器中的URL后面附加/employee,然后按Enter键。您将看到以下输出。

Can't Find Index View

如上面的屏幕截图所示,出现了一个错误,这个错误实际上非常具有描述性,它告诉我们找不到Index视图。

步骤16 - 因此,要添加视图,请右键单击Index操作内部,然后选择“添加视图”。

Right-click Index Action

它将显示“添加视图”对话框,并将添加默认名称。

Add Default Name

步骤17 - 从“模板”下拉列表中选择“列表”,从“模型类”下拉列表中选择“Employee”,并取消选中“使用布局页”复选框,然后单击“添加”按钮。

它将在此视图中为您添加一些默认代码。

@model IEnumerable<MVCSimpleApp.Models.Employee>
@{
   Layout = null;
}

<!DOCTYPE html>
<html>
   <head>
      <meta name = "viewport" content = "width = device-width" />
      <title>Index</title>
   </head>
	
   <body>
      <p>@Html.ActionLink("Create New", "Create")</p>
         <table class = "table">
         <tr>
            <th>
               @Html.DisplayNameFor(model => model.Name)
            </th>
				
            <th>
               @Html.DisplayNameFor(model => model.JoiningDate)
            </th>
				
            <th>
               @Html.DisplayNameFor(model => model.Age)
            </th>
				
            <th></th>
         </tr>
			
         @foreach (var item in Model) {
            <tr>
               <td>
                  @Html.DisplayFor(modelItem => item.Name)
               </td>
					
               <td>
                  @Html.DisplayFor(modelItem => item.JoiningDate)
               </td>
					
               <td>
                  @Html.DisplayFor(modelItem => item.Age)
               </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>
   </body>
</html>

步骤18 - 运行此应用程序,您将收到以下输出。

List of Employees

将显示员工列表。

ASP.NET MVC - 辅助方法

在ASP.Net Web窗体中,开发人员使用工具箱在任何特定页面上添加控件。但是,在ASP.NET MVC应用程序中,没有可用于将HTML控件拖放到视图上的工具箱。在ASP.NET MVC应用程序中,如果您要创建视图,它应该包含HTML代码。因此,那些刚接触MVC,尤其是具有Web窗体背景的开发人员会觉得这有点困难。

为了克服这个问题,ASP.NET MVC提供了HtmlHelper类,其中包含不同的方法,可以帮助您以编程方式创建HTML控件。所有HtmlHelper方法都生成HTML并将结果作为字符串返回。最终的HTML是由这些函数在运行时生成的。HtmlHelper类旨在生成UI,不应在控制器或模型中使用。

有不同类型的辅助方法。

  • Createinputs - 为文本框和按钮创建输入。

  • Createlinks - 创建基于路由表信息的链接。

  • Createforms - 创建可以发布回我们的操作或发布回不同控制器上的操作的表单标签。

序号 方法和描述
1

Action(String)

重载。调用指定子操作方法并将结果作为HTML字符串返回。(由ChildActionExtensions定义)

2

Action(String, Object)

重载。使用指定参数调用指定子操作方法并将结果作为HTML字符串返回。(由ChildActionExtensions定义)

3

Action(String, RouteValueDictionary)

重载。使用指定的参数调用指定子操作方法并将结果作为HTML字符串返回。(由ChildActionExtensions定义)

4

Action(String, String)

重载。使用指定的控制器名称调用指定子操作方法并将结果作为HTML字符串返回。(由ChildActionExtensions定义)

5

Action(String, String, Object)

重载。使用指定的参数和控制器名称调用指定子操作方法并将结果作为HTML字符串返回。(由ChildActionExtensions定义)

6

Action(String, String, RouteValueDictionary)

重载。使用指定的参数和控制器名称调用指定子操作方法并将结果作为HTML字符串返回。(由ChildActionExtensions定义)

7

ActionLink(String, String)

重载。(由LinkExtensions定义)

8

ActionLink(String, String, Object)

重载。(由LinkExtensions定义)

9

ActionLink(String, String, Object, Object)

重载。(由LinkExtensions定义)

10

ActionLink(String, String, RouteValueDictionary)

重载。(由LinkExtensions定义)

11

ActionLink(String, String, RouteValueDictionary, IDictionary<String, Object>)

重载。(由LinkExtensions定义)

12

ActionLink(String, String, String)

重载。(由LinkExtensions定义)

13

ActionLink(String, String, String, Object, Object)

重载。(由LinkExtensions定义)

14

ActionLink(String, String, String, RouteValueDictionary, IDictionary<String, Object>)

重载。(由LinkExtensions定义)

15

ActionLink(String, String, String, String, String, String, Object, Object)

重载。(由LinkExtensions定义)

16

ActionLink(String, String, String, String, String, String, RouteValueDictionary, IDictionary<String, Object>)

重载。(由LinkExtensions定义)

17

BeginForm()

重载。将打开的<form>标签写入响应。该表单使用POST方法,请求由视图的操作方法处理。(由FormExtensions定义)

18

BeginForm(Object)

重载。将打开的<form>标签写入响应,并在action属性中包含路由值。该表单使用POST方法,请求由视图的操作方法处理。(由FormExtensions定义)

19

BeginForm(RouteValueDictionary)

重载。将打开的<form>标签写入响应,并在action属性中包含来自路由值字典的路由值。该表单使用POST方法,请求由视图的操作方法处理。(由FormExtensions定义。)

20

BeginForm(String, String)

重载。将打开的<form>标签写入响应,并将action标签设置为指定的控制器和操作。该表单使用POST方法。(由FormExtensions定义)

21

BeginForm(String, String, FormMethod)

重载。将打开的<form>标签写入响应,并将action标签设置为指定的控制器和操作。该表单使用指定的HTTP方法。(由FormExtensions定义)

22

BeginForm(String, String, FormMethod, IDictionary<String, Object>)

重载。将打开的<form>标签写入响应,并将action标签设置为指定的控制器和操作。该表单使用指定的HTTP方法,并包含来自字典的HTML属性。(由FormExtensions定义)

23

BeginForm(String, String, FormMethod, Object)

重载。将打开的<form>标签写入响应,并将action标签设置为指定的控制器和操作。该表单使用指定的HTTP方法,并包含HTML属性。(由FormExtensions定义)

24

BeginForm(String, String, Object)

重载。向响应中写入一个起始<form>标记,并将 action 标记设置为指定的控制器、操作和路由值。表单使用 POST 方法。(由 FormExtensions 定义)

25

BeginForm(String, String, Object, FormMethod)

重载。向响应中写入一个起始<form>标记,并将 action 标记设置为指定的控制器、操作和路由值。表单使用指定的 HTTP 方法。(由 FormExtensions 定义)

26

BeginForm(String, String, Object, FormMethod, Object)

重载。向响应中写入一个起始<form>标记,并将 action 标记设置为指定的控制器、操作和路由值。表单使用指定的 HTTP 方法并包含 HTML 属性。(由 FormExtensions 定义)

27

BeginForm(String, String, RouteValueDictionary)

重载。向响应中写入一个起始<form>标记,并将 action 标记设置为来自路由值字典中指定的控制器、操作和路由值。表单使用 POST 方法。(由 FormExtensions 定义)

28

BeginForm(String, String, RouteValueDictionary, FormMethod)

重载。向响应中写入一个起始<form>标记,并将 action 标记设置为来自路由值字典中指定的控制器、操作和路由值。表单使用指定的 HTTP 方法。(由 FormExtensions 定义)

29

BeginForm(String, String, RouteValueDictionary, FormMethod, IDictionary<String, Object>)

重载。向响应中写入一个起始<form>标记,并将 action 标记设置为来自路由值字典中指定的控制器、操作和路由值。表单使用指定的 HTTP 方法,并包含来自字典的 HTML 属性。(由 FormExtensions 定义)

30

BeginRouteForm(Object)

重载。向响应中写入一个起始<form>标记。当用户提交表单时,请求将由路由目标处理。(由 FormExtensions 定义)

31

BeginRouteForm(RouteValueDictionary)

重载。向响应中写入一个起始<form>标记。当用户提交表单时,请求将由路由目标处理。(由 FormExtensions 定义)

32

BeginRouteForm(String)

重载。向响应中写入一个起始<form>标记。当用户提交表单时,请求将由路由目标处理。(由 FormExtensions 定义)

33

BeginRouteForm(String, FormMethod)

重载。向响应中写入一个起始<form>标记。当用户提交表单时,请求将由路由目标处理。(由 FormExtensions 定义)

34

BeginRouteForm(String, FormMethod, IDictionary<String, Object>)

重载。向响应中写入一个起始<form>标记。当用户提交表单时,请求将由路由目标处理。(由 FormExtensions 定义)

35

BeginRouteForm(String, FormMethod, Object)

重载。向响应中写入一个起始<form>标记。当用户提交表单时,请求将由路由目标处理。(由 FormExtensions 定义)

36

BeginRouteForm(String, Object)

重载。向响应中写入一个起始<form>标记。当用户提交表单时,请求将由路由目标处理。(由 FormExtensions 定义)

37

BeginRouteForm(String, Object, FormMethod)

重载。向响应中写入一个起始<form>标记。当用户提交表单时,请求将由路由目标处理。(由 FormExtensions 定义)

38

BeginRouteForm(String, Object, FormMethod, Object)

重载。向响应中写入一个起始<form>标记。当用户提交表单时,请求将由路由目标处理。(由 FormExtensions 定义)

39

BeginRouteForm(String, RouteValueDictionary)

重载。向响应中写入一个起始<form>标记。当用户提交表单时,请求将由路由目标处理。(由 FormExtensions 定义)

40

BeginRouteForm(String, RouteValueDictionary, FormMethod)

重载。向响应中写入一个起始<form>标记。当用户提交表单时,请求将由路由目标处理。(由 FormExtensions 定义)

41

BeginRouteForm(String, RouteValueDictionary, FormMethod, IDictionary<String, Object>)

重载。向响应中写入一个起始<form>标记。当用户提交表单时,请求将由路由目标处理。(由 FormExtensions 定义)

42

CheckBox(String)

重载。使用指定的 HTML 辅助方法和表单字段的名称返回一个复选框输入元素。(由 InputExtensions 定义)

43

CheckBox(String, Boolean)

重载。使用指定的 HTML 辅助方法、表单字段的名称和一个值来指示复选框是否被选中,返回一个复选框输入元素。(由 InputExtensions 定义)

44

CheckBox(String, Boolean, IDictionary<String, Object>)

重载。使用指定的 HTML 辅助方法、表单字段的名称、一个值来指示复选框是否被选中以及 HTML 属性,返回一个复选框输入元素。(由 InputExtensions 定义)

45

CheckBox(String, Boolean, Object)

重载。使用指定的 HTML 辅助方法、表单字段的名称、一个值来指示复选框是否被选中以及 HTML 属性,返回一个复选框输入元素。(由 InputExtensions 定义)

46

CheckBox(String, IDictionary<String, Object>)

重载。使用指定的 HTML 辅助方法、表单字段的名称和 HTML 属性,返回一个复选框输入元素。(由 InputExtensions 定义)

47

CheckBox(String, Object)

重载。使用指定的 HTML 辅助方法、表单字段的名称和 HTML 属性,返回一个复选框输入元素。(由 InputExtensions 定义)

48

Display(String)

重载。返回由字符串表达式表示的对象中每个属性的 HTML 标记。(由 DisplayExtensions 定义)

49

Display(String, Object)

重载。使用附加视图数据返回由字符串表达式表示的对象中每个属性的 HTML 标记。(由 DisplayExtensions 定义)

50

Display(String, String)

重载。使用指定的模板返回由表达式表示的对象中每个属性的 HTML 标记。(由 DisplayExtensions 定义)

51

Display(String, String, Object)

重载。使用指定的模板和附加视图数据返回由表达式表示的对象中每个属性的 HTML 标记。(由 DisplayExtensions 定义)

52

Display(String, String, String)

重载。使用指定的模板和 HTML 字段 ID 返回由表达式表示的对象中每个属性的 HTML 标记。(由 DisplayExtensions 定义)

53

Display(String, String, String, Object)

重载。使用指定的模板、HTML 字段 ID 和附加视图数据返回由表达式表示的对象中每个属性的 HTML 标记。(由 DisplayExtensions 定义)

54

DisplayForModel()

重载。返回模型中每个属性的 HTML 标记。(由 DisplayExtensions 定义)

55

DisplayForModel(Object)

重载。使用附加视图数据返回模型中每个属性的 HTML 标记。(由 DisplayExtensions 定义)

56

DisplayForModel(String)

重载。使用指定的模板返回模型中每个属性的 HTML 标记。(由 DisplayExtensions 定义)

57

DisplayForModel(String, Object)

重载。使用指定的模板和附加视图数据返回模型中每个属性的 HTML 标记。(由 DisplayExtensions 定义)

58

DisplayForModel(String, String)

重载。使用指定的模板和 HTML 字段 ID 返回模型中每个属性的 HTML 标记。(由 DisplayExtensions 定义)

59

DisplayForModel(String, String, Object)

重载。使用指定的模板、HTML 字段 ID 和附加视图数据返回模型中每个属性的 HTML 标记。(由 DisplayExtensions 定义)

60

DisplayName(String)

获取显示名称。(由 DisplayNameExtensions 定义)

61

DisplayNameForModel()

获取模型的显示名称。(由 DisplayNameExtensions 定义)

62

DisplayText(String)

返回由指定表达式表示的对象中每个属性的 HTML 标记。(由 DisplayTextExtensions 定义)

63

DropDownList(String)

重载。使用指定的 HTML 辅助方法和表单字段的名称返回一个单选选择元素。(由 SelectExtensions 定义)

64

DropDownList(String, IEnumerable<SelectListItem>)

重载。使用指定的 HTML 辅助方法、表单字段的名称和指定的列表项返回一个单选选择元素。(由 SelectExtensions 定义)

65

DropDownList(String, IEnumerable<SelectListItem>, IDictionary<String, Object>)

重载。使用指定的 HTML 辅助方法、表单字段的名称、指定的列表项和指定的 HTML 属性返回一个单选选择元素。(由 SelectExtensions 定义)

66

DropDownList(String, IEnumerable<SelectListItem>, Object)

重载。使用指定的 HTML 辅助方法、表单字段的名称、指定的列表项和指定的 HTML 属性返回一个单选选择元素。(由 SelectExtensions 定义)

67

DropDownList(String, IEnumerable<SelectListItem>, String)

重载。使用指定的 HTML 辅助方法、表单字段的名称、指定的列表项和一个选项标签返回一个单选选择元素。(由 SelectExtensions 定义)

68

DropDownList(String, IEnumerable<SelectListItem>, String, IDictionary<String, Object>)

重载。使用指定的 HTML 辅助方法、表单字段的名称、指定的列表项、一个选项标签和指定的 HTML 属性返回一个单选选择元素。(由 SelectExtensions 定义)

69

DropDownList(String, IEnumerable<SelectListItem>, String, Object)

重载。使用指定的 HTML 辅助方法、表单字段的名称、指定的列表项、一个选项标签和指定的 HTML 属性返回一个单选选择元素。(由 SelectExtensions 定义)

70

DropDownList(String, String)

重载。使用指定的 HTML 辅助方法、表单字段的名称和一个选项标签返回一个单选选择元素。(由 SelectExtensions 定义)

71

Editor(String)

重载。为由表达式表示的对象中每个属性返回一个 HTML 输入元素。(由 EditorExtensions 定义)

72

Editor(String, Object)

重载。使用附加视图数据为由表达式表示的对象中每个属性返回一个 HTML 输入元素。(由 EditorExtensions 定义)

73

Editor(String, String)

重载。使用指定的模板为由表达式表示的对象中每个属性返回一个 HTML 输入元素。(由 EditorExtensions 定义)

74

Editor(String, String, Object)

重载。使用指定的模板和附加视图数据为由表达式表示的对象中每个属性返回一个 HTML 输入元素。(由 EditorExtensions 定义)

75

Editor(String, String, String)

重载。使用指定的模板和 HTML 字段名称为由表达式表示的对象中每个属性返回一个 HTML 输入元素。(由 EditorExtensions 定义)

76

Editor(String, String, String, Object)

重载。使用指定的模板、HTML 字段名称和附加视图数据为由表达式表示的对象中每个属性返回一个 HTML 输入元素。(由 EditorExtensions 定义)

77

EditorForModel()

重载。为模型中的每个属性返回一个 HTML 输入元素。(由 EditorExtensions 定义)

78

EditorForModel(Object)

重载。使用附加视图数据为模型中的每个属性返回一个 HTML 输入元素。(由 EditorExtensions 定义)

79

EditorForModel(String)

重载。使用指定的模板为模型中的每个属性返回一个 HTML 输入元素。(由 EditorExtensions 定义)

80

EditorForModel(String, Object)

重载。使用指定的模板和附加视图数据为模型中的每个属性返回一个 HTML 输入元素。(由 EditorExtensions 定义)

81

EditorForModel(String, String)

重载。使用指定的模板名称和 HTML 字段名称为模型中的每个属性返回一个 HTML 输入元素。(由 EditorExtensions 定义)

82

EditorForModel(String, String, Object)

重载。使用模板名称、HTML 字段名称和附加视图数据为模型中的每个属性返回一个 HTML 输入元素。(由 EditorExtensions 定义)

83

EndForm()

向响应中呈现结束</form>标记。(由 FormExtensions 定义)

84

Hidden(String)

重载。使用指定的 HTML 辅助方法和表单字段的名称返回一个隐藏的输入元素。(由 InputExtensions 定义)

85

Hidden(String, Object)

重载。使用指定的 HTML 辅助方法、表单字段的名称和值返回一个隐藏的输入元素。(由 InputExtensions 定义)

86

Hidden(String, Object, IDictionary<String, Object>)

重载。使用指定的 HTML 辅助方法、表单字段的名称、值和 HTML 属性返回一个隐藏的输入元素。(由 InputExtensions 定义)

87

Hidden(String, Object, Object)

重载。使用指定的 HTML 辅助方法、表单字段的名称、值和 HTML 属性返回一个隐藏的输入元素。(由 InputExtensions 定义)

88

Id(String)

获取 HtmlHelper 字符串的 ID。(由 NameExtensions 定义)

89

IdForModel()

获取 HtmlHelper 字符串的 ID。(由 NameExtensions 定义)

90

Label(String)

重载。返回一个 HTML 标签元素和由指定表达式表示的属性的属性名称。(由 LabelExtensions 定义)

91

Label(String, IDictionary<String, Object>)

重载。返回一个 HTML 标签元素和由指定表达式表示的属性的属性名称。(由 LabelExtensions 定义)

92

Label(String, Object)

重载。返回一个 HTML 标签元素和由指定表达式表示的属性的属性名称。(由 LabelExtensions 定义)

93

Label(String, String)

重载。使用标签文本返回一个 HTML 标签元素和由指定表达式表示的属性的属性名称。(由 LabelExtensions 定义)

94

Label(String, String, IDictionary<String, Object>)

重载。返回一个 HTML 标签元素和由指定表达式表示的属性的属性名称。(由 LabelExtensions 定义)

95

Label(String, String, Object)

重载。返回一个 HTML 标签元素和由指定表达式表示的属性的属性名称。(由 LabelExtensions 定义)

96

LabelForModel()

重载。返回一个 HTML 标签元素和由模型表示的属性的属性名称。(由 LabelExtensions 定义)

97

LabelForModel(IDictionary<String, Object>)

重载。返回一个 HTML 标签元素和由指定表达式表示的属性的属性名称。(由 LabelExtensions 定义)

98

LabelForModel(Object)

重载。返回一个 HTML 标签元素和由指定表达式表示的属性的属性名称。(由 LabelExtensions 定义)

99

LabelForModel(String)

重载。使用标签文本返回一个 HTML 标签元素和由指定表达式表示的属性的属性名称。(由 LabelExtensions 定义)

100

LabelForModel(String, IDictionary<String, Object>)

重载。返回一个 HTML 标签元素和由指定表达式表示的属性的属性名称。(由 LabelExtensions 定义)

101

LabelForModel(String, Object)

重载。返回一个 HTML 标签元素和由指定表达式表示的属性的属性名称。(由 LabelExtensions 定义)

102

ListBox(String)

重载。使用指定的 HTML 辅助方法和表单字段的名称返回一个多选选择元素。(由 SelectExtensions 定义)

103

ListBox(String, IEnumerable<SelectListItem>)

重载。使用指定的 HTML 辅助方法、表单字段的名称和指定的列表项返回一个多选选择元素。(由 SelectExtensions 定义)

104

ListBox(String, IEnumerable<SelectListItem>, IDictionary<String, Object>)

重载。使用指定的 HTML 辅助方法、表单字段的名称、指定的列表项和指定的 HTML 属性返回一个多选选择元素。(由 SelectExtensions 定义)

105

ListBox(String, IEnumerable<SelectListItem>, Object)

重载。使用指定的 HTML 辅助方法、表单字段的名称和指定的列表项返回一个多选选择元素。(由 SelectExtensions 定义)

106

Name(String)

获取由表达式表示的对象的完整 HTML 字段名称。(由 NameExtensions 定义)

107

NameForModel()

获取由表达式表示的对象的完整 HTML 字段名称。(由 NameExtensions 定义。)

108

Partial(String)

重载。将指定的局部视图呈现为 HTML 编码的字符串。(由 PartialExtensions 定义)

109

Partial(String, Object)

重载。将指定的局部视图呈现为 HTML 编码的字符串。(由 PartialExtensions 定义)

110

Partial(String, Object, ViewDataDictionary)

重载。将指定的局部视图呈现为 HTML 编码的字符串。(由 PartialExtensions 定义)

111

Partial(String, ViewDataDictionary)

重载。将指定的局部视图呈现为 HTML 编码的字符串。(由 PartialExtensions 定义)

112

Password(String)

重载。使用指定的HTML辅助方法和表单字段名称返回密码输入元素。(由InputExtensions定义)

113

Password(String, Object)

重载。使用指定的HTML辅助方法、表单字段名称和值返回密码输入元素。(由InputExtensions定义)

114

Password(String, Object, IDictionary<String, Object>)

重载。使用指定的HTML辅助方法、表单字段名称、值和HTML属性返回密码输入元素。(由InputExtensions定义)

115

Password(String, Object, Object)

重载。使用指定的HTML辅助方法、表单字段名称、值和HTML属性返回密码输入元素。(由InputExtensions定义)

116

RadioButton(String, Object)

重载。返回一个单选按钮输入元素,用于呈现互斥选项。(由InputExtensions定义)

117

RadioButton(String, Object, Boolean)

重载。返回一个单选按钮输入元素,用于呈现互斥选项。(由InputExtensions定义)

118

RadioButton(String, Object, Boolean, IDictionary<String, Object>)

重载。返回一个单选按钮输入元素,用于呈现互斥选项。(由InputExtensions定义)

119

RadioButton(String, Object, Boolean, Object)

重载。返回一个单选按钮输入元素,用于呈现互斥选项。(由InputExtensions定义)

120

RadioButton(String, Object, IDictionary<String, Object>)

重载。返回一个单选按钮输入元素,用于呈现互斥选项。(由InputExtensions定义)

121

RadioButton(String, Object, Object)

重载。返回一个单选按钮输入元素,用于呈现互斥选项。(由InputExtensions定义)

122

RenderAction(String)

重载。调用指定的子操作方法,并将结果内联渲染到父视图中。(由ChildActionExtensions定义)

123

RenderAction(String, Object)

重载。使用指定参数调用指定的子操作方法,并将结果内联渲染到父视图中。(由ChildActionExtensions定义)

124

RenderAction(String, RouteValueDictionary)

重载。使用指定参数调用指定的子操作方法,并将结果内联渲染到父视图中。(由ChildActionExtensions定义)

125

RenderAction(String, String)

重载。使用指定的控制器名称调用指定的子操作方法,并将结果内联渲染到父视图中。(由ChildActionExtensions定义)

126

RenderAction(String, String, Object)

重载。使用指定的参数和控制器名称调用指定的子操作方法,并将结果内联渲染到父视图中。(由ChildActionExtensions定义)

127

RenderAction(String, String, RouteValueDictionary)

重载。使用指定的参数和控制器名称调用指定的子操作方法,并将结果内联渲染到父视图中。(由ChildActionExtensions定义)

128

RenderPartial(String)

重载。使用指定的HTML辅助方法呈现指定的局部视图。(由RenderPartialExtensions定义)

129

RenderPartial(String, Object)

重载。呈现指定的局部视图,并传递当前ViewDataDictionary对象的副本,但Model属性设置为指定模型。(由RenderPartialExtensions定义)

130

RenderPartial(String, Object, ViewDataDictionary)

重载。呈现指定的局部视图,用指定的ViewDataDictionary对象替换局部视图的ViewData属性,并将视图数据的Model属性设置为指定的模型。(由RenderPartialExtensions定义)

131

RenderPartial(String, ViewDataDictionary)

重载。呈现指定的局部视图,用指定的ViewDataDictionary对象替换其ViewData属性。(由RenderPartialExtensions定义)

132

RouteLink(String, Object)

重载。(由LinkExtensions定义)

133

RouteLink(String, Object, Object)

重载。(由LinkExtensions定义)

134

RouteLink(String, RouteValueDictionary)

重载。(由LinkExtensions定义)

135

RouteLink(String, RouteValueDictionary, IDictionary<String, Object>)

重载。(由LinkExtensions定义)

136

RouteLink(String, String)

重载。(由LinkExtensions定义)

137

RouteLink(String, String, Object)

重载。(由LinkExtensions定义)

138

RouteLink(String, String, Object, Object)

重载。(由LinkExtensions定义)

139

RouteLink(String, String, RouteValueDictionary)

重载。(由LinkExtensions定义)

140

RouteLink(String, String, RouteValueDictionary, IDictionary<String, Object>)

重载。(由LinkExtensions定义)

141

RouteLink(String, String, String, String, String, Object, Object)

重载。(由LinkExtensions定义)

142

RouteLink(String, String, String, String, String, RouteValueDictionary, IDictionary<String, Object>)

重载。(由LinkExtensions定义)

143

TextArea(String)

重载。使用指定的HTML辅助方法和表单字段名称返回指定的文本区域元素。(由TextAreaExtensions定义。)

144

TextArea(String, IDictionary<String, Object>)

重载。使用指定的HTML辅助方法、表单字段名称和指定的HTML属性返回指定的文本区域元素。(由TextAreaExtensions定义)

145

TextArea(String, Object)

重载。使用指定的HTML辅助方法和HTML属性返回指定的文本区域元素。(由TextAreaExtensions定义)

146

TextArea(String, String)

重载。使用指定的HTML辅助方法、表单字段名称和文本内容返回指定的文本区域元素。(由TextAreaExtensions定义)

147

TextArea(String, String, IDictionary<String, Object>)

重载。使用指定的HTML辅助方法、表单字段名称、文本内容和指定的HTML属性返回指定的文本区域元素。(由TextAreaExtensions定义)

148

TextArea(String, String, Int32, Int32, IDictionary<String, Object>)

重载。使用指定的HTML辅助方法、表单字段名称、文本内容、行数和列数以及指定的HTML属性返回指定的文本区域元素。(由TextAreaExtensions定义)

149

TextArea(String, String, Int32, Int32, Object)

重载。使用指定的HTML辅助方法、表单字段名称、文本内容、行数和列数以及指定的HTML属性返回指定的文本区域元素。(由TextAreaExtensions定义)

150

TextArea(String, String, Object)

重载。使用指定的HTML辅助方法、表单字段名称、文本内容和指定的HTML属性返回指定的文本区域元素。(由TextAreaExtensions定义)

151

TextBox(String)

重载。使用指定的HTML辅助方法和表单字段名称返回文本输入元素。(由InputExtensions定义)

152

TextBox(String, Object)

重载。使用指定的HTML辅助方法、表单字段名称和值返回文本输入元素。(由InputExtensions定义)

153

TextBox(String, Object, IDictionary<String, Object>)

重载。使用指定的HTML辅助方法、表单字段名称、值和HTML属性返回文本输入元素。(由InputExtensions定义)

154

TextBox(String, Object, Object)

重载。使用指定的HTML辅助方法、表单字段名称、值和HTML属性返回文本输入元素。(由InputExtensions定义)

155

TextBox(String, Object, String)

重载。返回一个文本输入元素。(由InputExtensions定义)

156

TextBox(String, Object, String, IDictionary<String, Object>)

重载。返回一个文本输入元素。(由InputExtensions定义)

157

TextBox(String, Object, String, Object)

重载。返回一个文本输入元素。(由InputExtensions定义)

158

Validate(String)

检索指定模型的验证元数据,并将每个规则应用于数据字段。(由ValidationExtensions定义)

159

ValidationMessage(String)

重载。如果ModelStateDictionary对象中指定字段存在错误,则显示验证消息。(由ValidationExtensions定义)

160

ValidationMessage(String, IDictionary<String, Object>)

重载。如果ModelStateDictionary对象中指定字段存在错误,则显示验证消息。(由ValidationExtensions定义。)

161

ValidationMessage(String, IDictionary<String, Object>, String)

重载。如果ModelStateDictionary对象中指定条目存在错误,则显示验证消息。(由ValidationExtensions定义)

162

ValidationMessage(String, Object)

重载。如果ModelStateDictionary对象中指定字段存在错误,则显示验证消息。(由ValidationExtensions定义)

163

ValidationMessage(String, Object, String)

重载。如果ModelStateDictionary对象中指定条目存在错误,则显示验证消息。(由ValidationExtensions定义)

164

ValidationMessage(String, String)

重载。如果ModelStateDictionary对象中指定字段存在错误,则显示验证消息。(由ValidationExtensions定义)

165

ValidationMessage(String, String, IDictionary<String, Object>)

重载。如果ModelStateDictionary对象中指定字段存在错误,则显示验证消息。(由ValidationExtensions定义)

166

ValidationMessage(String, String, IDictionary<String, Object>, String)

重载。如果ModelStateDictionary对象中指定条目存在错误,则显示验证消息。(由ValidationExtensions定义)

167

ValidationMessage(String, String, Object)

重载。如果ModelStateDictionary对象中指定字段存在错误,则显示验证消息。(由ValidationExtensions定义)

168

ValidationMessage(String, String, Object, String)

重载。如果ModelStateDictionary对象中指定条目存在错误,则显示验证消息。(由ValidationExtensions定义)

169

ValidationMessage(String, String, String)

重载。如果ModelStateDictionary对象中指定条目存在错误,则显示验证消息。(由ValidationExtensions定义)

170

ValidationSummary()

重载。返回ModelStateDictionary对象中验证消息的无序列表(ul元素)。(由ValidationExtensions定义)

171

ValidationSummary(Boolean)

重载。返回ModelStateDictionary对象中验证消息的无序列表(ul元素),并可以选择仅显示模型级错误。(由ValidationExtensions定义)

172

ValidationSummary(Boolean, String)

重载。返回ModelStateDictionary对象中验证消息的无序列表(ul元素),并可以选择仅显示模型级错误。(由ValidationExtensions定义)

173

ValidationSummary(Boolean, String, IDictionary<String, Object>)

重载。返回ModelStateDictionary对象中验证消息的无序列表(ul元素),并可以选择仅显示模型级错误。(由ValidationExtensions定义)

174

ValidationSummary(Boolean, String, IDictionary<String, Object>, String)

重载。(由ValidationExtensions定义)

175

ValidationSummary(Boolean, String, Object)

重载。返回ModelStateDictionary对象中验证消息的无序列表(ul元素),并可以选择仅显示模型级错误。(由ValidationExtensions定义)

176

ValidationSummary(Boolean, String, Object, String)

重载。(由ValidationExtensions定义)

177

ValidationSummary(Boolean, String, String)

重载。(由ValidationExtensions定义)

178

ValidationSummary(String)

重载。返回ModelStateDictionary对象中验证消息的无序列表(ul元素)。(由ValidationExtensions定义)

179

ValidationSummary(String, IDictionary<String, Object>)

重载。返回ModelStateDictionary对象中验证消息的无序列表(ul元素)。(由ValidationExtensions定义)

180

ValidationSummary(String, IDictionary<String, Object>, String)

重载。(由ValidationExtensions定义)

181

ValidationSummary(String, Object)

重载。返回ModelStateDictionary对象中验证消息的无序列表(ul元素)。(由ValidationExtensions定义)

182

ValidationSummary(String, Object, String)

重载。(由ValidationExtensions定义)

183

ValidationSummary(String, String)

重载。(由ValidationExtensions定义)

184

Value(String)

重载。提供一种机制来创建与ASP.NET MVC模型绑定器和模板兼容的自定义HTML标记。(由ValueExtensions定义)

185

Value(String, String)

重载。提供一种机制来创建与ASP.NET MVC模型绑定器和模板兼容的自定义HTML标记。(由ValueExtensions定义)

186

ValueForModel()

重载。提供一种机制来创建与ASP.NET MVC模型绑定器和模板兼容的自定义HTML标记。(由ValueExtensions定义)

187

ValueForModel(String)

重载。提供一种机制来创建与ASP.NET MVC模型绑定器和模板兼容的自定义HTML标记。(由ValueExtensions定义)

如果您查看上一章中从EmployeeController索引操作生成的视图,您将看到许多以Html开头的操作,例如Html.ActionLinkHtml.DisplayNameFor等,如下面的代码所示。

@model IEnumerable<MVCSimpleApp.Models.Employee>
@{
   Layout = null;
} 

<!DOCTYPE html>
<html>
   <head>
      <meta name = "viewport" content = "width = device-width" />
      <title>Index</title>
   </head>
	
   <body>
      <p>
         @Html.ActionLink("Create New", "Create")
      </p>
		
      <table class = "table">
         <tr>
            <th>
               @Html.DisplayNameFor(model => model.Name)
            </th>
				
            <th>
               @Html.DisplayNameFor(model => model.JoiningDate)
            </th>
				
            <th>
               @Html.DisplayNameFor(model => model.Age)
            </th>
				
            <th></th>
         </tr>
			
         @foreach (var item in Model) {
            <tr>
               <td>
                  @Html.DisplayFor(modelItem => item.Name)
               </td>
					
               <td>
                  @Html.DisplayFor(modelItem => item.JoiningDate)
               </td>
					
               <td>
                  @Html.DisplayFor(modelItem => item.Age)
               </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>
   </body>
</html>

此HTML是继承自ViewPage基类的属性。因此,它在所有视图中都可用,并且它返回一个称为HTML Helper类型的实例。

让我们来看一个简单的例子,在这个例子中,我们将允许用户编辑员工。因此,此编辑操作将使用大量不同的HTML Helper。

如果您查看上面的代码,您将在最后看到以下HTML Helper方法

@Html.ActionLink("Edit", "Edit", new { id = item.ID })

在ActionLink helper中,第一个参数是链接“Edit”,第二个参数是控制器中的操作方法,也是“Edit”,第三个参数ID是您要编辑的任何特定员工的ID。

让我们通过添加静态列表来更改EmployeeController类,并使用以下代码更改索引操作。

public static List<Employee> empList = new List<Employee>{
   new Employee{
      ID = 1,
      Name = "Allan",
      JoiningDate = DateTime.Parse(DateTime.Today.ToString()),
      Age = 23
   },
	
   new Employee{
      ID = 2,
      Name = "Carson",
      JoiningDate = DateTime.Parse(DateTime.Today.ToString()),
      Age = 45
   },
	
   new Employee{
      ID = 3,
      Name = "Carson",
      JoiningDate = DateTime.Parse(DateTime.Today.ToString()),
      Age = 37
   },
	
   new Employee{
      ID = 4,
      Name = "Laura",
      JoiningDate = DateTime.Parse(DateTime.Today.ToString()),
      Age = 26
   },
	
};

public ActionResult Index(){
   var employees = from e in empList
   orderby e.ID
   select e;
   return View(employees);
}

让我们更新Edit操作。您将看到两个Edit操作,一个用于GET,一个用于POST。让我们更新用于Get的Edit操作,它在参数中只有Id,如下面的代码所示。

// GET: Employee/Edit/5
public ActionResult Edit(int id){
   List<Employee> empList = GetEmployeeList();
   var employee = empList.Single(m => m.ID == id);
   return View(employee);
}

现在,我们知道我们有Edit操作,但我们没有这些操作的任何视图。因此,我们也需要添加一个视图。为此,右键单击Edit操作并选择添加视图。

Right-click Edit Action

您将看到视图的默认名称。从模板下拉列表中选择Edit,从模型类下拉列表中选择Employee。

以下是Edit视图中的默认实现。

@model MVCSimpleApp.Models.Employee
@{
   Layout = null;
}

<!DOCTYPE html>
<html>
   <head>
      <meta name = "viewport" content = "width = device-width" />
      <title>Edit</title>
   </head>
	
   <body>
      @using (Html.BeginForm()){
         @Html.AntiForgeryToken()
         <div class = "form-horizontal">
            <h4>Employee</h4>
            <hr />
            @Html.ValidationSummary(
               true, "", new { @class = "text-danger" })
					
            @Html.HiddenFor(model => model.ID)
				
            <div class = "form-group">
               @Html.LabelFor(
                  model => model.Name, htmlAttributes: new{
                     @class = "control-label col-md-2" })
							
               <div class = "col-md-10">
                  @Html.EditorFor(model => model.Name, new{
                     htmlAttributes = new {
                        @class = "form-control" } })
								
                  @Html.ValidationMessageFor(model => model.Name, "", new{
                        @class = "text-danger" })
               </div>
					
            </div>
				
            <div class = "form-group">
               @Html.LabelFor(
                  model => model.JoiningDate, htmlAttributes: new{
                     @class = "control-label col-md-2" })
							
               <div class = "col-md-10">
                  @Html.EditorFor(
                     model => model.JoiningDate, new{
                        htmlAttributes = new{ @class = "form-control" } })
								
                  @Html.ValidationMessageFor(
                     model => model.JoiningDate, "", new{
                        @class = "text-danger" })
               </div>
					
            </div>
				
            <div class = "form-group">
               @Html.LabelFor(
                  model => model.Age, htmlAttributes: new{
                     @class = "control-label col-md-2" })
							
               <div class = "col-md-10">
                  @Html.EditorFor(
                     model => model.Age, new{
                        htmlAttributes = new{ @class = "form-control" } })
								
                  @Html.ValidationMessageFor(
                     model => model.Age, "", new{
                        @class = "text-danger" })
               </div>
					
            </div>
				
            <div class = "form-group">
               <div class = "col-md-offset-2 col-md-10">
                  <input type = "submit" value = "Save" class = "btn btn-default"/>
               </div>
            </div>
				
         </div>
      }
		
      <div>
         @Html.ActionLink("Back to List", "Index")
      </div>
		
   </body>
</html>

正如您所看到的,使用了许多helper方法。“HTML.BeginForm”编写一个起始表单标签。它还确保当用户单击“保存”按钮时,方法将为“Post”。

Html.BeginForm非常有用,因为它允许您更改URL、更改方法等。

在上面的代码中,您将看到另一个HTML helper,即“@HTML.HiddenFor”,它发出隐藏字段。

MVC框架足够智能,可以知道此ID字段在模型类中已提及,因此需要防止对其进行编辑,这就是为什么它被标记为隐藏的原因。

Html.LabelFor HTML Helper在屏幕上创建标签。如果在进行更改时输入错误,Html.ValidationMessageFor helper将显示正确的错误消息。

我们还需要更改POST的Edit操作,因为一旦更新员工,它就会调用此操作。

// POST: Employee/Edit/5
[HttpPost]
public ActionResult Edit(int id, FormCollection collection){
   try{
      var employee = empList.Single(m => m.ID == id);
      if (TryUpdateModel(employee)){
         //To Do:- database code
         return RedirectToAction("Index");
      }
      return View(employee);
   }catch{
      return View();
   }
}

让我们运行此应用程序并请求以下URL https://127.0.0.1:63004/employee。您将收到以下输出。

Localhost Employee

单击任何特定员工的编辑链接,例如单击Allan的编辑链接。您将看到以下视图。

Click Particular Employee

让我们将年龄从23更改为29,然后单击“保存”按钮,然后您将在索引视图上看到更新后的年龄。

Updated Age Index View

ASP.NET MVC - 模型绑定

ASP.NET MVC模型绑定允许您将HTTP请求数据与模型映射。它是使用浏览器在HTTP请求中发送的数据创建.NET对象的过程。对于ASP.Net MVC的新手ASP.NET Web Forms开发人员来说,当它到达控制器的操作方法时,视图中的值如何转换为模型类,大多数人对此感到困惑,因此这种转换是由模型绑定器完成的。

模型绑定是HTTP请求和C#操作方法之间精心设计的桥梁。它使开发人员能够轻松处理表单(视图)上的数据,因为POST和GET会自动转换为您指定的DataModel。ASP.NET MVC使用默认绑定器在后台完成此操作。

让我们来看一个简单的例子,在这个例子中,我们在上一章的项目中添加一个“创建视图”,我们将看到如何将这些值从视图获取到EmployeeController操作方法。

以下是POST的创建操作方法。

// POST: Employee/Create
[HttpPost]
public ActionResult Create(FormCollection collection){
   try{
      // TODO: Add insert logic here
      return RedirectToAction("Index");
   }catch{
      return View();
   }
}

右键单击创建操作方法,然后选择添加视图…

Right-click Create Action

它将显示“添加视图”对话框。

Display Add View Dialog

正如您在上面的屏幕截图中看到的,默认名称已提及。现在从模板下拉列表中选择创建,从模型类下拉列表中选择Employee。

您将在Create.cshtml视图中看到默认代码。

@model MVCSimpleApp.Models.Employee
@{
   Layout = null;
}

<!DOCTYPE html>
<html>
   <head>
      <meta name = "viewport" content = "width = device-width" />
      <title>Create</title>
   </head>
	
   <body>
      @using (Html.BeginForm()){
         @Html.AntiForgeryToken()
         <div class = "form-horizontal">
            <h4>Employee</h4>
            <hr />
            @Html.ValidationSummary(true, "", new { @class = "text-danger" })
				
            <div class = "form-group">
               @Html.LabelFor(model => model.Name, htmlAttributes:
                  new{ @class = "control-label col-md-2" })
						
               <div class = "col-md-10">
                  @Html.EditorFor(model => model.Name, new{ htmlAttributes =
                     new { @class = "form-control" } })
							
                  @Html.ValidationMessageFor(model => model.Name, "",
                     new{ @class = "text-danger" })
               </div>
            </div>
				
            <div class = "form-group">
               @Html.LabelFor(model => model.JoiningDate, htmlAttributes:
                  new{ @class = "control-label col-md-2" })
						
               <div class = "col-md-10">
                  @Html.EditorFor(model => model.JoiningDate, new{ htmlAttributes =
                     new { @class = "form-control" } })
							
                  @Html.ValidationMessageFor(model => model.JoiningDate, "",
                     new { @class = "text-danger" })
               </div>
            </div>
				
            <div class = "form-group">
               @Html.LabelFor(model => model.Age, htmlAttributes:
                  new { @class = "control-label col-md-2" })
						
               <div class = "col-md-10">
                  @Html.EditorFor(model => model.Age, new { htmlAttributes =
                     new { @class = "form-control" } })
							
                  @Html.ValidationMessageFor(model => model.Age, "", new{ @class = "text-danger" })
               </div>
            </div>
				
            <div class = "form-group">
               <div class = "col-md-offset-2 col-md-10">
                  <input type = "submit" value = "Create" class = "btn btn-default"/>
               </div>
            </div>
				
         </div>
      }
		
      <div>
         @Html.ActionLink("Back to List", "Index")
      </div>
		
   </body>
</html>

当用户在“创建视图”中输入值时,它也存在于FormCollection和Request.Form中。我们可以使用这些值中的任何一个来填充视图中的员工信息。

让我们使用以下代码使用FormCollection创建员工。

// POST: Employee/Create
[HttpPost]
public ActionResult Create(FormCollection collection){
   try {
      Employee emp = new Employee();
      emp.Name = collection["Name"];
      DateTime jDate;
      DateTime.TryParse(collection["DOB"], out jDate);
      emp.JoiningDate = jDate;
      string age = collection["Age"];
      emp.Age = Int32.Parse(age);
      empList.Add(emp);
      return RedirectToAction("Index");
   }catch {
      return View();
   }
}

运行此应用程序并请求此URL https://127.0.0.1:63004/Employee/。您将收到以下输出。

Localhost Employee Output

点击页面顶部的“新建”链接,将跳转到以下视图。

Create New Link

让我们输入要添加的另一个员工的数据。

Another Employee Data

点击创建按钮,您将看到新员工已添加到您的列表中。

New Employee Added

在上面的示例中,我们获取HTML视图中所有提交的值,然后将这些值映射到Employee属性并逐个赋值。

在这种情况下,我们还将在提交的值与模型属性的格式不同的地方进行类型转换。

这也被称为手动绑定,这种实现方式对于简单的小数据模型来说可能还不错。但是,如果您有庞大的数据模型并且需要大量的类型转换,那么我们可以利用ASP.NET MVC模型绑定的强大功能和易用性。

让我们看看我们为模型绑定做的同一个例子。

我们需要更改Create方法的参数,使其接受Employee模型对象而不是FormCollection,如下面的代码所示。

// POST: Employee/Create
[HttpPost]
public ActionResult Create(Employee emp){
   try{
      empList.Add(emp);
      return RedirectToAction("Index");
   }catch{
      return View();
   }
}

现在,模型绑定的魔力取决于提供值的HTML变量的id。

对于我们的Employee模型,HTML输入字段的id应该与Employee模型的属性名称相同,您可以看到Visual Studio在创建视图时使用的是相同的模型属性名称。

@Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })

映射默认情况下将基于属性名称。在这里,我们会发现HTML辅助方法非常有用,因为这些辅助方法将生成HTML,这些HTML将具有模型绑定正常工作的正确名称。

运行此应用程序并请求URL https://127.0.0.1:63004/Employee/。您将看到以下输出。

Request for URL

点击页面顶部的“新建”链接,将跳转到以下视图。

Click Create New Link

让我们输入要添加的另一个员工的数据。

Enter Data Another Employee

现在点击创建按钮,您将看到新员工已使用ASP.Net MVC模型绑定添加到您的列表中。

MVC Model Binding

ASP.NET MVC - 数据库

在本教程中创建的所有ASP.NET MVC应用程序中,我们都将硬编码数据从控制器传递到视图模板。但是,为了构建一个真实的Web应用程序,您可能需要使用一个真实的数据库。在本章中,我们将了解如何使用数据库引擎来存储和检索应用程序所需的数据。

为了存储和检索数据,我们将使用一种名为实体框架的.NET Framework数据访问技术来定义和使用模型。

实体框架 (EF) 支持代码优先技术,允许您通过编写简单的类来创建模型对象,然后数据库将根据您的类动态创建,这使得开发工作流程非常简洁和快速。

让我们看一个简单的例子,在这个例子中,我们将向我们的例子中添加对实体框架的支持。

步骤1 - 要安装实体框架,请右键单击您的项目,然后选择NuGet包管理器→管理解决方案的NuGet包…

Install Entity Framework

它将打开NuGet包管理器。在搜索框中搜索实体框架。

Search Entity Framework

选择实体框架并点击“安装”按钮。它将打开预览对话框。

Select Entity Framework

点击确定继续。

License Acceptance

点击“我接受”按钮开始安装。

I Accept Button

安装实体框架后,您将在输出窗口中看到上面的屏幕截图中所示的消息。

添加DBContext

我们需要向Employee模型添加另一个类,该类将与实体框架通信,以使用以下代码检索和保存数据。

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;

using System.Web;

namespace MVCSimpleApp.Models{
   public class Employee{
      public int ID { get; set; }
      public string Name { get; set; }
      public DateTime JoiningDate { get; set; }
      public int Age { get; set; }
   }
	
   public class EmpDBContext : DbContext{
      public EmpDBContext()
      { }
      public DbSet<Employee> Employees { get; set; }
   }
}

如上所示,EmpDBContext 派生自一个名为DbContext 的EF类。在这个类中,我们有一个名为DbSet的属性,它基本上代表您要查询和保存的实体。

连接字符串

我们需要在Web.config文件的<configuration>标签下为我们的数据库指定连接字符串。

<connectionStrings>
   <add name = "EmpDBContext" connectionString = "Data
   Source = (LocalDb)\v14.0;AttachDbFilename = |DataDirectory|\EmpDB.mdf;Initial
   Catalog = EmployeeDB;Integrated Security = SSPI;"
   providerName = "System.Data.SqlClient"/>
</connectionStrings>

您实际上不需要添加EmpDBContext连接字符串。如果您没有指定连接字符串,实体框架将在用户的目录中创建一个localDB数据库,其名称为DbContext类的完全限定名。为了简化演示,我们不会添加连接字符串。

现在我们需要更新EmployeeController.cs文件,以便我们可以从数据库中保存和检索数据,而不是使用硬编码数据。

首先,我们添加一个私有的EmpDBContext类对象,然后更新Index、Create和Edit操作方法,如下面的代码所示。

using MVCSimpleApp.Models;
using System.Linq;
using System.Web.Mvc;

namespace MVCSimpleApp.Controllers {
   public class EmployeeController : Controller{
      private EmpDBContext db = new EmpDBContext();
      // GET: Employee
		
      public ActionResult Index(){
         var employees = from e in db.Employees
         orderby e.ID
         select e;
         return View(employees);
      }
		
      // GET: Employee/Create
      public ActionResult Create(){
         return View();
      }
		
      // POST: Employee/Create
      [HttpPost]
      public ActionResult Create(Employee emp){
         try{
            db.Employees.Add(emp);
            db.SaveChanges();
            return RedirectToAction("Index");
         }catch{
            return View();
         }
      }
		
      // GET: Employee/Edit/5
      public ActionResult Edit(int id){
         var employee = db.Employees.Single(m => m.ID == id);
         return View(employee);
      }
		
      // POST: Employee/Edit/5
      [HttpPost]
      public ActionResult Edit(int id, FormCollection collection){
         try{
            var employee = db.Employees.Single(m => m.ID == id);
            if (TryUpdateModel(employee)){
               //To Do:- database code
               db.SaveChanges();
               return RedirectToAction("Index");
            }
            return View(employee);
         }catch{
            return View();
         }
      }
   }
}

然后,我们使用以下URLhttps://127.0.0.1:63004/Employee运行此应用程序。您将看到以下输出。

Name JoiningDate Age

您可以看到视图上没有数据,这是因为我们还没有在Visual Studio创建的数据库中添加任何记录。

让我们转到SQL Server对象资源管理器,您将看到数据库的名称与我们在DBContext类中使用的名称相同。

DBContext Class

让我们展开此数据库,您将看到它有一个表,其中包含Employee模型类中的所有字段。

Employee Model Class

要查看此表中的数据,请右键单击Employees表并选择查看数据。

Employee Table View Data

您将看到目前我们没有任何记录。

No Records Moment

让我们直接在数据库中添加一些记录,如下面的屏幕截图所示。

Add Records in Database

刷新浏览器,您将看到数据现在已从数据库更新到视图。

Updated View

让我们通过单击“新建”链接从浏览器添加一条记录。它将显示创建视图。

Create View

让我们在以下字段中添加一些数据。

Add Some Data

点击创建按钮,它将更新索引视图并将此新记录添加到数据库。

New Record Database

现在让我们转到SQL Server对象资源管理器并刷新数据库。右键单击Employees表并选择查看数据菜单选项。您将看到该记录已添加到数据库中。

Record Added in Database

ASP.NET MVC - 验证

验证是ASP.NET MVC应用程序中的一个重要方面。它用于检查用户输入是否有效。ASP.NET MVC提供了一套易于使用的验证方法,同时也是检查错误并在必要时向用户显示消息的强大方法。

DRY

DRY代表不要重复自己,是ASP.NET MVC的核心设计原则之一。从开发的角度来看,建议只在一个地方指定功能或行为,然后在整个应用程序中从该地方使用它。

这减少了您需要编写的代码量,并使您编写的代码更不容易出错,也更容易维护。

向模型添加验证

让我们看一个在我们上一章项目中验证的简单示例。在这个示例中,我们将数据注释添加到我们的模型类中,该类提供了一些内置的验证属性集,可以直接应用于应用程序中的任何模型类或属性,例如Required、StringLength、RegularExpressionRange验证属性。

它还包含像DataType这样的格式化属性,这些属性有助于格式化并且不提供任何验证。验证属性指定要对应用它们的模型属性强制执行的行为。

Required和MinimumLength属性指示属性必须具有值;但没有任何东西可以阻止用户输入空格来满足此验证。RegularExpression属性用于限制可以输入的字符。

让我们通过添加不同的注释属性来更新Employee类,如下面的代码所示。

using System;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;

namespace MVCSimpleApp.Models {
   public class Employee{
      public int ID { get; set; }
      [StringLength(60, MinimumLength = 3)]
		
      public string Name { get; set; }
      [Display(Name = "Joining Date")]
      [DataType(DataType.Date)]
      [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}",
		
      ApplyFormatInEditMode = true)]
      public DateTime JoiningDate { get; set; }
      [Range(22, 60)]
      public int Age { get; set; }
   }
}

现在我们还需要设置数据库的限制。但是,SQL Server对象资源管理器中的数据库显示name属性设置为NVARCHAR(MAX),如下面的屏幕截图所示。

NVARCHAR (MAX)

为了在数据库上设置此限制,我们将使用迁移来更新模式。

从工具→NuGet包管理器→包管理器控制台打开包管理器控制台窗口。

Package Manager Console

包管理器控制台窗口中逐一输入以下命令。

Enable-Migrations
add-migration DataAnnotations
update-database

以下是执行这些命令后在包管理器控制台窗口中的日志。

Package Manager Console Window

Visual Studio还将打开派生自DbMIgration类的类,您可以在其中看到在Up方法中更新模式约束的代码。

namespace MVCSimpleApp.Migrations {
   using System;
   using System.Data.Entity.Migrations;
	
   public partial class DataAnnotations : DbMigration{
      public override void Up(){
         AlterColumn("dbo.Employees", "Name", c => c.String(maxLength: 60));
      }
		
      public override void Down(){
         AlterColumn("dbo.Employees", "Name", c => c.String());
      }
   }
}

Name字段的最大长度为60,这是数据库中的新长度限制,如下面的快照所示。

New Length Limits

运行此应用程序,并通过指定以下URLhttps://127.0.0.1:63004/Employees/Create转到创建视图。

Localhost Employees Create

让我们在这些字段中输入一些无效数据,然后单击创建按钮,如下面的屏幕截图所示。

Enter Invalid Data

您将看到jQuery客户端验证检测到错误,并且它还会显示错误消息。

ASP.NET MVC - 安全性

在本章中,我们将讨论如何在应用程序中实现安全功能。我们还将了解ASP.NET包含的新的成员资格功能,以及可从ASP.NET MVC中使用的功能。在最新版本的ASP.NET中,我们可以使用以下方法管理用户身份:-

  • SQL数据库
  • 本地Windows活动目录

在本章中,我们还将了解ASP.NET的一部分的新身份组件,并了解如何为我们的用户和角色自定义成员资格。

身份验证

用户的身份验证意味着验证用户的身份。这非常重要。出于显而易见的原因,您可能需要仅向已认证的用户展示您的应用程序。

让我们创建一个新的ASP.Net MVC应用程序。

New MVC Application

点击确定继续。

当您启动一个新的ASP.NET应用程序时,该过程中的一个步骤是为应用程序需求配置身份验证服务。

选择MVC模板,您将看到“更改身份验证”按钮现在已启用。

Authentication Button Enabled

这是通过“新建项目”对话框中出现的“更改身份验证”按钮完成的。默认身份验证是“单个用户帐户”。

身份验证选项

单击“更改”按钮时,您将看到一个对话框,其中包含四个选项,如下所示。

无身份验证

第一个选项是“无身份验证”,当您想要构建一个不关心访问者是谁的网站时,可以使用此选项。

No Authentication

它对任何人都开放,每个人都连接到每一个页面。您以后可以随时更改它,但“无身份验证”选项意味着不会有任何功能来识别访问网站的用户。

单个用户帐户

第二个选项是“单个用户帐户”,这是传统的基于表单的身份验证,用户可以访问网站。他们可以注册,创建登录,默认情况下,他们的用户名使用一些新的ASP.NET身份功能存储在SQL Server数据库中,我们稍后将介绍。

Individual User Accounts

密码也存储在数据库中,但在存储之前先进行哈希处理。由于密码已进行哈希处理,因此您无需担心数据库中存在纯文本密码。

此选项通常用于您想要建立用户身份的互联网站点。除了允许用户使用密码创建本地登录名外,您还可以启用来自Microsoft、Google、Facebook和Twitter等第三方登录名。

这允许用户使用他们的Live帐户或Twitter帐户登录您的站点,他们可以选择一个本地用户名,但您无需存储任何密码。

本模块我们将重点讲解这个选项:单个用户帐户选项。

工作和学校帐户

第三个选项是使用组织帐户,这通常用于企业应用程序,其中您将使用活动目录联合服务。

Work School Accounts

您可以设置 Office 365 或使用 Azure Active Directory 服务,并拥有用于内部应用程序和云应用程序的单点登录功能。

您还需要提供应用程序 ID,因此如果基于 Azure,则您的应用程序需要在 Windows Azure 管理门户中注册,并且应用程序 ID 将在所有可能注册的应用程序中唯一标识此应用程序。

Windows 身份验证

第四个选项是 Windows 身份验证,它非常适用于内联网应用程序。

Windows Authentication

用户登录到 Windows 桌面,并可以使用浏览器启动位于同一防火墙内的应用程序。ASP.NET 可以自动获取用户的身份,即活动目录已建立的身份。此选项不允许任何匿名访问站点,但这又是一个可以更改的配置设置。

让我们来看看基于表单的身份验证,也就是所谓的单个用户帐户。此应用程序将用户名和密码(旧密码)存储在本地 SQL Server 数据库中,创建此项目时,Visual Studio 还将添加 NuGet 包。

Forms-based Authentication

现在运行此应用程序,当您第一次访问此应用程序时,您将是匿名用户。

Anonymous User

您还没有可以登录的帐户,因此您需要在此站点上注册。

单击“注册”链接,您将看到以下视图。

Click Register Link

输入您的电子邮件 ID 和密码。

Enter EmailId Password

单击“注册”。现在,应用程序将识别您。

Click Register

它将能够显示您的姓名。在下面的屏幕截图中,您可以看到显示了“您好,[email protected]!”。您可以单击它,这是一个链接到可以更改密码的页面。

Display Your Name

您也可以注销、关闭、重启,一周后再回来,您应该能够使用之前使用的凭据登录。现在单击“注销”按钮,它将显示以下页面。

Click Logoff Button

再次单击“登录”链接,您将转到以下页面。

Click Login Link

您可以使用相同的凭据再次登录。

幕后做了很多工作才能达到这一点。但是,我们要做的是检查每个功能,看看这个 UI 是如何构建的。是什么管理注销和登录过程?此信息存储在数据库中的哪个位置?

让我们从几个简单的基础开始。首先,我们将看到如何显示此用户名。在解决方案资源管理器中打开 View/Shared 文件夹中的 _Layout.cshtml。

<!DOCTYPE html>
<html>
   <head>
      <meta charset = "utf-8" />
      <meta name = "viewport" content = "width = device-width, initial-scale = 1.0">
      <title>@ViewBag.Title - My ASP.NET Application</title>
      @Styles.Render("~/Content/css")
      @Scripts.Render("~/bundles/modernizr")
   </head>
	
   <body>
      <div class = "navbar navbar-inverse navbar-fixed-top">
         <div class = "container">
			
            <div class = "navbar-header">
               <button type = "button" class = "navbar-toggle" datatoggle = "collapse"
                  data-target = ".navbar-collapse">
                     <span class = "icon-bar"></span>
                     <span class = "icon-bar"></span>
                     <span class = "icon-bar"></span>
               </button>
					
               @Html.ActionLink("Application name", "Index", "Home", new
               { area = "" }, new { @class = "navbar-brand" })
            </div>
				
            <div class = "navbar-collapse collapse">
               <ul class = "nav navbar-nav">
                  <li>@Html.ActionLink("Home", "Index", "Home")</li>
                  <li>@Html.ActionLink("About", "About", "Home")</li>
                  <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
               </ul>
					
               @Html.Partial("_LoginPartial")
            </div>
				
         </div>
			
      </div>
      <div class = "container body-content">
         @RenderBody()
         <hr />
         <footer>
            <p>© @DateTime.Now.Year - My ASP.NET Application</p>
         </footer>
      </div>
		
      @Scripts.Render("~/bundles/jquery")
      @Scripts.Render("~/bundles/bootstrap")
      @RenderSection("scripts", required: false)
		
   </body>
</html>

有一个公共导航栏、应用程序名称、菜单,还有一个名为 _loginpartial 的正在呈现的部分视图。这实际上是显示用户名或注册和登录名称的视图。因此 _loginpartial.cshtml 也在共享文件夹中。

@using Microsoft.AspNet.Identity
@if (Request.IsAuthenticated) {
   using (Html.BeginForm("LogOff", "Account", FormMethod.Post,
      new { id = "logoutForm", @class = "navbar-right" })){
         @Html.AntiForgeryToken()
         <ul class = "nav navbar-nav navbar-right">
            <li>
               @Html.ActionLink("Hello " + User.Identity.GetUserName() + "!",
               "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage" })
            </li>
				
            <li>
               <a href = "javascript:document.getElementById('logoutForm').submit()">Logoff</a>
            </li>
				
         </ul>
      }
}else{
   <ul class = "nav navbar-nav navbar-right">
      <li>@Html.ActionLink("Register", "Register", "Account", routeValues:
         null, htmlAttributes: new { id = "registerLink" })</li>
			
      <li>@Html.ActionLink("Log in", "Login", "Account", routeValues: null,
         htmlAttributes: new { id = "loginLink" })</li>
   </ul>
}

如上所示,存在 if/else 语句。如果我们不知道用户是谁,因为请求未经身份验证,则此视图将显示注册和登录链接。用户可以单击链接登录或注册。所有这一切都是由帐户控制器完成的。

目前,我们想知道如何获取用户名,它位于 Request.IsAuthenticated 内部。您可以看到对 User.Identity.GetUserName 的调用。这将检索用户名,在本例中为“[email protected]

授权

假设我们有一些信息需要保护,防止未经身份验证的用户访问。因此,让我们创建一个新的控制器来显示这些信息,但仅当用户登录时才显示。

右键单击控制器文件夹,然后选择“添加”→“控制器”。

User Logged in

选择 MVC 5 控制器 - 空控制器,然后单击“添加”。

输入名称 SecretController 并单击“添加”按钮。

SecretController

它内部将有两个操作,如下面的代码所示。

using System.Web.Mvc;

namespace MVCSecurityDemo.Controllers{
   public class SecretController : Controller{
      // GET: Secret
      public ContentResult Secret(){
         return Content("Secret informations here");
      }
		
      public ContentResult PublicInfo(){
         return Content("Public informations here");
      }
   }
}

运行此应用程序时,您可以访问此信息,无需任何身份验证,如下面的屏幕截图所示。

Secret Information Here

因此,只有经过身份验证的用户才能访问 Secret 操作方法,而 PublicInfo 可以被任何人无身份验证地使用。

为了保护此特定操作并阻止未经身份验证的用户到达此处,您可以使用 Authorize 属性。没有其他参数的 Authorize 属性将确保已知用户的身份,并且他们不是匿名用户。

// GET: Secret
[Authorize]
public ContentResult Secret(){
   return Content("Secret informations here");
}

现在再次运行此应用程序并指定相同的 URL **https://127.0.0.1:54232/Secret/Secret**。MVC 应用程序将检测到您无权访问应用程序的该特定区域,它会自动将您重定向到登录页面,在该页面上,它将为您提供登录并尝试返回您被拒绝访问的应用程序区域的机会。

Redirect Automatically Login Page

您可以看到它在返回 URL 中指定,这实际上告诉此页面,如果用户成功登录,则将其重定向回 /secret/secret。

输入您的凭据并单击“登录”按钮。您将看到它直接转到该页面。

Secret Information Here

如果您返回主页并注销,则无法访问 secret 页面。系统将再次要求您登录,但如果您转到 /Secret/PublicInfo,即使您未经身份验证,您也可以看到该页面。

Public Information Here

因此,当您不想在控制器内的每个操作上都放置授权时,在控制器中几乎所有内容都需要授权。在这种情况下,您可以始终将此过滤器应用于控制器本身,现在此控制器内的每个操作都需要用户进行身份验证。

using System.Web.Mvc;

namespace MVCSecurityDemo.Controllers{
   [Authorize]
   public class SecretController : Controller{
      // GET: Secret
      public ContentResult Secret(){
         return Content("Secret informations here");
      }
		
      public ContentResult PublicInfo(){
         return Content("Public informations here");
      }
   }
}

但是,如果您确实希望任何操作保持开放,您可以使用另一个属性覆盖此授权规则,即 AllowAnonymous。

using System.Web.Mvc;

namespace MVCSecurityDemo.Controllers{
   [Authorize]
   public class SecretController : Controller{
      // GET: Secret
      public ContentResult Secret(){
         return Content("Secret informations here");
      }
		
      [AllowAnonymous]
      public ContentResult PublicInfo(){
         return Content("Public informations here");
      }
   }
}

运行此应用程序,您可以访问 /Secret/PublicInfo 而无需登录,但其他操作需要身份验证。

Public Information Here

它只允许匿名用户进入此一项操作。

使用 Authorize 属性,您还可以指定一些参数,例如允许某些特定用户进入此操作。

using System.Web.Mvc;

namespace MVCSecurityDemo.Controllers{
   [Authorize(Users = "[email protected]")]
   public class SecretController : Controller{
      // GET: Secret
      public ContentResult Secret(){
         return Content("Secret informations here");
      }
		
      [AllowAnonymous]
      public ContentResult PublicInfo(){
         return Content("Public informations here");
      }
   }
}

运行此应用程序并转到 /secret/secret 时,它将要求您登录,因为它不是此控制器的正确用户。

Go to Secret

ASP.NET MVC - 缓存

在本节中,我们将重点关注 ASP.NET 中最常见的技术之一,例如缓存,以提高应用程序的性能。缓存意味着将经常使用的内容存储在内存中,以提供更好的性能。我们将了解如何通过利用输出缓存来显著提高 ASP.NET MVC 应用程序的性能。

在 ASP.NET MVC 中,有一个 OutputCache 筛选器属性可以应用,这与 Web 窗体中的输出缓存概念相同。输出缓存使您可以缓存控制器操作返回的内容。

输出缓存基本上允许您将特定控制器的输出存储在内存中。因此,将来对该控制器中相同操作的任何请求都将从缓存结果返回。这样,每次调用相同的控制器操作时,就不需要重新生成相同的内容。

为什么需要缓存?

在许多不同的场景中,我们需要缓存来提高应用程序的性能。例如,您有一个 ASP.NET MVC 应用程序,它显示员工列表。现在,每次用户调用控制器操作时,这些记录都通过执行数据库查询从数据库中检索,它返回 Index 视图。

因此,您可以利用输出缓存来避免每次用户调用相同的控制器操作时都执行数据库查询。在这种情况下,视图将从缓存中检索,而不是从控制器操作重新生成。

缓存使您可以避免在服务器上执行冗余工作。

让我们来看一个项目中缓存的简单示例。

[OutputCache(Duration = 60)]
public ActionResult Index(){
   var employees = from e in db.Employees
   orderby e.ID
   select e;
   return View(employees);
}

如您所见,我们在 EmployeeController 的 index 操作中添加了“OutputCache”属性。现在,为了理解这个概念,让我们在调试模式下运行此应用程序,并在 Index 操作方法中插入一个断点。

OutputCache

指定以下 URL **https://127.0.0.1:63004/employee**,然后按“Enter”。您将看到断点已命中 Index 操作方法。

Breakpoint is Hit

按“F5”按钮继续,您将在视图中看到从数据库检索到的员工列表。

List of Employees Retrieved

在 60 秒内再次刷新浏览器,您会发现这次断点没有命中。这是因为我们使用了持续时间为 60 秒的输出缓存。因此,它将在 60 秒内缓存此结果,当您刷新浏览器时,它将从缓存中获取结果,并且不会从数据库服务器加载内容。

除了 duration 参数外,还可以使用输出缓存的其他设置选项。这些设置不仅适用于 MVC 框架,而且继承自 ASP.Net 缓存。

更改输出缓存

在某些情况下,您可能需要不同的缓存版本,例如,当您创建详细信息页面时,然后当您单击详细信息链接时,您将获得所选员工的详细信息。

但首先我们需要创建详细信息视图。为此,右键单击 EmployeeController 的 Details 操作方法,然后选择“添加视图…”。

Create Detail View

您会看到默认情况下选择了 Details 名称。现在从“模板”下拉列表中选择 Details,从“模型类”下拉列表中选择 Employee。

Template Dropdown

单击“添加”继续,您将看到 Details.cshtml。

@model MVCSimpleApp.Models.Employee
@{
   Layout = null;
}

<!DOCTYPE html>
<html>
   <head>
      <meta name = "viewport" content = "width = device-width" />
      <title>Details</title>
   </head>
	
   <body>
      <div>
         <h4>Employee</h4>
         <hr />
         <dl class = "dl-horizontal">
            <dt>
               @Html.DisplayNameFor(model => model.Name)
            </dt>
				
            <dd>
               @Html.DisplayFor(model => model.Name)
            </dd>
				
            <dt>
               @Html.DisplayNameFor(model => model.JoiningDate)
            </dt>
				
            <dd>
               @Html.DisplayFor(model => model.JoiningDate)
            </dd>
				
            <dt>
               @Html.DisplayNameFor(model => model.Age)
            </dt>
				
            <dd>
               @Html.DisplayFor(model => model.Age)
            </dd>
				
         </dl>
      </div>
		
      <p>
         @Html.ActionLink("Edit", "Edit", new { id = Model.ID }) |
         @Html.ActionLink("Back to List", "Index")
      </p>
		
   </body>
</html>

您可以利用 [OutputCache] 属性的 VaryByParam 属性。当表单参数或查询字符串参数变化时,此属性使您可以创建相同内容的不同缓存版本。以下是 Details 操作的实现。

// GET: Employee/Details/5
[OutputCache(Duration = int.MaxValue, VaryByParam = "id")]

public ActionResult Details(int id){
   var employee = db.Employees.SingleOrDefault(e => e.ID == id);
   return View(employee);
}

编译并执行上述代码后,通过指定 URL **https://127.0.0.1:63004/employee**,您将收到以下输出。

Create New

单击任何链接的“详细信息”链接,您将看到该特定员工的详细信息视图。

Particular Employee Details

Details() 操作包含一个值为“Id”的 VaryByParam 属性。当不同的 Id 参数值传递给控制器操作时,将生成 Details 视图的不同缓存版本。

重要的是要理解,使用 VaryByParam 属性会导致更多缓存。将为 Id 参数的每个不同版本创建 Details 视图的不同缓存版本。

缓存配置文件

您可以在 web.config 文件中创建缓存配置文件。这是一种通过修改 [OutputCache] 属性的属性来配置输出缓存属性的替代方法。它提供了一些重要的优势,如下所示。

  • 控制控制器操作在一个中心位置缓存内容的方式。

  • 创建一个缓存配置文件,并将该配置文件应用于多个控制器或控制器操作。

  • 修改 web 配置文件而无需重新编译应用程序。

  • 禁用已部署到生产环境的应用程序的缓存。

让我们来看一个缓存配置文件的简单示例,方法是在 web.config 文件中创建缓存配置文件。 部分必须出现在 部分内。

<caching>
   <outputCacheSettings>
      <outputCacheProfiles>
         <add name = "Cache10Min" duration = "600" varyByParam = "none"/>
      </outputCacheProfiles>
   </outputCacheSettings>
</caching>

您可以使用 [OutputCache] 属性将 Cache10Min 配置文件应用于控制器操作,如下所示。

[OutputCache(CacheProfile = "Cache10Min")]

public ActionResult Index(){
   var employees = from e in db.Employees
   orderby e.ID
   select e;
   return View(employees);
}

运行此应用程序并指定以下 URL **https://127.0.0.1:63004/employee**

Invoke Index Action

如果您如上所示调用 Index() 操作,则将在 10 分钟内返回相同的时间。

ASP.NET MVC - Razor

在本节中,我们将研究 ASP.NET MVC 应用程序中的 Razor 视图引擎以及 Razor 存在的一些原因。Razor 是一种标记语法,允许您使用 C# 和 VB.Net 将基于服务器的代码嵌入到网页中。它不是编程语言。它是一种服务器端标记语言。

Razor 与 ASP.NET MVC 无关,因为 Razor 是一个通用的模板引擎。你可以在任何地方使用它来生成输出,例如 HTML。只是 ASP.NET MVC 实现了一个视图引擎,允许我们在 MVC 应用程序中使用 Razor 来生成 HTML。

View Engine

你将拥有一个模板文件,它混合了一些文本和一些代码块。你将该模板与一些数据或特定模型组合起来,模板指定数据应该出现在哪里,然后你执行模板以生成输出。

Razor 与 ASPX

  • Razor 与 ASPX 文件的工作方式非常相似。ASPX 文件是模板,包含文本和一些 C# 代码,用于指定数据应该出现在哪里。我们执行这些文件来生成应用程序的 HTML。

  • ASPX 文件依赖于 ASP.NET 运行时才能解析和执行这些 ASPX 文件。Razor 没有这种依赖性。

  • 与 ASPX 文件不同,Razor 有一些不同的设计目标。

目标

Microsoft 希望 Razor 易于使用和学习,并在 Visual Studio 等工具中工作,以便可以使用 IntelliSense 和调试器,但他们希望 Razor 与特定技术(如 ASP.NET 或 ASP.NET MVC)无关。

如果你熟悉 ASPX 文件的生命周期,那么你可能知道它依赖于 ASP.NET 运行时才能解析和执行这些 ASPX 文件。Microsoft 希望 Razor 更智能,让开发人员的工作更容易。

让我们来看一个 ASPX 文件的示例代码,其中包含一些文本。这是我们的 HTML 标记。它还包含少量 C# 代码。

<% foreach (var item in Model) { %>
   <tr>
      <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>
		
      <td>
         <%: item.Name %>
      </td>
		
      <td>
         <%: String.Format("{0,g}", item.JoiningDate) %>
      </td>
		
   </tr>
<%}%>

但这些 Web 窗体基本上被 Microsoft 重新用于与早期版本的 MVC 协同工作,这意味着 ASPX 文件从未与 MVC 完全匹配。

当你需要从 C# 代码切换回 HTML,以及从 HTML 代码切换回 C# 代码时,语法有点笨拙。IntelliSense 还会提示你执行在 MVC 项目中毫无意义的操作,例如向 ASPX 视图添加输出缓存和用户控件的指令。

现在看看这段代码,它产生相同的输出,不同之处在于它使用了 Razor 语法。

@foreach (var item in Model) {
   <tr>
      <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>
		
      <td>
         @item.Name
      </td>
		
      <td>
         @String.Format("{0,g}", item.JoiningDate)
      </td>
   </tr>
}

使用 Razor 语法,你可以使用“@”符号开始一段 C# 代码,Razor 解析器会自动切换到将此语句(此 foreach 语句)作为一段 C# 代码进行解析。

但是当我们完成 foreach 语句并有我们的左大括号时,我们可以从 C# 代码切换到 HTML,而无需在其中放置显式标记,例如百分号和尖括号。

Razor 解析器足够智能,可以切换 C# 代码和 HTML,并在需要放置右大括号时再次从 HTML 切换回 C# 代码。如果你比较这两个代码块,我认为你会同意 Razor 版本更容易阅读和编写。

使用 Razor 创建视图

让我们创建一个新的 ASP.Net MVC 项目。

Razor MVC Project

在名称字段中输入项目名称,然后单击“确定”。

project_name

为简便起见,选择“空”选项,并在“添加文件夹和核心引用”部分选中 MVC 复选框,然后单击“确定”。它将创建一个具有最少预定义内容的基本 MVC 项目。

Visual Studio 创建项目后,你将在“解决方案资源管理器”窗口中看到许多文件和文件夹。由于我们是从空项目模板创建 ASP.Net MVC 项目,因此目前应用程序没有任何内容可以运行。由于我们从空应用程序开始,甚至没有一个控制器,让我们添加一个 HomeController。

要添加控制器,请右键单击解决方案资源管理器中的控制器文件夹,然后选择“添加”→“控制器”。这将显示“添加脚手架”对话框。

Razor Controller Folder

选择**MVC 5 控制器 - 空**选项,然后单击“添加”按钮,然后将显示“添加控制器”对话框。

HomeController

将名称设置为 HomeController,然后单击“添加”按钮。你将在 Controllers 文件夹中看到一个新的 C# 文件“HomeController.cs”,它也将在 Visual Studio 中打开以进行编辑。

Editing in Visual Studio

右键单击 Index 操作,然后选择“添加视图…”。

Index Action Add View

从“模板”下拉列表中选择“空”,然后单击“添加”按钮。Visual Studio 将在**View/Home**文件夹中创建一个 Index.cshtml 文件。

Create Index.cshtml

请注意,Razor 视图具有 cshtml 扩展名。如果你使用 Visual Basic 构建 MVC 应用程序,它将是 VBHTML 扩展名。此文件的顶部是一个代码块,它显式地将此 Layout 属性设置为 null。

运行此应用程序时,你将看到空白网页,因为我们是从空模板创建的视图。

Blank Webpage

让我们添加一些 C# 代码来使事情更有趣。要在 Razor 视图中编写一些 C# 代码,我们要做的第一件事是键入“@”符号,该符号告诉解析器它将执行代码中的某些操作。

让我们创建一个 FOR 循环,在花括号内指定“@i”,这实际上是告诉 Razor 放置 i 的值。

@{
   Layout = null;
} 

<!DOCTYPE html>
<html>
   <head>
      <meta name = "viewport" content = "width = device-width" />
      <title>Index</title>
   </head>
	
   <body>
      <div>
         @for (int index = 0; index < 12; index++){
            <div>@index </div>
         }
      </div>
   </body>
	
</html>

运行此应用程序,你将看到以下输出。

Razor Output

ASP.NET MVC - 数据注解

DataAnnotations 用于配置你的模型类,这将突出显示最常用的配置。DataAnnotations 也被许多 .NET 应用程序(例如 ASP.NET MVC)理解,这允许这些应用程序利用相同的注释进行客户端验证。DataAnnotation 属性覆盖默认的 Code-First 约定。

**System.ComponentModel.DataAnnotations** 包括以下影响列的可空性或大小的属性。

  • Key
  • Timestamp
  • ConcurrencyCheck
  • Required
  • MinLength
  • MaxLength
  • StringLength

**System.ComponentModel.DataAnnotations.Schema** 命名空间包括以下影响数据库模式的属性。

  • Table
  • Column
  • Index
  • ForeignKey
  • NotMapped
  • InverseProperty

Key

Entity Framework 依赖于每个实体都有一个它用于跟踪实体的键值。Code First 依赖的一个约定是它如何暗示每个 Code First 类中的哪个属性是键。

约定是查找名为“Id”的属性或一个组合了类名和“Id”的属性,例如“StudentId”。该属性将映射到数据库中的主键列。Student、Course 和 Enrollment 类遵循此约定。

现在假设 Student 类使用 StdntID 而不是 ID。当 Code First 未找到与该约定匹配的属性时,由于 Entity Framework 要求你必须拥有一个键属性,因此它将抛出异常。

你可以使用 key 注释来指定哪个属性用作 EntityKey。

让我们看一下包含 StdntID 的 Student 类。它不遵循默认的 Code First 约定,因此为了处理这个问题,添加了 Key 属性,这将使其成为主键。

public class Student{
   [Key]
   public int StdntID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }

   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

运行应用程序并在 SQL Server 资源管理器中查看数据库时,你将看到主键现在是 Students 表中的 StdntID。

Primary Key StdntID

Entity Framework 也支持复合键。复合键是由多个属性组成的主键。例如,你有一个 DrivingLicense 类,其主键是 LicenseNumber 和 IssuingCountry 的组合。

public class DrivingLicense{
   [Key, Column(Order = 1)]
   public int LicenseNumber { get; set; }
	
   [Key, Column(Order = 2)]
   public string IssuingCountry { get; set; }
   public DateTime Issued { get; set; }
   public DateTime Expires { get; set; }
}

当你有复合键时,Entity Framework 要求你定义键属性的顺序。你可以使用 Column 注释来指定顺序。

Composite Keys

Timestamp

Code First 将 Timestamp 属性与 ConcurrencyCheck 属性相同对待,但它还将确保 Code First 生成的数据库字段不可为空。

更常见的是使用 rowversion 或 timestamp 字段进行并发检查。但与其使用 ConcurrencyCheck 注释,不如使用更具体的 TimeStamp 注释,只要属性的类型是字节数组即可。在一个给定的类中,你只能有一个 timestamp 属性。

让我们来看一个简单的例子,通过向 Course 类添加 TimeStamp 属性。

public class Course{
   public int CourseID { get; set; }
   public string Title { get; set; }
   public int Credits { get; set; }
   [Timestamp]
   public byte[] TStamp { get; set; }

   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

如上例所示,Timestamp 属性应用于 Course 类的 Byte[] 属性。因此,Code First 将在 Courses 表中创建一个 timestamp 列 TStamp。

ConcurrencyCheck

ConcurrencyCheck 注释允许你标记一个或多个属性,以便在用户编辑或删除实体时在数据库中用于并发检查。如果你一直在使用 EF 设计器,这与将属性的 ConcurrencyMode 设置为 Fixed 一致。

让我们来看一个简单的例子,看看 ConcurrencyCheck 如何通过将其添加到 Course 类中的 Title 属性来工作。

public class Course{
   public int CourseID { get; set; }
	
   [ConcurrencyCheck]
   public string Title { get; set; }
   public int Credits { get; set; }
	
   [Timestamp, DataType("timestamp")]
   public byte[] TimeStamp { get; set; }

   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

在上例的 Course 类中,ConcurrencyCheck 属性应用于现有的 Title 属性。Code First 将在更新命令中包含 Title 列以检查乐观并发,如下面的代码所示。

exec sp_executesql N'UPDATE [dbo].[Courses]
   SET [Title] = @0
   WHERE (([CourseID] = @1) AND ([Title] = @2))
   ',N'@0 nvarchar(max) ,@1 int,@2 nvarchar(max)
',@0 = N'Maths',@1 = 1,@2 = N'Calculus'
go

Required

Required 注释告诉 EF 特定属性是必需的。让我们看看以下 Student 类,其中 Required id 已添加到 FirstMidName 属性。Required 属性将强制 EF 确保该属性包含数据。

public class Student{
   [Key]
   public int StdntID { get; set; }
	
   [Required]
   public string LastName { get; set; }
	
   [Required]
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }

   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

你可以在上面的 Student 类示例中看到 Required 属性应用于 FirstMidName 和 LastName。因此,Code First 将在 Students 表中创建一个 NOT NULL FirstMidName 和 LastName 列,如下面的屏幕截图所示。

Students Table

MaxLength

MaxLength 属性允许你指定其他属性验证。它可以应用于域类的字符串或数组类型属性。EF Code First 将根据 MaxLength 属性中指定的设置列的大小。

让我们看一下下面的 Course 类,其中 MaxLength(24) 属性应用于 Title 属性。

public class Course{
   public int CourseID { get; set; }
   [ConcurrencyCheck]
   [MaxLength(24)]
	
   public string Title { get; set; }
   public int Credits { get; set; }

   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

运行上述应用程序时,Code-First 将在 Coursed 表中创建一个 nvarchar(24) 列 Title,如下面的屏幕截图所示。

Column Title Coursed Table

现在,当用户设置包含超过 24 个字符的 Title 时,EF 将抛出 EntityValidationError。

MinLength

MinLength 属性允许你指定其他属性验证,就像你对 MaxLength 所做的那样。MinLength 属性也可以与 MaxLength 属性一起使用,如下面的代码所示。

public class Course{
   public int CourseID { get; set; }
   [ConcurrencyCheck]
   [MaxLength(24) , MinLength(5)]
   public string Title { get; set; }
   public int Credits { get; set; }

   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

如果将 Title 属性的值设置为小于 MinLength 属性中指定的长度或大于 MaxLength 属性中指定的长度,EF 将抛出 EntityValidationError。

StringLength

StringLength 属性还允许您指定其他属性验证,例如 MaxLength。不同之处在于 StringLength 属性只能应用于域类的字符串类型属性。

public class Course{
   public int CourseID { get; set; }
   [StringLength (24)]
   public string Title { get; set; }
   public int Credits { get; set; }

   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

Entity Framework 也验证 StringLength 属性的属性值。现在,如果用户设置的标题包含超过 24 个字符,则 EF 将抛出 EntityValidationError。

Table

默认的 Code First 约定会创建与类名相同的表名。如果您让 Code First 创建数据库,您也可以更改它正在创建的表的名称。您可以将 Code First 与现有数据库一起使用。但并非总是类名与数据库中表名匹配的情况。

Table 属性会覆盖此默认约定。对于给定的域类,EF Code First 将使用 Table 属性中指定的名称创建一个表。

让我们来看一个例子,其中类名为 Student,根据约定,Code First 假设这将映射到名为 Students 的表。如果不是这种情况,您可以使用 Table 属性指定表名,如下面的代码所示。

[Table("StudentsInfo")]
public class Student{
   [Key]
   public int StdntID { get; set; }
	
   [Required]
   public string LastName { get; set; }
	
   [Required]
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }

   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

您现在可以看到 Table 属性将表指定为 StudentsInfo。生成表时,您将看到表名 StudentsInfo,如下面的屏幕截图所示。

Table Name StudentsInfo

您不仅可以指定表名,还可以使用 Table 属性指定表的架构,如下面的代码所示。

[Table("StudentsInfo", Schema = "Admin")]

public class Student{
   [Key]
   public int StdntID { get; set; }
	
   [Required]
   public string LastName { get; set; }
	
   [Required]
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }

   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

在上面的示例中,表使用 admin 架构指定。现在 Code First 将在 Admin 架构中创建 StudentsInfo 表,如下面的屏幕截图所示。

StudentsInfo Table in Admin Schema

Column

它也与 Table 属性相同,但 Table 属性会覆盖表行为,而 Column 属性会覆盖列行为。默认的 Code First 约定会创建与属性名相同的列名。

如果您让 Code First 创建数据库,并且您还想更改表中列的名称。Column 属性会覆盖此默认约定。对于给定的属性,EF Code First 将使用 Column 属性中指定的名称创建一个列。

让我们再次来看下面的示例,其中属性名为 FirstMidName,根据约定,Code First 假设这将映射到名为 FirstMidName 的列。如果不是这种情况,您可以使用 Column 属性指定列名,如下面的代码所示。

public class Student{
   public int ID { get; set; }
   public string LastName { get; set; }
	
   [Column("FirstName")]
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }

   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

您现在可以看到 Column 属性将列指定为 FirstName。生成表时,您将看到列名 FirstName,如下面的屏幕截图所示。

Column Name FirstName

Index

Index 属性是在 Entity Framework 6.1 中引入的。**注意** - 如果你使用的是早期版本,本节中的信息不适用。

您可以使用 IndexAttribute 在一个或多个列上创建索引。将属性添加到一个或多个属性将导致 EF 在创建数据库时在数据库中创建相应的索引。

在大多数情况下,索引可以使数据检索更快、更高效。但是,使用索引过度加载表或视图可能会对其他操作(例如插入或更新)的性能产生不利影响。

**索引** 是 Entity Framework 中的新功能,您可以通过减少从数据库查询数据所需的时间来提高 Code First 应用程序的性能。

您可以使用 Index 属性向数据库添加索引,并覆盖默认的 Unique 和 Clustered 设置以获得最适合您方案的索引。默认情况下,索引将命名为 IX_<属性名>

让我们来看下面的代码,其中在 Course 类中为 Credits 添加了 Index 属性。

public class Cours{
   public int CourseID { get; set; }
   public string Title { get; set; }
   [Index]
   public int Credits { get; set; }

   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

您可以看到 Index 属性应用于 Credits 属性。现在生成表时,您将在索引中看到 IX_Credits。

IX_Credits in Indexes

默认情况下,索引是非唯一的,但您可以使用**IsUnique**命名参数指定索引应该是唯一的。以下示例介绍了一个唯一索引,如下面的代码所示。

public class Course{
   public int CourseID { get; set; }
   [Index(IsUnique = true)]
	
   public string Title { get; set; }
   [Index]
	
   public int Credits { get; set; }

   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

ForeignKey

Code First 约定将处理模型中最常见的关联,但在某些情况下需要帮助。例如,更改 Student 类中主键的名称会导致与其与 Enrollment 类之间的关联出现问题。

public class Enrollment{
   public int EnrollmentID { get; set; }
   public int CourseID { get; set; }
   public int StudentID { get; set; }
   public Grade? Grade { get; set; }
   public virtual Course Course { get; set; }
   public virtual Student Student { get; set; }
}

public class Student{
   [Key]
   public int StdntID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }

   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

在生成数据库时,Code First 会看到 Enrollment 类中的 StudentID 属性,并根据约定(它与类名加“ID”匹配)将其识别为对 Student 类的外键。但是 Student 类中没有 StudentID 属性,而是 Student 类中的 StdntID 属性。

解决方法是在 Enrollment 中创建一个导航属性,并使用 ForeignKey DataAnnotation 来帮助 Code First 理解如何在两个类之间建立关联,如下面的代码所示。

public class Enrollment{
   public int EnrollmentID { get; set; }
   public int CourseID { get; set; }
   public int StudentID { get; set; }
   public Grade? Grade { get; set; }
   public virtual Course Course { get; set; }
	
   [ForeignKey("StudentID")]
   public virtual Student Student { get; set; }
}

您现在可以看到 ForeignKey 属性已应用于导航属性。

ForeignKey Attribute

NotMapped

根据 Code First 的默认约定,每个具有受支持数据类型并包含 getter 和 setter 的属性都将在数据库中表示。但这并非应用程序中的始终如此。NotMapped 属性会覆盖此默认约定。例如,您可能在 Student 类中有一个属性,例如 FatherName,但它不需要存储。您可以将 NotMapped 属性应用于 FatherName 属性,您不希望在数据库中为此属性创建列。以下是代码。

public class Student{
   [Key]
   public int StdntID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
   [NotMapped]
   public int FatherName { get; set; }

   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

您可以看到 NotMapped 属性已应用于 FatherName 属性。现在生成表时,您将看到 FatherName 列不会在数据库中创建,但它存在于 Student 类中。

FatherName Column Created

对于没有 getter 或 setter 的属性,Code First 不会创建列。

InverseProperty

当您在类之间有多个关系时,使用 InverseProperty。在 Enrollment 类中,您可能希望跟踪谁注册了 Current Course 和谁注册了 Previous Course。

让我们为 Enrollment 类添加两个导航属性。

public class Enrollment{
   public int EnrollmentID { get; set; }
   public int CourseID { get; set; }
   public int StudentID { get; set; }
   public Grade? Grade { get; set; }
	
   public virtual Course CurrCourse { get; set; }
   public virtual Course PrevCourse { get; set; }
   public virtual Student Student { get; set; }
}

同样,您还需要在这些属性引用的 Course 类中添加内容。Course 类具有返回 Enrollment 类的导航属性,其中包含所有当前和以前的注册信息。

public class Course{
   public int CourseID { get; set; }
   public string Title { get; set; }
   [Index]
	
   public int Credits { get; set; }
   public virtual ICollection<Enrollment> CurrEnrollments { get; set; }
   public virtual ICollection<Enrollment> PrevEnrollments { get; set; }
}

如果外键属性未包含在特定类中,则 Code First 会创建 {类名} _{主键} 外键列,如上面的类所示。生成数据库时,您将看到许多外键,如下面的屏幕截图所示。

Number of ForeignKeys

您可以看到 Code First 无法自行匹配两个类中的属性。Enrollments 的数据库表应该有一个 CurrCourse 的外键和一个 PrevCourse 的外键,但是 Code First 将创建四个外键属性,即:

  • CurrCourse_CourseID
  • PrevCourse_CourseID
  • Course_CourseID
  • Course_CourseID1

要解决这些问题,您可以使用 InverseProperty 注释来指定属性的对齐方式。

public class Course{
   public int CourseID { get; set; }
   public string Title { get; set; }
	
   [Index]
   public int Credits { get; set; }
	
   [InverseProperty("CurrCourse")]
   public virtual ICollection<Enrollment> CurrEnrollments { get; set; }
	
   [InverseProperty("PrevCourse")]
   public virtual ICollection<Enrollment> PrevEnrollments { get; set; }
}

如您现在所见,当在上面的 Course 类中应用 InverseProperty 属性时,通过指定它属于 Enrollment 类的哪个引用属性,Code First 将生成数据库并在 Enrollments 表中仅创建两个外键列,如下面的屏幕截图所示。

ForeignKey Enrollments Table

我们建议您执行上述示例以更好地理解。

ASP.NET MVC - NuGet 包管理

在本章中,我们将讨论 NuGet,它是 .NET 和 Visual Studio 的包管理器。NuGet 可用于查找和安装包,即您希望在项目中使用的软件部件、程序集和内容。

NuGet 不是特定于 ASP.NET MVC 项目的工具。这是一个可以在 Visual Studio 中用于控制台应用程序、WPF 应用程序、Azure 应用程序以及任何类型应用程序的工具。

包管理

NuGet 是一个包管理器,负责下载、安装、更新和配置系统中的软件。软件这个词并不意味着像 Microsoft Word 或 Notepad 2 等最终用户软件,而是指您希望在项目中使用的软件部件、程序集引用。

例如,您可能想要使用的程序集可能是用于模拟对象单元测试的模拟程序集,或者用于数据访问的 NHibernate,以及您在构建应用程序时使用的组件。上述组件是开源软件,但您可以找到一些 NuGet 包是闭源软件。您找到的一些包甚至是由 Microsoft 生产的。

上述所有包(如模拟和 NHibernate 以及 Microsoft 包,例如 Entity Framework 的预览版)的共同点是它们默认情况下不包含在 Visual Studio 中。

没有 NuGet

要安装任何这些组件而无需 NuGet,您需要执行以下步骤。

Components without NuGet

如果您想使用其中一个组件,您需要找到某个特定项目的首页并查找下载链接。然后,下载项目后,它通常以 ZIP 格式存在,因此您需要解压缩它。

如果您没有下载二进制文件,则首先需要构建软件,然后在项目中引用它。此时,许多组件仍然需要一些配置才能启动和运行。

使用 NuGet

NuGet 替换了前面讨论的所有步骤,您只需要说“添加包”。NuGet 知道在哪里下载最新版本,知道如何解压缩它,如何建立对该组件的引用,甚至如何配置它。这可以让您有更多时间来构建软件。

让我们来看一个简单的示例,我们将使用 NuGet 在 ASP.NET MVC 项目中添加对 Entity Framework 的支持。

**步骤 1** - 安装 Entity Framework。右键单击项目并选择 NuGet 包管理器→管理 NuGet 包解决方案…

Select NuGet Package Manager

它将打开 NuGet 包管理器。

**步骤 2** - 在搜索框中搜索 Entity framework。

Search for Entity Framework

**步骤 3** - 选择 Entity Framework 并单击“安装”按钮。它将打开预览对话框。

Preview Dialog

**步骤 4** - 单击“确定”继续。

Preview Dialog Click Ok

**步骤 5** - 单击“我接受”按钮开始安装。

I Accept Installation

安装 Entity Framework 后,您将在输出窗口中看到消息,如上所示。

使用 NuGet 安装包时,您会在托管项目的解决方案文件所在的同一文件夹中看到一个新的 packages 目录。此 packages 目录包含您为该解决方案中的任何项目安装的所有包。

All Packages in Projects

换句话说,NuGet 不会将包下载到中心位置,而是基于每个解决方案进行存储。

ASP.NET MVC - Web API

ASP.NET Web API 是一个框架,它使构建可访问各种客户端(包括浏览器和移动设备)的 HTTP 服务变得容易。ASP.NET Web API 是在 .NET Framework 上构建 RESTful 应用程序的理想平台。

在 Web 上构建 API 时,您可以通过多种方式构建 Web 上的 API。这些包括 HTTP/RPC,这意味着使用 HTTP 在远程过程调用中调用 Web 上的内容,例如方法。

动词本身包含在 API 中,例如获取客户、插入发票、删除客户,并且这些端点中的每一个最终都是一个单独的 URI。

让我们通过创建一个新的 ASP.NET Web 应用程序来看一个 Web API 的简单示例。

步骤 1 - 打开 Visual Studio 并单击文件 → 新建 → 项目菜单选项。

将打开一个新的项目对话框。

Visual Studio Click File

步骤2 - 从左窗格中选择“模板”→“Visual C#”→“Web”。

**步骤 3** - 在中间窗格中,选择 ASP.NET Web 应用程序

在“名称”字段中输入项目名称 WebAPIDemo,然后单击“确定”继续。您将看到以下对话框,该对话框要求您设置 ASP.NET 项目的初始内容。

WebAPIDemo

步骤 4 − 为简化操作,选择“Empty”选项,并在“Add folders and core references for”部分选中“Web API”复选框,然后单击“Ok”。

步骤 5 − 这将创建一个具有最少预定义内容的基本 MVC 项目。

Visual Studio创建项目后,您将在解决方案资源管理器窗口中看到许多文件和文件夹。

步骤 6 − 现在我们需要添加一个模型。在解决方案资源管理器中右键单击“Models”文件夹,然后选择“Add”→“Class”。

Add a Model

现在您将看到“添加新项”对话框。

Add Item Dialog

步骤 7 − 在中间面板中选择“Class”,并在名称字段中输入“Employee.cs”。

步骤 8 − 使用以下代码向 Employee 类添加一些属性。

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

namespace WebAPIDemo.Models {
   public class Employee{
      public int ID { get; set; }
      public string Name { get; set; }
      public DateTime JoiningDate { get; set; }
      public int Age { get; set; }
   }
}

步骤 9 − 让我们添加控制器。在解决方案资源管理器中右键单击“Controllers”文件夹,然后选择“Add”→“Controller”。

它将显示“添加脚手架”对话框。

Select Add Controller

步骤 10 − 选择“Web API 2 Controller - Empty”选项。此模板将为控制器创建一个带有默认操作的 Index 方法。

步骤 11 − 单击“Add”按钮,将出现“添加控制器”对话框。

 Add Button Controller

步骤 12 − 将名称设置为“EmployeesController”,然后单击“Add”按钮。

您将在“Controllers”文件夹中看到一个新的 C# 文件“EmployeeController.cs”,它在 Visual Studio 中打开以进行编辑,其中包含一些默认操作。

using System;
using System.Collections.Generic;
using System.Linq;

using System.Web.Http;
using WebAPIDemo.Models;

namespace WebAPIDemo.Controllers{
   public class EmployeesController : ApiController{
      Employee[] employees = new Employee[]{
         new Employee { ID = 1, Name = "Mark", JoiningDate =
            DateTime.Parse(DateTime.Today.ToString()), Age = 30 },
         new Employee { ID = 2, Name = "Allan", JoiningDate =
            DateTime.Parse(DateTime.Today.ToString()), Age = 35 },
         new Employee { ID = 3, Name = "Johny", JoiningDate =
            DateTime.Parse(DateTime.Today.ToString()), Age = 21 }
      };
		
      public IEnumerable<Employee> GetAllEmployees(){
         return employees;
      }
		
      public IHttpActionResult GetEmployee(int id){
         var employee = employees.FirstOrDefault((p) => p.ID == id);
         if (employee == null){
            return NotFound();
         }
         return Ok(employee);
      }
   }
}

步骤 13 − 运行此应用程序,并在 URL 末尾指定“/api/employees/”,然后按“Enter”。您将看到以下输出。

Specify API Employees

步骤 14 − 让我们指定以下 URL https://127.0.0.1:63457/api/employees/1,您将看到以下输出。

Localhost API Employees

ASP.NET MVC - 脚手架

ASP.NET Scaffolding 是一个用于 ASP.NET Web 应用程序的代码生成框架。Visual Studio 2013 包括为 MVC 和 Web API 项目预安装的代码生成器。当您想要快速添加与数据模型交互的代码时,可以将 scaffolding 添加到您的项目中。使用 scaffolding 可以减少开发项目中标准数据操作所需的时间。

正如您所看到的,我们已经为 Index、Create、Edit 操作创建了视图,并且还需要更新操作方法。但是 ASP.Net MVC 提供了一种更简单的方法来使用 scaffolding 创建所有这些视图和操作方法。

让我们来看一个简单的例子。我们将创建一个包含 Employee 模型类的相同示例,但这次我们将使用 scaffolding。

**步骤1** - 打开Visual Studio,然后单击“文件”→“新建”→“项目”菜单选项。

将打开一个新的项目对话框。

New Dialog

步骤2 - 从左窗格中选择“模板”→“Visual C#”→“Web”。

步骤3 - 在中间窗格中,选择ASP.NET Web应用程序。

步骤 4 − 在“Name”字段中输入项目名称“MVCScaffoldingDemo”,然后单击“Ok”继续。您将看到以下对话框,要求您设置 ASP.NET 项目的初始内容。

MVCScaffoldingDemo

步骤 5 − 为简化操作,选择“Empty”选项,并在“Add folders and core references for”部分选中“MVC”复选框,然后单击“Ok”。

它将创建一个具有最少预定义内容的基本MVC项目。

Visual Studio创建项目后,您将在解决方案资源管理器窗口中看到许多文件和文件夹。

Project Created by Visual Studio

添加 Entity Framework 支持

第一步是安装 Entity Framework。右键单击项目,然后选择“NuGet Package Manager”→“Manage NuGet Packages for Solution…”。

NuGet Package Manager

这将打开“NuGet Package Manager”。在搜索框中搜索 Entity framework。

Entity Framework Search Box

选择实体框架并点击“安装”按钮。它将打开预览对话框。

Open Preview Dialog

点击确定继续。

Click Ok to Continue

单击“I Accept”按钮开始安装。

I Accept Button Installation

安装 Entity Framework 后,您将在输出窗口中看到如下所示的消息。

添加模型

要添加模型,请在解决方案资源管理器中右键单击“Models”文件夹,然后选择“Add”→“Class”。您将看到“添加新项”对话框。

Item Dialog

在中间面板中选择“Class”,并在名称字段中输入“Employee.cs”。

使用以下代码向 Employee 类添加一些属性。

using System;

namespace MVCScaffoldingDemo.Models {
   public class Employee{
      public int ID { get; set; }
      public string Name { get; set; }
      public DateTime JoiningDate { get; set; }
      public int Age { get; set; }
   }
}

添加DBContext

我们有一个 Employee 模型,现在我们需要添加另一个类,它将与 Entity Framework 通信以检索和保存数据。以下是 Employee.cs 文件中的完整代码。

using System;
using System.Data.Entity;

namespace MVCScaffoldingDemo.Models{
   public class Employee{
      public int ID { get; set; }
      public string Name { get; set; }
      public DateTime JoiningDate { get; set; }
      public int Age { get; set; }
   }
	
   public class EmpDBContext : DbContext{
      public DbSet<Employee> Employees { get; set; }
   }
}

如您所见,“EmpDBContext”派生自一个名为“DbContext”的 EF 类。在这个类中,我们有一个名为 DbSet 的属性,它基本上代表您想要查询和保存的实体。

现在让我们构建一个解决方案,您将在项目成功构建时看到消息。

Project Successfully Build

添加 Scaffolding 项

要添加 scaffolding,请在解决方案资源管理器中右键单击“Controllers”文件夹,然后选择“Add”→“New Scaffolded Item”。

New Scaffolded Item

它将显示“添加脚手架”对话框。

Display Scaffold Dialog

在中间面板中选择“MVC 5 Controller with views, using Entity Framework”,然后单击“Add”按钮,这将显示“添加控制器”对话框。

Entity Framework Middle Pane

从“Model class”下拉列表中选择“Employee”,从“Data context class”下拉列表中选择“EmpDBContext”。您还会看到控制器名称已默认选中。

单击“Add”按钮继续,您将在 EmployeesController 中看到以下代码,该代码是由 Visual Studio 使用 Scaffolding 创建的。

using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web.Mvc;
using MVCScaffoldingDemo.Models;

namespace MVCScaffoldingDemo.Controllers {
   public class EmployeesController : Controller{
      private EmpDBContext db = new EmpDBContext();
      
      // GET: Employees
      public ActionResult Index(){
         return View(db.Employees.ToList());
      }
      
      // GET: Employees/Details/5
      public ActionResult Details(int? id){
         if (id == null){
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
         }
			
         Employee employee = db.Employees.Find(id);
			
         if (employee == null){
            return HttpNotFound();
         }
         return View(employee);
      }
      
      // GET: Employees/Create
      public ActionResult Create(){
         return View();
      }
      
      // POST: Employees/Create
      // To protect from overposting attacks, please enable the specific
      properties you want to bind to, for
      // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
      [HttpPost]
      [ValidateAntiForgeryToken]
		
      public ActionResult Create([Bind(Include = "ID,Name,JoiningDate,Age")]
      Employee employee){
         if (ModelState.IsValid){
            db.Employees.Add(employee);
            db.SaveChanges();
            return RedirectToAction("Index");
         }
         return View(employee);
      }
      
      // GET: Employees/Edit/5
      public ActionResult Edit(int? id){
         if (id == null){
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
         }
			
         Employee employee = db.Employees.Find(id);
			
         if (employee == null){
            return HttpNotFound();
         }
         return View(employee);
      }
      
      // POST: Employees/Edit/5
      // To protect from overposting attacks, please enable the specific
      properties you want to bind to, for
      // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
      [HttpPost]
      [ValidateAntiForgeryToken]
      public ActionResult Edit([Bind(Include = "ID,Name,JoiningDate,Age")]Employee employee){
         if (ModelState.IsValid){
            db.Entry(employee).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Index");
         }
         return View(employee);
      }
      
      // GET: Employees/Delete/5
      public ActionResult Delete(int? id){
         if (id == null){
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
         }
			
         Employee employee = db.Employees.Find(id);
			
         if (employee == null){
            return HttpNotFound();
         }
         return View(employee);
      }
      
      // POST: Employees/Delete/5
      [HttpPost, ActionName("Delete")]
      [ValidateAntiForgeryToken]
		
      public ActionResult DeleteConfirmed(int id){
         Employee employee = db.Employees.Find(id);
         db.Employees.Remove(employee);
         db.SaveChanges();
         return RedirectToAction("Index");
      }
      
      protected override void Dispose(bool disposing){
         if (disposing){
            db.Dispose();
         }
			
         base.Dispose(disposing);
      }
   }
}

运行您的应用程序并指定以下 URL https://127.0.0.1:59359/employees。您将看到以下输出。

Run Your Application

您可以看到 View 中没有数据,因为我们尚未向 Visual Studio 创建的数据库中添加任何记录。

让我们通过单击“创建新”链接从浏览器添加一条记录,它将显示“创建”视图。

Clicking Create New

让我们在以下字段中添加一些数据。

Adding Data in Field

单击“创建”按钮,它将更新 Index 视图。

Update Index View

您可以看到新记录也已添加到数据库中。

New Record Added

如您所见,我们已经使用 Scaffolding 实现了相同的示例,这是一种更简单的方法,可以根据您的模型类创建视图和操作方法。

ASP.NET MVC - Bootstrap

在本章中,我们将介绍 Bootstrap,它是一个现在包含在 ASP.NET 和 MVC 中的前端框架。它是一个流行的 Web 应用程序前端工具包,将帮助您使用 HTML、CSS 和 JavaScript 构建用户界面。

它最初是由 Twitter 的 Web 开发人员为个人使用而创建的,但是,它现在是开源的,并且由于其灵活性和易用性而受到设计师和开发人员的欢迎。

您可以使用 Bootstrap 创建一个在大型桌面显示器到小型移动屏幕上的所有设备上看起来都很好的界面。在本章中,我们还将了解 Bootstrap 如何与您的布局视图一起使用以构建应用程序的外观。

Bootstrap 提供了布局、按钮、表单、菜单、窗口小部件、图片轮播、标签、徽章、排版和各种功能所需的所有组件。由于 Bootstrap 全部都是 HTML、CSS 和 JavaScript(所有开放标准),因此您可以将其与任何框架一起使用,包括 ASP.NET MVC。当您启动一个新的 MVC 项目时,Bootstrap 将存在,这意味着您将在项目中找到 Bootstrap.css 和 Bootstrap.js。

让我们创建一个新的 ASP.NET Web 应用程序。

ASP.NET Web Application

输入项目名称,例如“MVCBootstrap”,然后单击“Ok”。您将看到以下对话框。

MVCBootstrap

在此对话框中,如果您选择空模板,您将获得一个空的 Web 应用程序,并且不会存在 Bootstrap。也不会出现任何控制器或任何其他脚本文件。

现在选择 MVC 模板并单击“Ok”。当 Visual Studio 创建此解决方案时,它将下载并安装到项目中的一个包将是 Bootstrap NuGet 包。您可以通过转到 packages.config 来验证,您可以在其中看到 Bootstrap 版本 3 包。

Bootstrap version 3 package

您还可以看到包含不同 css 文件的 Content 文件夹。

Content Folder

运行此应用程序,您将看到以下页面。

Run this application

当此页面出现时,您看到的大部分布局和样式都是 Bootstrap 应用的布局和样式。它包括顶部的导航栏以及链接,以及宣传 ASP.NET 的显示。它还包括所有这些关于入门和获取更多库和 Web 托管的片段。

如果您稍微扩大浏览器,它们实际上将并排显示,这是 Bootstrap 响应式设计功能的一部分。

Bootstrap's responsive design features

如果您查看 Content 文件夹,您将找到 Bootstrap.css 文件。

Bootstrap.css file

NuGet 包还提供了该文件的一个缩小版本,该版本略小一些。在 scripts 下,您将找到 Bootstrap.js,这是 Bootstrap 的某些组件所必需的。

Bootstrap.js

它确实依赖于 jQuery,幸运的是 jQuery 也安装在此项目中,并且有一个 Bootstrap JavaScript 文件的缩小版本。

现在问题是,所有这些都在应用程序中的哪里添加?您可能期望它位于布局模板中,此项目的布局视图位于 View/Shared/_layout.cshtml 下。

Layout View Controls

布局视图控制 UI 的结构。以下是 _layout.cshtml 文件中的完整代码。

<!DOCTYPE html>
<html>
   <head>
      <meta charset = "utf-8" />
      <meta name = "viewport" content = "width = device-width, initial-scale = 1.0">
      <title>@ViewBag.Title - My ASP.NET Application</title>
      @Styles.Render("~/Content/css")
      @Scripts.Render("~/bundles/modernizr")
   </head>
	
   <body>
      <div class = "navbar navbar-inverse navbar-fixed-top">
         <div class = "container">
			
            <div class = "navbar-header">
               <button type = "button" class = "navbar-toggle" datatoggle =
                  "collapse" data-target = ".navbar-collapse">
                  <span class = "icon-bar"></span>
                  <span class = "icon-bar"></span>
                  <span class = "icon-bar"></span>
               </button>
					
               @Html.ActionLink("Application name", "Index", "Home", new
                  { area = "" }, new { @class = "navbar-brand" })
            </div>
				
            <div class = "navbar-collapse collapse">
               <ul class = "nav navbar-nav">
                  <li>@Html.ActionLink("Home", "Index", "Home")</li>
                  <li>@Html.ActionLink("About", "About", "Home")</li>
                  <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
               </ul>
					
               @Html.Partial("_LoginPartial")
            </div>
				
         </div>
			
      </div>
      <div class = "container body-content">
         @RenderBody()
         <hr />
         <footer>
            <p>© @DateTime.Now.Year - My ASP.NET Application</p>
         </footer>
      </div>
		
      @Scripts.Render("~/bundles/jquery")
      @Scripts.Render("~/bundles/bootstrap")
      @RenderSection("scripts", required: false)
		
   </body>
</html>

在上面的代码中,需要注意两点。首先,在 <title> 之后,您将看到以下代码行。

@Styles.Render("~/Content/css")

用于 Content/css 的 Styles.Render 实际上是包含 Bootstrap.css 文件的位置,在底部,您将看到以下代码行。

@Scripts.Render("~/bundles/bootstrap")

它正在呈现 Bootstrap 脚本。因此,为了找出这些捆绑包中究竟包含什么,我们必须进入 BundleConfig 文件,该文件位于 App_Start 文件夹中。

BundleConfig File

在 BundleConfig 中,您可以看到底部 CSS 捆绑包同时包含 Bootstrap.css 和我们自定义的 site.css。

bundles.Add(new StyleBundle("~/Content/css").Include(
   "~/Content/bootstrap.css",
   "~/Content/site.css"));

这是一个我们可以添加自己的样式表以自定义应用程序外观的地方。您还可以看到 Bootstrap 捆绑包出现在 CSS 捆绑包之前,该捆绑包包括 Bootstrap.js 和另一个 JavaScript 文件 respond.js。

bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include(
   "~/Scripts/bootstrap.js",
   "~/Scripts/respond.js"));

让我们注释掉 Bootstrap.css,如下面的代码所示。

bundles.Add(new StyleBundle("~/Content/css").Include(
   //"~/Content/bootstrap.css",
   "~/Content/site.css"));

再次运行此应用程序,让您了解 Bootstrap 的作用,因为现在唯一可用的样式是 site.css 中的样式。

Styles in site.css

如您所见,我们丢失了布局,页面顶部的导航栏。现在一切看起来都很普通和乏味。

现在让我们看看 Bootstrap 的全部内容。Bootstrap 自动执行几件事,当您添加类并具有正确的 HTML 结构时,Bootstrap 可以为您执行几件事。如果您查看 _layout.cshtml 文件,您将看到 navbar 类,如下面的代码所示。

<div class = "navbar navbar-inverse navbar-fixed-top">
   <div class = "container">
	
      <div class = "navbar-header">
         <button type = "button" class = "navbar-toggle" datatoggle =
            "collapse" data-target = ".navbar-collapse">
            <span class = "icon-bar"></span>
            <span class = "icon-bar"></span>
            <span class = "icon-bar"></span>
         </button>
         <a class = "navbar-brand" href = "/">Application name</a>
      </div>
		
      <div class = "navbar-collapse collapse">
         <ul class = "nav navbar-nav">
            <li><a href = "/">Home</a></li>
            <li><a href = "/Home/About">About</a></li>
            <li><a href = "/Home/Contact">Contact</a></li>
         </ul>
			
         <ul class = "nav navbar-nav navbar-right">
            <li><a href = "/Account/Register" id = "registerLink">Register</a></li>
            <li><a href = "/Account/Login" id = "loginLink">Log in</a></li>
         </ul>
			
      </div>
		
   </div>
	
</div>

它是来自 Bootstrap 的 CSS 类,例如 navbar、navbar inverse 和 navbar fixed top。如果您删除其中一些类,例如 navbar inverse、navbar fixed top,并且还取消注释 Bootstrap.css,然后再次运行您的应用程序,您将看到以下输出。

CSS classes

您将看到我们仍然有一个导航栏,但现在它没有使用反向颜色,所以它是白色的。它也不会粘在页面的顶部。当您向下滚动时,导航栏会从顶部滚动,您将再也看不到它。

Navbar

ASP.NET MVC - 单元测试

在计算机编程中,单元测试是一种软件测试方法,通过该方法测试单个源代码单元以确定它们是否适合使用。换句话说,它是一种软件开发过程,其中应用程序中最小的可测试部分(称为单元)被单独且独立地仔细检查其是否正常运行。

在过程式编程中,一个单元可以是整个模块,但更常见的是单个函数或过程。在面向对象编程中,一个单元通常是整个接口,例如一个类,但也可能是一个单独的方法。

单元测试通常是自动化的,但也可以手动进行。

单元测试的目标

单元测试的主要目标是获取应用程序中最小的可测试软件单元,并确定其行为是否完全符合预期。在将各个单元集成到模块中以测试模块间的接口之前,需要分别测试每个单元。

让我们来看一个简单的单元测试示例,在这个示例中,我们将创建一个新的带有单元测试的 ASP.NET MVC 应用程序。

步骤 1 - 打开 Visual Studio 并单击文件 → 新建 → 项目菜单选项。

将打开一个新的项目对话框。

New Project Dialog

步骤 2 − 从左侧面板中,选择模板 > Visual C# > Web。

步骤3 - 在中间窗格中,选择ASP.NET Web应用程序。

步骤 4 − 在“名称”字段中输入项目名称“MVCUnitTestingDemo”,然后单击“确定”继续。您将看到以下对话框,要求您设置 ASP.NET 项目的初始内容。

MVCUnitTestingDemo

步骤 5 − 选择 MVC 作为模板,并且不要忘记选中对话框底部的“添加单元测试”复选框。您也可以更改测试项目名称,但在本例中,我们保留默认名称。

Visual Studio创建项目后,您将在解决方案资源管理器窗口中看到许多文件和文件夹。

步骤 6 − 您可以在解决方案资源管理器中看到两个项目。一个是 ASP.NET Web 项目,另一个是单元测试项目。

Web Project

步骤 7 − 运行此应用程序,您将看到以下输出。

Run Web Project

如上图所示,导航栏上有“主页”、“关于”和“联系”按钮。让我们选择“关于”,您将看到以下视图。

About Select

让我们选择“联系”,以下屏幕将弹出。

Contact Select

现在让我们展开“MVCUnitTestingDemo”项目,您将在“Controllers”文件夹下看到 HomeController.cs 文件。

HomeController.cs file

HomeController 包含三个操作方法,如下面的代码所示。

using System;
using System.Collections.Generic;
using System.Linq;

using System.Web;
using System.Web.Mvc;

namespace MVCUnitTestingDemo.Controllers {
   public class HomeController : Controller{
      public ActionResult Index(){
         return View();
      } 
		
      public ActionResult About(){
         ViewBag.Message = "Your application description page.";
         return View();
      }
		
      public ActionResult Contact(){
         ViewBag.Message = "Your contact page.";
         return View();
      }
   }
}

让我们展开MVCUnitTestingDemo.Tests项目,您将在“Controllers”文件夹下看到 HomeControllerTest.cs 文件。

MVCUnitTestingDemo.Test

在这个 HomeControllerTest 类中,您将看到三个方法,如下面的代码所示。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Web.Mvc;
using Microsoft.VisualStudio.TestTools.UnitTesting;

using MVCUnitTestingDemo;
using MVCUnitTestingDemo.Controllers;

namespace MVCUnitTestingDemo.Tests.Controllers{
   [TestClass]
   public class HomeControllerTest{
	
      [TestMethod]
      public void Index(){
         // Arrange
         HomeController controller = new HomeController();
         // Act
         ViewResult result = controller.Index() as ViewResult;
         // Assert
         Assert.IsNotNull(result);
      }
		
      [TestMethod]
      public void About(){
         // Arrange
         HomeController controller = new HomeController();
         // Act
         ViewResult result = controller.About() as ViewResult;
         // Assert
         Assert.AreEqual("Your application description page.", result.ViewBag.Message);
      }
		
      [TestMethod]
      public void Contact(){
         // Arrange
         HomeController controller = new HomeController();
         // Act
         ViewResult result = controller.Contact() as ViewResult;
         // Assert
         Assert.IsNotNull(result);
      }
   }
}

这三个方法将测试 Index、About 和 Contact 操作方法是否正常工作。要测试这三个操作方法,请转到“测试”菜单。

Test Menu

选择“运行”→“所有测试”来测试这些操作方法。

Action Methods

现在,您将在左侧看到测试资源管理器,其中您可以看到所有测试都已通过。让我们再添加一个操作方法,该方法将列出所有员工。首先,我们需要在 Models 文件夹中添加一个员工类。

以下是 Employee 类的实现。

using System;
using System.Collections.Generic;
using System.Linq;

using System.Web;

namespace MVCUnitTestingDemo.Models{
   public class Employee{
      public int ID { get; set; }
      public string Name { get; set; }
      public DateTime JoiningDate { get; set; }
      public int Age { get; set; }
   }
}

我们需要添加 EmployeeController。右键单击解决方案资源管理器中的控制器文件夹,然后选择“添加”→“控制器”。

它将显示“添加脚手架”对话框。

Add Scaffold

选择 MVC 5 Controller – Empty 选项,然后单击“添加”按钮,将出现“添加控制器”对话框。

将名称设置为 EmployeeController 并单击“添加”按钮。

Add Controller EmployeeController

您将在“Controllers”文件夹中看到一个新的 C# 文件“EmployeeController.cs”,该文件可在 Visual Studio 中打开进行编辑。让我们使用以下代码更新 EmployeeController。

using MVCUnitTestingDemo.Models;
using System;
using System.Collections.Generic;
using System.Linq;

using System.Web;
using System.Web.Mvc;

namespace MVCUnitTestingDemo.Controllers {
   public class EmployeeController : Controller{
      [NonAction]
		
      public List<Employee> GetEmployeeList(){
         return new List<Employee>{
            new Employee{
               ID = 1,
               Name = "Allan",
               JoiningDate = DateTime.Parse(DateTime.Today.ToString()),
               Age = 23
            },
				
            new Employee{
               ID = 2,
               Name = "Carson",
               JoiningDate = DateTime.Parse(DateTime.Today.ToString()),
               Age = 45
            },
				
            new Employee{
               ID = 3,
               Name = "Carson",
               JoiningDate = DateTime.Parse(DateTime.Today.ToString()),
               Age = 37
            },
				
            new Employee{
               ID = 4,
               Name = "Laura",
               JoiningDate = DateTime.Parse(DateTime.Today.ToString()),
               Age = 26
            },
         };
      }
      
      // GET: Employee
      public ActionResult Index(){
         return View();
      }
		
      public ActionResult Employees(){
         var employees = from e in GetEmployeeList()
         orderby e.ID
         select e;
         return View(employees);
      }
   }
}

要为 Employees 操作方法添加视图,请右键单击 Employees 操作并选择“添加视图…”。

Employee Action

您将看到视图的默认名称。从“模板”下拉列表中选择“列表”,从“模型类”下拉列表中选择“Employee”,然后单击“确定”。

现在我们需要添加员工列表链接,让我们打开位于 Views/Shared 文件夹下的 _layout.cshtml 文件,并在“联系”链接下方添加员工列表的链接。

<li>@Html.ActionLink("Employees List", "Employees", "Employee")</li>

以下是 _layout.cshtml 的完整实现。

<!DOCTYPE html>
<html>
   <head>
      <meta charset = "utf-8" />
      <meta name = "viewport" content = "width = device-width, initial-scale = 1.0">
      <title>@ViewBag.Title - My ASP.NET Application</title>
      @Styles.Render("~/Content/css")
      @Scripts.Render("~/bundles/modernizr")
   </head>
	
   <body>
      <div class = "navbar navbar-inverse navbar-fixed-top">
         <div class = "container">
			
            <div class = "navbar-header">
               <button type = "button" class = "navbar-toggle" datatoggle =
                  "collapse" data-target = ".navbar-collapse">
                  <span class = "icon-bar"></span>
                  <span class = "icon-bar"></span>
                  <span class = "icon-bar"></span>
               </button>
					
               @Html.ActionLink("Application name", "Index", "Home", new
                  { area = "" }, new { @class = "navbar-brand" })
            </div>
				
            <div class = "navbar-collapse collapse">
               <ul class = "nav navbar-nav">
                  <li>@Html.ActionLink("Home", "Index", "Home")</li>
                  <li>@Html.ActionLink("About", "About", "Home")</li>
                  <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
                  <li>@Html.ActionLink("Employees List", "Employees", "Employee")</li>
               </ul>
					
               @Html.Partial("_LoginPartial")
            </div>
				
         </div>
			
      </div>
		
      <div class = "container body-content">
         @RenderBody()
         <hr />
         <footer>
            <p>© @DateTime.Now.Year - My ASP.NET Application</p>
         </footer>
      </div>
		
      @Scripts.Render("~/bundles/jquery")
      @Scripts.Render("~/bundles/bootstrap")
      @RenderSection("scripts", required: false)
		
   </body>
</html>

要测试 Employee 控制器中的 Employees 操作方法,我们需要在单元测试项目中添加另一个测试方法。以下是 EmployeeControllerTest 类,我们将在其中测试 Employees 操作方法。

[TestClass]
public class EmployeeControllerTest{
   [TestMethod]
   public void Employees(){
      // Arrange
      EmployeeController controller = new EmployeeController();
		
      // Act
      ViewResult result = controller.Index() as ViewResult;
		
      // Assert
      Assert.IsNotNull(result);
   }
}

从“测试”菜单中选择“运行”→“所有测试”来测试这些操作方法。

Employee Test Method

您可以看到 Employees 测试方法现在也已通过。运行应用程序后,您将看到以下输出。

单击导航栏中的“员工列表”选项,您将看到员工列表。

Employee List

ASP.NET MVC - 部署

在本章中,我们将介绍如何部署 ASP.NET MVC 应用程序。在理解 ASP.NET MVC 应用程序中的不同概念之后,现在是时候了解部署过程了。因此,每当我们构建任何 MVC 应用程序时,我们实际上都会生成一个与其关联的dll文件,其中包含所有应用程序设置和逻辑,这些dll位于项目的 bin 目录中,如下面的屏幕截图所示。

Deployment

发布到 Microsoft Azure

让我们来看一个简单的示例,我们将在此示例中将我们的示例部署到 Microsoft Azure。

步骤 1 − 右键单击解决方案资源管理器中的项目,然后选择“发布”,如下面的屏幕截图所示。

Solution Explorer

步骤 2 − 您将看到“发布 Web”对话框。单击“Microsoft Azure Web 应用”。

Microsoft Azure Web Apps

它将显示“登录”页面。

步骤 3 − 输入 Microsoft Azure 订阅的凭据。

Credentials

成功连接到您的 Azure 帐户后,您将看到以下对话框。

Azure account

步骤 4 − 单击“新建”按钮。

New Button

步骤 5 − 在上面的对话框中输入所需的信息,例如 Web 应用名称(必须是唯一名称)。您还需要输入应用服务计划、资源组,然后选择您的区域。

Desired Information

步骤 6 − 单击“下一步”按钮继续。

Click Next Button

步骤 7 − 单击省略号“…”以选择连接字符串。

Ellipsis Mark

步骤 8 − 选择服务器名称,然后选择 Windows 身份验证选项。也选择数据库名称。现在您将看到系统为您生成的连接字符串。

Generating Connection

步骤 9 − 单击“下一步”继续。

Click Publish Web Next

步骤 10 − 要检查我们将发布到 Azure 的所有文件和 dll,请单击“启动预览”。单击“发布”按钮以发布您的应用程序。

应用程序成功发布到 Azure 后,您将在输出窗口中看到消息。

Publishing Azure

步骤 11 − 现在打开您的浏览器并输入以下 URL “http://mymvcdemoapp.azurewebsites.net/employees”,您将看到员工列表。

Employees List

步骤 12 − 现在,如果您转到您的 Azure 门户并单击“应用服务”,您将看到您的应用程序已部署到 Azure。

App Services

步骤 13 − 单击您的应用的名称,您将看到与该应用程序相关的各种信息,例如 URL、状态、位置等。

Related Information

到目前为止,我们已经了解了如何在创建应用程序后将 Web 应用程序发布到 Azure 应用。您还可以创建将部署到 Azure 的应用程序。

让我们创建一个新的 ASP.NET MVC 应用程序。

ASP.NET MVC application

步骤 1 − 单击“确定”,您将看到以下对话框。

ASP.NET Project

步骤 2 − 选择 MVC 模板,并选中“在云中托管”复选框。单击“确定”。

当出现“配置 Microsoft Azure Web 应用设置”对话框时,请确保您已登录到 Azure。

Configure Microsoft Azure

您可以看到默认名称,但您也可以更改Web 应用名称

步骤 3 − 输入所需的信息,如下面的屏幕截图所示。

Enter Desired Information

步骤 4 − 从“数据库服务器”下拉列表中选择“创建新服务器”,您将看到其他字段。

Create New Server

步骤 5 − 输入数据库服务器、用户名和密码。单击“确定”。

步骤 6 − 项目创建后,运行应用程序,您将看到它正在 localhost 上运行。

Run Application

步骤 7 − 要将这些应用程序部署到 Azure,请右键单击解决方案资源管理器中的项目,然后选择“发布”。

Deploy Application

您将看到以下对话框。

Select Publish Target

步骤 8 − 单击“Microsoft Azure Web 应用”。

Click Microsoft Azure Web Apps

步骤 9 − 从现有 Web 应用中选择您的应用程序名称,然后单击“确定”。

Select Application Name

步骤 10 − 单击“验证连接”按钮以检查 Azure 上的连接。

Validate Connection

步骤 11 − 单击“下一步”继续。

Click on Next

现在您将看到连接字符串已默认生成。

Generated Connection String

步骤 12 − 单击“下一步”继续。

Connection String Next

步骤 13 − 要检查将发布到 Azure 的所有文件和 dll,请单击“启动预览”。

Preview

步骤 14 − 单击“发布”按钮以发布您的应用程序。应用程序成功发布到 Azure 后,您将在输出窗口中看到消息。

Publish Button

您还将看到该应用程序现在正在云端运行。

Cloud

让我们再次转到 Azure 门户。您也可以在这里看到该应用程序。

Azure Portal

ASP.NET MVC - 自托管

在本章中,我们将介绍自托管。自托管为应用程序创建运行时环境,以便在任何环境(例如 MAC 或 Linux 系统)中运行。自托管还意味着它将具有迷你 CLR 版本。

使用文件系统部署

让我们来看一个简单的自托管示例。

步骤 1 − 完成 ASP.NET MVC 应用程序后,如果要使用自托管,请右键单击解决方案资源管理器中的项目。

Use Self-Hosting

您将看到以下对话框。

Self-Hosting Dialog Box

步骤 2 − 单击“自定义”选项,这将显示“新建自定义配置文件”对话框。

New Custom Profile dialog

步骤 3 − 输入配置文件名称,然后单击“确定”。

Enter Profile Name

步骤 4 − 从“发布方法”下拉列表中选择“文件系统”,并指定目标位置。单击“下一步”按钮。

Select File System

步骤 5 − 展开“文件发布选项”。

File Publish Options

步骤 6 − 选中“发布前删除所有现有文件”和“发布期间预编译”复选框,然后单击“下一步”继续。

Delete all Existing Files

步骤 7 − 单击“发布”按钮,它将把文件发布到所需的位置。

Publish Files at Desired Location

您将在系统上的目标位置看到所有文件和文件夹。

Target Location

它将包含在本地主机上部署所需的所有文件。

步骤 8 − 现在打开“启用或关闭 Windows 功能”,然后展开“Internet 信息服务”→“万维网服务”→“应用程序开发功能”。

Open Turn Windows Features

步骤 9 − 选中如上图所示的复选框,然后单击“确定”。

步骤 10 − 让我们打开 IIS 管理器,如下面的屏幕截图所示。

IIS Manager

步骤 11 − 您将在屏幕左侧看到不同的连接,右键单击 MyWebSite。

Different Connections

步骤 12 − 选择“转换为应用程序”选项。

Convert to Application

如您所见,其物理路径与我们在使用文件系统发布时上面提到的相同。

步骤 13 − 单击“确定”继续。

Click OK

现在您可以看到它的图标已更改。

步骤 14 − 打开您的浏览器并指定以下 URL https://127.0.0.1/MyWebSite

Specify URL

您可以看到它正在我们部署期间指定的文件夹中运行。

广告