首页 > 编程语言 >第4章 使用 Razor Pages 创建网站(ASP.NET Core in Action, 2nd Edition)

第4章 使用 Razor Pages 创建网站(ASP.NET Core in Action, 2nd Edition)

时间:2022-12-07 11:44:06浏览次数:40  
标签:Razor ASP Core 应用程序 MVC 处理程序 视图 RazorPages 页面

本章重点

  • RazorPages和模型视图-控制器(MVC)设计模式简介
  • 在ASP.NET Core中使用RazorPages
  • 在RazorPages和MVC控制器之间进行选择
  • 使用Action结果控制应用程序流

在第3章中,您了解了中间件管道,它定义了ASP.NET Core应用程序如何响应请求。在将请求传递到管道中的下一个中间件之前,每个中间件都可以修改或处理传入的请求。

在ASP.NET Core web应用程序中,中间件管道通常包括EndpointMiddleware。这通常是编写大部分应用程序逻辑的地方,调用应用程序中的各种其他类。它也是用户与应用程序交互的主要入口。它通常采用以下三种形式之一:

  • 为用户直接使用而设计的HTML web应用程序——如果应用程序直接由用户使用,就像传统web应用程序一样,那么RazorPages负责生成用户交互的网页。它处理URL请求,接收使用表单发布的数据,并生成用户用于查看和导航应用程序的HTML。
  • 为另一台机器或代码使用而设计的API——web应用程序的另一种主要可能是用作后端服务器进程、移动应用程序或客户端框架的API,用于构建单页应用程序(SPA)。在这种情况下,应用程序以机器可读格式(如JSON或XML)提供数据,而不是以人为中心的HTML输出。
  • 一个HTML web应用程序和一个API——也可以有同时满足这两种需求的应用程序。这可以让您在应用程序中共享逻辑的同时满足更广泛的客户。

在本章中,您将了解ASP.NET Core如何使用RazorPages来处理第一个选项,即创建服务器端呈现的HTML页面。您将首先查看模型-视图-控制器(MVC)设计模式,以了解通过使用它可以获得的好处,并了解为什么它被如此多的web框架采用为构建可维护应用程序的模型。

接下来,您将了解MVC设计模式如何应用于ASP.NET Core。MVC模式是一个广泛的概念,可以应用于各种情况,但ASP.NET Core中的使用主要是作为UI抽象。您将看到RazorPages是如何实现MVC设计模式的,它是如何在ASP.NET Core MVC框架之上构建的,并比较这两种方法。

接下来,您将看到如何将RazorPages添加到现有应用程序中,以及如何创建第一个RazorPage。您将学习如何定义应用程序接收请求时要执行的页面处理程序,以及如何生成可用于创建要返回的HTTP响应的结果。

在本章中,我不会介绍如何创建WebAPI。Web API仍然使用ASP.NET Core MVC框架,但它们的使用方式与RazorPages略有不同。它们不返回直接显示在用户浏览器中的网页,而是返回格式化后的数据以供代码使用。Web API通常用于向移动和Web应用程序或其他服务器应用程序提供数据。但它们仍然遵循相同的通用MVC模式。您将在第9章中了解如何创建Web API。

注:本章是ASP.NET Core中RazorPages和MVC的第一章。正如我已经提到的,这些框架通常负责处理应用程序的所有业务逻辑和UI代码,因此,可能并不奇怪,它们很大而且有些复杂。接下来的五章都讨论了构成MVC和RazorPages框架的MVC模式的不同方面。

在本章中,我将尝试为您准备接下来的每一个主题,但您可能会发现,在这个阶段,有些行为感觉有点像魔术。试着不要太在意所有部件是如何结合在一起的;专注于所处理的具体概念。当我们在本书的其他部分中介绍相关细节时,这一切都将变得清晰。

4.1 RazorPages简介

RazorPages编程模型在ASP.NET Core 2.0中引入,作为构建服务器端呈现的“基于页面”网站的一种方式。它建立在ASP.NET Core基础设施之上,提供了一种简化的体验,在可能的情况下使用约定来减少所需的样板代码和配置的数量。

定义:基于页面的网站是一个用户在多个页面之间浏览、将数据输入表单并生成内容的网站。这与游戏或单页应用程序(SPA)等应用程序形成了鲜明对比,后者在客户端具有很强的交互性。

在第2章中,您已经看到了RazorPage的一个非常基本的示例。在本节中,我们将从稍微复杂一点的RazorPage开始,以更好地理解RazorPage的总体设计。我将展示

  • 典型RazorPage的示例
  • MVC设计模式及其如何应用于RazorPages
  • 如何将RazorPages添加到应用程序

在本节结束时,您应该很好地了解RazorPages背后的总体设计,以及它们与MVC模式的关系。

4.1.1 探索典型的RazorPage

在第二章中,我们看到了一个非常简单的RazorPage。它不包含任何逻辑,只是呈现了关联的Razor视图。例如,如果您正在构建一个内容众多的营销网站,这种模式可能很常见,但更常见的是,RazorPages将包含一些逻辑、从数据库加载数据或使用表单允许用户提交信息。

为了让您更了解典型RazorPages的工作原理,在本节中,我们将简要介绍一个稍微复杂一些的RazorPage。此页面取自待办事项列表应用程序,用于显示给定类别的所有待办事项。现在我们没有关注HTML的生成,所以下面的列表只显示RazorPage的PageModel代码。

清单4.1 用于查看给定类别中所有待办事项的RazorPage

public class CategoryModel : PageModel
{
private readonly ToDoService _service; //ToDoService是使用依赖注入在模型构造函数中提供的 public CategoryModel(ToDoService service) { _service = service; } public ActionResult OnGet(string category) //OnGet处理程序接受一个参数category。 { Items = _service.GetItemsForCategory(category); //处理程序调用ToDoService以检索数据并设置Items属性。 return Page(); //返回一个PageResult,表明应呈现Razor视图 } public List<ToDoListModel> Items { get; set; } //Razor视图在渲染时可以访问Items属性。 }

 

该示例仍然相对简单,但与第2章中的基本示例相比,它展示了多种功能:

  • 页面处理程序OnGet接受方法参数category。RazorPage基础结构使用来自传入请求的值在一个称为模型绑定的过程中自动填充此参数。我在第6章中详细讨论了模型绑定。
  • 处理程序不直接与数据库交互。相反,它使用提供的类别值与ToDoService进行交互,ToDoService通过依赖注入作为构造函数参数注入。
  • 处理程序在方法末尾返回Page(),以指示应呈现关联的Razor视图。在这种情况下,return语句实际上是可选的;按照惯例,如果页面处理程序是一个void方法,Razor视图仍将被呈现,就像您在方法末尾调用了return page()一样。
  • RazorView可以访问CategoryModel实例,因此它可以访问处理程序设置的Items属性。它使用这些项来构建最终发送给用户的HTML。

清单4.1的RazorPage中的交互模式显示了一种常见的模式。页面处理程序是RazorPage的中央控制器。它接收用户的输入(类别方法参数),调用应用程序(ToDoService)的“大脑”,并将数据(通过Items属性)传递给Razor视图,Razor将生成HTML响应。这看起来像模型-视图-控制器(MVC)设计模式。

根据您在软件开发方面的背景,您可能以前遇到过某种形式的MVC模式。在web开发中,MVC是一种常见的模式,用于Django、Rails和Spring MVC等框架中。但由于MVC是一个广泛的概念,您可以在从移动应用程序到富客户端桌面应用程序的所有应用程序中找到MVC。希望这表明了如果正确使用该模式可以带来的好处!在下一节中,我们将了解MVC模式的一般情况,以及ASP.NET Core如何使用它。

4.1.2 MVC设计模式

MVC设计模式是设计具有UI的应用程序的常见模式。最初的MVC模式有许多不同的解释,每一种解释都侧重于模式的稍微不同的方面。例如,最初的MVC设计模式是使用在富客户端图形用户界面(GUI)应用程序而不是web应用程序,因此它使用了与GUI环境相关的术语和范例。不过,从根本上讲,该模式旨在将数据的管理和操作与其可视化表示分开。

在深入研究设计模式本身之前,让我们考虑一个典型的请求。想象一下,应用程序的用户从显示待办事项列表类别的前一部分请求RazorPage。图4.1显示了RazorPage如何处理请求的不同方面,所有这些方面结合起来生成最终响应。

  

 图4.1请求RazorPages应用程序的待办事项列表页面。不同的“组件”处理请求的每个方面。

通常,MVC设计模式由三个“组件”组成:

  • 模型-这是需要显示的数据,即应用程序的全局状态。它可以通过清单4.1中的ToDoService访问。
  • 视图-显示模型提供的数据的模板。
  • 控制器-这将更新模型并向视图提供显示数据。此角色由RazorPages中的页面处理程序承担。这是清单4.1中的OnGet方法。

MVC设计模式中的每一个组件都负责整个系统的一个方面,当它们结合起来时,可以用来生成UI。待办事项列用例将MVC视为使用RazorPages的web应用程序,这时请求也可以理解为在桌面GUI应用程序中单击按钮。

通常,应用程序响应用户交互或请求时的事件顺序如下:

  1. 控制器(RazorPage处理程序)接收请求。
  2. 根据请求,控制器或者使用注入的服务从应用程序模型获取请求的数据,或者更新构成模型的数据。
  3. 控制器选择要显示的视图,并将模型的表示传递给它。
  4. 视图使用模型中包含的数据来生成UI。

当我们以这种格式描述MVC时,控制器(RazorPage处理程序)充当交互的入口点。用户与控制器通信以发起交互。在web应用程序中,这种交互采用HTTP请求的形式,因此当接收到对URL的请求时,控制器会处理它。

根据请求的性质,控制器可以采取各种行动,但关键点是,这些行动是使用应用程序模型进行的。这里的模型包含应用程序的所有业务逻辑,因此它能够提供请求的数据或执行操作。

注:在MVC的描述中,模型被认为是一个复杂的野兽,包含了如何执行动作的所有逻辑,以及任何内部状态。RazorPage PageModel 类不是我们所讨论的模型!不幸的是,与所有软件开发一样,命名同样是个难题。

考虑查看电子商务应用程序的产品页面的请求。控制器将接收请求,并知道如何联系属于应用程序模型的某个产品服务。这可能会从数据库中获取所请求产品的详细信息,并将其返回给控制器。

或者,设想一个控制器接收到向用户的购物车添加产品的请求。控制器将接收请求,并且很可能会调用模型上的方法来请求添加产品。然后,模型将更新用户购物车的内部表示,例如,向保存用户数据的数据库表中添加新行。

提示:您可以将每个RazorPage处理程序视为专注于单个页面的小型控制器。每个web请求都是对生成响应的控制器的一个独立调用。尽管有许多不同的控制器,但处理程序都与同一个应用程序模型交互。

 模型更新后,控制器需要决定生成什么响应。使用MVC设计模式的优点之一是,表示应用程序数据的模型与称为视图的数据的最终表示分离。控制器负责决定响应是否应生成HTML视图,是否应将用户发送到新页面,或者是否应返回错误页面。

模型独立于视图的优点之一是它提高了可测试性。UI代码通常很难测试,因为它依赖于环境,任何编写过模拟用户单击按钮并输入表单的UI测试的人都知道它通常很脆弱。通过保持模型独立于视图,可以确保模型易于测试,而不依赖于UI构造。由于模型通常包含应用程序的业务逻辑,这显然是一件好事!

视图可以使用控制器传递给它的数据来生成适当的HTML响应。视图仅负责生成数据的最终表示;它不涉及任何业务逻辑。

这就是与web应用程序相关的MVC设计模式的全部内容。许多与MVC相关的容易混淆的概念似乎源于对略有不同的框架和应用程序类型的术语使用略有不同。在下一节中,我将展示ASP.NET Core框架如何在RazorPages中使用MVC模式,以及该模式的更多实例。

4.1.3 将MVC设计模式应用于RazorPage

在上一节中,我讨论了MVC模式,因为它通常用于web应用程序;RazorPages使用此模式。但是ASP.NET Core还包括一个名为ASP.NET Core MVC的框架。这个框架(毫不奇怪)非常接近MVC设计模式,使用控制器和Action方法代替RazorPages和页面处理程序。RazorPages直接构建在底层ASP.NET Core MVC框架之上,使用底层MVC框架来实现其行为。

如果您愿意,可以完全避免RazorPages,直接在ASP.NET Core中使用MVC框架。这是早期版本ASP.NET Core和早期版本ASP.NET中的唯一选项。

提示:我在第4.2节中更深入地研究了RazorPages和MVC框架之间的选择。

在本节中,我们将更深入地了解MVC设计模式如何应用于ASP.NET Core中的RazorPages。这也有助于澄清RazorPages的各种功能的作用。

RazorPages使用MVC还是MVVM?
我偶尔看到人们将RazorPages描述为使用模型-视图-视图-模型(MVVM)设计模式,而不是MVC设计模式。就我个人而言,我不同意,但值得注意的是其中的差异。
MVVM是一种UI模式,常用于移动应用程序、桌面应用程序和一些客户端框架。它与MVC的不同之处在于视图和视图模型之间存在双向交互。视图模型告诉视图要显示什么,但视图也可以直接在视图模型上触发更改。它通常用于双向数据绑定,其中视图模型“绑定”到视图。

正如您在前几章中所看到的,ASP.NET Core使用RoutingMiddleware和EndpointMiddleware的组合实现RazorPage端点,如图4.2所示。一旦早期中间件处理了请求(假设没有一个中间件处理过请求并使管道短路),路由中间件将选择应该执行哪个RazorPagehandler,并且端点中间件执行页面处理程序。

 

 图4.2 典型ASP.NET Core应用程序的中间件管道。请求由每个中间件依次处理。如果请求到达路由中间件,中间件将选择一个端点(如RazorPage)来执行。端点中间件执行所选端点。

中间件经常处理一些简单问题或狭义的请求,例如文件请求。对于超出这些功能或具有许多外部依赖性的需求,需要一个更健壮的框架。RazorPages(和/或ASP.NET Core MVC)可以提供此框架,允许与应用程序的核心业务逻辑交互并生成UI。它处理从将请求映射到适当的控制器到生成HTML或API响应的所有事情。

在MVC设计模式的传统描述中,只有一种类型的模型,它包含所有非UI数据和行为。控制器根据需要更新该模型,然后将其传递给视图,视图使用该模型生成UI。

讨论MVC时的一个问题是它使用的模糊和模棱两可的术语,例如“控制器”和“模型”。特别是模型,它是一个过载的术语,通常很难确定它到底指的是什么-它是对象、对象集合还是抽象概念?即使是ASP.NET Core也使用“模型”一词来描述几个相关但不同的组件,您很快就会看到。

将请求定向到RazorPage并构建绑定模型

应用程序收到请求的第一步是将请求路由到适当的RazorPage处理程序。让我们再次考虑类别待办事项列表页面,从列表4.1开始。在此页面上,您将显示具有给定类别标签的项目列表。如果您正在查看类别为“Simple”的项目列表,则会向/categy/Simple路径发出请求。

路由采用请求的标头和路径/categy/Simple,并将其映射到预先注册的模式列表。这些模式每个都匹配到单个RazorPage和页面处理程序的路径。您将在下一章中了解有关路由的更多信息。

提示:我使用术语RazorPage来指Razor视图和包含页面处理程序的PageModel的组合。注意,Page-Model类不是我们在描述MVC模式时所指的“模型”。它完成了其他角色,您将在本节稍后部分看到。

一旦选择了页面处理程序,就会生成绑定模型(如果适用)。该模型是基于传入请求、标记为绑定的PageModel的属性以及页面处理程序所需的方法参数构建的,如图4.3所示。绑定模型通常是一个或多个标准C#对象,其属性映射到请求的数据。我们将在第6章中详细讨论绑定模型。

 

 图4.3将请求路由到控制器并构建绑定模型。对/categy/SimpleURL的请求导致执行CategoryModel.OnGet页面处理程序,并传递填充的绑定模型category。

定义:绑定模型是一个或多个对象,充当页面处理程序所需的请求数据中提供的数据的“容器”。

在本例中,绑定模型是一个简单的字符串category,它绑定到“simple”值。此值在请求URL的路径中提供。还可以使用更复杂的绑定模型,其中填充了多个属性。

本例中的绑定模型对应于OnGet页面处理程序的方法参数。RazorPage的实例是使用其构造函数创建的,绑定模型在执行时传递给页面处理程序,因此可以使用它来决定如何响应。对于本例,页面处理程序使用它来决定要在页面上显示哪些待办事项。

使用应用程序模型执行处理程序

页面处理程序作为MVC模式中的控制器的作用是协调生成对其处理的请求的响应。这意味着它只能执行有限数量的操作。特别是,它应该

  • 验证所提供的绑定模型中包含的数据对请求有效
  • 使用服务在应用程序模型上调用适当的操作
  • 根据应用程序模型的响应选择要生成的适当响应

图4.4显示了在应用程序模型上调用适当方法的页面处理程序。在这里,您可以看到应用程序模型是一个有点抽象的概念,它封装了应用程序的其余非UI部分。它包含域模型、许多服务和数据库交互。

 

 图4.4 执行时,一个动作将调用应用程序模型中的适当方法。

定义:域模型将复杂的业务逻辑封装在一系列类中,这些类不依赖于任何基础设施,并且可以很容易地进行测试。

页面处理程序通常调用应用程序模型中的单个点。在我们查看待办事项列表类别的示例中,应用程序模型可能会使用各种服务来检查当前用户是否被允许查看某些项目、搜索给定类别中的项目、从数据库加载详细信息或从文件加载与项目相关联的图片。

假设请求有效,应用程序模型将向页面处理程序返回所需的详细信息。然后由页面处理程序选择要生成的响应。

使用视图模型构建HTML

一旦页面处理程序调用了包含应用程序业务逻辑的应用程序模型,就应该生成响应了。视图模型捕获视图生成响应所需的详细信息。

定义:MVC模式中的视图模型是视图呈现UI所需的所有数据。这通常是应用程序模型中包含的数据的一些转换,以及呈现页面所需的额外信息,例如页面标题。

术语视图模型在ASP.NET Core MVC中广泛使用,它通常指传递给Razor视图进行渲染的单个对象。然而,使用RazorPages,Razor视图可以直接访问RazorPage的页面模型类。因此,RazorPage PageModel通常充当RazorPage中的视图模型,Razor视图所需的数据通过属性公开,如您之前在清单4.1中所见。

注意:RazorPages使用PageModel类本身作为Razor视图的视图模型,将所需数据作为属性公开。

Razor视图使用页面模型中公开的数据来生成最终的HTML响应。最后,通过中间件管道将其发送回用户的浏览器,如图4.5所示。

 

 图4.5 页面处理程序通过在PageModel上设置属性来构建视图模型。生成响应的是视图。

需要注意的是,尽管页面处理程序选择是否执行视图和要使用的数据,但它并不控制生成的HTML。是视图本身决定了响应的内容。

把这一切放在一起:一个完整的RazorPage请求

现在您已经看到了使用RazorPages在ASP.NET Core中处理请求的每一个步骤,让我们将其从请求到响应放在一起。图4.6显示了如何组合这些步骤来处理显示“简单”类别待办事项列表的请求。传统的MVC模式在RazorPages中仍然可见,它由页面处理程序(控制器)、视图和应用程序模型组成。

  

图4.6 “简单”类别中待办事项列表的完整RazorPages请求

到目前为止,您可能会认为整个过程似乎相当复杂,需要这么多步骤才能显示一些HTML!为什么不允许应用程序模型直接创建视图,而不是必须使用页面处理程序方法来回跳舞?

整个过程的关键好处是将关注点分离:

  • 视图只负责获取一些数据并生成HTML。
  • 应用程序模型只负责执行所需的业务逻辑。
  • 页面处理程序(控制器)仅负责验证传入的请求,并根据应用程序模型的输出选择所需的响应。

通过明确定义边界,可以更容易地更新和测试每个组件,而不依赖其他组件。如果您的UI逻辑发生了变化,您不必修改任何业务逻辑类,因此您不太可能在意外的地方引入错误。

紧密耦合的危险
一般来说,尽可能减少应用程序逻辑上分离的部分之间的耦合是一个好主意。这使得更新应用程序更容易,而不会造成不利影响或需要在看似无关的领域进行修改。应用MVC模式是帮助实现这一目标的一种方式。
作为一个例子,我记得几年前我在开发一个小型网络应用时的一个案例。在匆忙中,我们没有将我们的业务逻辑与HTML生成代码正确地分离,但最初代码没有明显的问题,所以我们将其交付!
几个月后,有人开始开发该应用程序,并立即“帮助”重命名了业务层某个类中的一个无害拼写错误。不幸的是,这些类的名称被用于生成HTML代码,因此重命名类会导致整个网站在用户的浏览器中崩溃!可以说,在那之后,我们做出了一致的努力来应用MVC模式,并确保我们有适当的关注点分离。

本章所示的示例演示了Razor Pages的大部分功能。它还有其他功能,比如过滤管道,我将在后面介绍(第13章),第6章将更深入地讨论绑定模型,但系统的整体行为是相同的。

同样,在第9章中,我将讨论当您使用WebAPI控制器生成机器可读响应时,MVC设计模式是如何应用的。除产生的最终结果外,该过程在所有意图和目的上都是相同的。

在下一节中,您将看到如何将RazorPages添加到应用程序中。默认情况下,Visual Studio和.NET CLI中的一些模板将包含Razor Pages,但您将看到如何将其添加到现有应用程序中并探索各种可用选项。

4.1.4 向应用程序添加RazorPages

MVC基础设施,无论是RazorPages还是MVC/API控制器,都是除了最简单的ASP.NET Core应用程序之外的所有应用程序的基础,因此几乎所有模板都包含默认配置的MVC基础设施。但为了确保您能够轻松地将RazorPages添加到现有项目中,我将向您展示如何从一个基本的空应用程序开始,并从头开始将Razor Pages添加到此项目中。

你努力的结果还不会令人兴奋。我们将在网页上显示“Hello World”,但这将显示将ASP.NET Core应用程序转换为使用RazorPages是多么简单。如果您不需要RazorPages提供的功能,也不必使用它,它还将强调ASP.NET Core的可插拔性。

以下是如何将RazorPages添加到应用程序中:

1. 在Visual Studio 2019中,选择“文件”>“新建”>“项目”,或从启动屏幕中选择“创建新项目”。
2. 从模板列表中,选择ASP.NET Core Web应用程序,确保选择C#语言模板。
3. 在下一个屏幕上,输入项目名称、位置和解决方案名称,然后单击创建。
4. 在下面的屏幕上,通过在Visual Studio中选择ASP.NET Core空项目模板,创建一个没有MVC或RazorPages的基本模板,如图4.7所示。您可以使用.NET CLI和dotnet new web命令创建一个类似的空项目。

图4.7 创建空ASP.NET Core模板。空模板将创建一个简单的ASP.NET Core应用程序,该应用程序包含一个没有RazorPages的小型中间件管道。

5. 在Startup.cs文件的ConfigureServices方法中添加必要的Razor Page服务(以粗体显示):

public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
}
6. 用MapRazorPages()扩展方法(粗体)替换中间件管道末端EndpointMiddleware中配置的现有基本端点。为了简单起见,还可以从Startup.cs的Configure方法中删除现有的错误处理程序中间件:
public void Configure(IApplicationBuilder app,IWebHostEnvironment env)
{
  app.UseRouting();
  app.UseEndpoints(endpoints=>
  {
    endpoints.MapRazorPages();
  });
}
7. 右键单击解决方案资源管理器中的项目,然后选择“添加”>“新建文件夹”,将新文件夹添加到项目的根目录中。将新文件夹命名为“Pages”。您现在已经将项目配置为使用RazorPages,但您还没有任何页面。以下步骤将新的RazorPage添加到应用程序中。可以使用.NET CLI创建类似的RazorPage,通过从项目目录运行dotnet new page-n Index -o Pages。
8. 右键单击新页面文件夹并选择Add>RazorPage,如图4.8所示。

图4.8 向项目添加新的Razor页面

9. 在下一页中,选择RazorPage–Empty,然后单击Add。在下面的对话框中,将页面命名为Index.cshtml,如图4.9所示。

图4.9 使用AddRazorPage对话框创建新的Razor页面

10. Visual Studio完成生成文件后,打开Index.cshtml文件,并更新HTML以表示Hello World!通过将文件内容替换为以下内容:
@page
@model AddingRazorPagesToEmptyProject.IndexModel
@{
  Layout = null;
}
<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width"/>
    <title>Index</title>
  </head>
  <body>
    <h1>Hello World!</h1>
  </body>
</html>

完成所有这些步骤后,您应该能够恢复、构建和运行应用程序。在Visual Studio 2019中,选择“文件”>“新建”>“项目”,或从启动屏幕中选择“创建新项目”。

注意:您可以在Visual Studio中按F5键(或在项目文件夹的命令行中调用dotnet run)来运行项目。这将恢复所有引用的NuGet包,构建项目,并启动应用程序。Visual Studio将自动打开浏览器窗口以访问应用程序的主页。

当您向根“/”路径发出请求时,应用程序会调用IndexModel上的OnGet处理程序,这是由于RazorPages基于文件名的常规路由方式。现在不要担心这一点;我们将在下一章详细讨论。

OnGet处理程序是一个void方法,它使RazorPage呈现关联的Razor视图,并在响应中将其发送到用户的浏览器。

RazorPages依赖于许多内部服务来执行其功能,这些服务必须在应用程序启动期间注册。这是通过调用Startup.cs的ConfigureServices方法中的AddRazorPages实现的。如果没有这一点,你的应用程序启动时会出现异常,提醒你需要通话。

Configure中对MapRazorPages的调用将RazorPage端点注册到端点中间件。作为此调用的一部分,将自动注册用于将URL路径映射到特定RazorPage处理程序的路由。

注:我将在下一章详细介绍路由。

本节中的说明描述了如何将RazorPages添加到应用程序中,但这并不是将HTML生成添加到应用中的唯一方法。正如我之前提到的,RazorPages构建在ASP.NET Core MVC框架之上,并共享许多相同的概念。在下一节中,我们将简要介绍MVC控制器,看看它们与RazorPages的比较,并讨论何时应该选择使用一种方法而不是另一种方法。

4.2 Razor Pages与ASP.NET Core中的MVC

在本书中,我将重点放在RazorPages上,因为这已经成为使用ASP.NET Core构建服务器端渲染应用程序的推荐方法。然而,我还提到Razor Pages在幕后使用ASP.NET Core MVC框架,如果您愿意,可以选择直接使用它。此外,如果您正在创建一个用于处理移动或客户端应用程序的Web API,那么您几乎可以直接使用MVC框架。

注:我在第9章中介绍了如何构建Web API。

那么RazorPages和MVC之间有什么区别,您应该在什么时候选择一个或另一个呢?

如果您是ASP.NET Core的新手,那么答案很简单:使用RazorPages来构建服务器端呈现的应用程序,使用MVC框架来构建WebAPI。我将在后面的章节中讨论一些细微差别,但这种区别最初会很好地为您服务。

如果您熟悉ASP.NET的早期版本或ASP.NET Core的早期版本,并且正在决定是否使用Razor Pages,那么本节将帮助您进行选择。来自这些背景的开发人员最初常常对RazorPages有误解(正如我所做的!),错误地将其等同于WebForm,忽视了MVC框架的底层基础。

但是,在我们进行比较之前,我们应该简要了解一下ASP.NET Core MVC框架本身。了解MVC和RazorPages之间的异同非常有用,因为您可能会在某个时候发现MVC的用处,即使您大部分时间都使用RazorPage。

4.2.1 ASP.NET Core中的MVC控制器

在第4.1节中,我们研究了MVC设计模式,以及它如何应用于ASP.NET Core中的RazorPages。也许毫不奇怪,您可以以几乎完全相同的方式使用ASP.NET Core MVC框架。为了演示RazorPages和MVC之间的区别,我们将查看清单4.1中RazorPage的MVC版本,其中显示了给定类别的待办事项列表。

MVC使用了控制器和操作方法的概念,而不是PageModel和页面处理程序。如图4.10所示,它们几乎直接类似于Razor Pages的计数器部分,图4.10显示了与图4.6等效的MVC。另一方面,MVC控制器使用显式视图模型将数据传递给Razor视图,而不是将数据作为属性本身公开(正如Razor page对页面模型所做的那样)。

定义:动作(或动作方法)是响应请求而运行的方法。MVC控制器是一个包含多个逻辑分组的动作方法的类。

图4.10 完整MVC控制器请求。MVC控制器模式与RazorPages模式几乎相同,如图4.6所示。控制器相当于RazorPage,操作相当于页面处理程序。

清单4.2显示了一个MVC控制器的示例,它提供了与清单4.1中的RazorPage相同的功能。在MVC中,控制器通常用于将类似的动作聚合在一起,因此这种情况下的控制器称为ToDoController,因为它通常包含用于处理待办事项的其他动作方法,例如查看特定项目或创建新项目的动作。

清单4.2 用于查看给定类别中所有待办事项的MVC控制器

public class ToDoController : Controller
{
    private readonly ToDoService _service; 
    public ToDoController(ToDoService service)    //ToDoService是使用依赖注入在控制器构造函数中提供的。
    {
        _service = service;
    }
    public ActionResult Category(string id)    //Category操作方法接受一个参数id。
    {
        var items = _service.GetItemsForCategory(id);    //action方法调用ToDoService以检索数据并构建视图模型。
        var viewModel = new CategoryViewModel(items);    //视图模型是一个简单的C#类,在应用程序的其他地方定义。
        return View(viewModel);    //返回一个ViewResult,指示应渲染Razor视图,并传入视图模型
    }
    //MVC控制器通常包含响应不同请求的多个动作方法。 
    public ActionResult Create(ToDoListModel model)
    {
        // ...
    }
}

除了一些命名上的差异,ToDoController看起来与清单4.1中的Razor Page非常相似。实际上,从架构上讲,Razor Pages和MVC本质上是等效的,因为它们都使用MVC设计模式。最明显的差异与文件在项目中的位置有关,我将在下一节中讨论。

4.2.2 Razor Pages的优势

在上一节中,我展示了MVC控制器的代码看起来与RazorPageModel的代码非常相似。如果是这样的话,使用Razor Pages有什么好处?在本节中,我将讨论MVC控制器的一些痛点,以及RazorPages如何解决这些痛点。

Razor页面不是Web表单
我从现有ASP.NET开发人员那里听到的反对Razor Pages的一个常见论点是“哦,他们只是Web表单。”这种观点在许多不同的方面都没有抓住重点,但这是很常见的,值得直接解决。
Web窗体是一种Web编程模型,于2002年作为.NET Framework 1.0的一部分发布。它们试图为首次从桌面开发转向Web的开发人员提供高效的体验。
Web表单现在受到了很多诋毁,但它们的弱点后来才变得明显。Web表单试图将网络的复杂性隐藏起来,让您感觉使用桌面应用程序开发。这通常会导致应用程序速度慢,相互依赖性强,难以维护。
Web表单提供了基于页面的编程模型,这就是为什么Razor Pages有时会与之关联。然而,正如您所看到的,RazorPages是基于MVC设计模式的,它暴露了web的内在特性,而不试图隐藏它们。
RazorPages使用约定(您已经看到了其中的一些约定)优化了某些流,但它并不像WebForms那样试图在无状态web应用程序的顶部构建有状态的应用程序模型。

在MVC中,一个控制器可以有多个动作方法。每个操作处理不同的请求并生成不同的响应。控制器中多个动作的分组有些随意,但通常用于对与特定实体相关的动作进行分组:在本例中为待办事项列表项。例如,清单4.2中的ToDoController的更完整版本可能包括列出所有待办事项、创建新项目和删除项目的操作方法。不幸的是,您经常会发现您的控制器变得非常庞大和臃肿,具有许多依赖关系。

注:您不必像这样使控制器非常大。这只是一种常见的模式。例如,您可以为每个操作创建单独的控制器。

MVC控制器的另一个缺陷是它们在项目中的组织方式。控制器中的大多数操作方法都需要关联的Razor视图,以及用于向视图传递数据的视图模型。MVC方法传统上按类型(控制器、视图、视图模型)对类进行分组,而RazorPage方法按功能对与特定页面相关的所有内容进行分组。

图4.11将简单RazorPages项目的文件布局与MVC等效项目进行了比较。使用RazorPages意味着无论何时在处理特定页面时,都可以在控制器、视图和视图模型文件夹之间上下滚动。您所需的一切都在两个文件中找到,.cshtml Razor视图和 .cshtml.cs PageModel文件。

图4.11 比较MVC项目的文件夹结构与RazorPages项目的文件夹架构

MVC和RazorPages之间还有其他不同之处,我将在本书中强调,但这种布局差异确实是很大的益处。RazorPages接受这样一个事实,即您正在构建基于页面的应用程序,并通过将与单个页面相关的所有内容放在一起来优化您的工作流程。

提示:您可以将每个Razor Page视为专注于单个页面的迷你控制器。页面处理程序在功能上等同于MVC控制器操作方法。

这种布局还具有使每个页面成为单独的类的优点。这与MVC方法形成了对比,MVC方法将每个页面作为给定控制器上的操作。每个RazorPage都是针对特定功能的,例如显示待办事项。MVC控制器包含处理多个不同功能的动作方法,以实现更抽象的概念,例如与待办事项相关的所有功能。

另一个重要的点是RazorPages并没有失去MVC所具有的关注点分离。RazorPages的视图部分仍然只关注呈现HTML,处理程序是调用应用程序模型的协调器。唯一真正的区别是缺少MVC中的显式视图模型,但如果这对您来说是一个破坏,那么在RazorPages中模仿它是完全可能的。

使用Razor Pages的好处在您拥有“内容”网站时尤其明显,例如营销网站,在那里您主要显示静态数据,而且没有真正的逻辑。在这种情况下,MVC增加了复杂性,但没有任何实际好处,因为控制器中根本没有任何逻辑。另一个很好的用例是创建表单供用户提交数据。RazorPages特别针对这个场景进行了优化,您将在后面的章节中看到。

显然,我是Razor Pages的粉丝,但这并不是说它们适合任何情况。在下一节中,我将讨论在应用程序中选择使用MVC控制器的一些情况。记住,这不是非此即彼的选择,在同一应用程序中同时使用MVC控制器和RazorPages是可能的,在很多情况下,这可能是最好的选择。

4.2.3 何时选择MVC控制器而不是Razor Pages

RazorPages非常适合构建基于页面的服务器端渲染应用程序。但并非所有的应用程序都符合这种模式,甚至有些属于这种类型的应用程序可能最好使用MVC控制器而不是RazorPages来开发。以下是一些这样的场景:

  • 当您不想呈现视图时,RazorPages最适合基于页面的应用程序,在那里您为用户呈现视图。如果您正在构建Web API,则应该使用MVC控制器。
  • 当您将现有MVC应用程序转换为ASP.NET Core时如果您已经有一个使用MVC的ASP.NET应用程序,那么将现有MVC控制器转换为Razor Pages可能不值得。保留现有代码更有意义,也许可以考虑使用RazorPages在应用程序中进行新的开发。
  • 当您进行大量部分页面更新时,可以在应用程序中使用JavaScript,通过一次仅更新部分页面来避免进行全页面导航。这种方法介于完全服务器端渲染和客户端应用程序之间,使用MVC控制器可能比RazorPages更容易实现。

何时不使用Razor Pages或MVC控制器
通常,您将使用Razor Pages或MVC控制器为应用程序编写大部分应用程序逻辑。您将使用它来定义应用程序中的API和页面,并定义它们如何与业务逻辑交互。RazorPages和MVC提供了一个广泛的框架(您将在接下来的六章中看到),它提供了大量功能,帮助快速高效地构建应用程序。但它们并不适合每个应用。
提供如此多的功能必然会带来一定程度的性能开销。对于典型的应用程序,使用MVC或RazorPages带来的生产力收益远远超过了性能影响。但是,如果您正在为云构建小型、轻量级的应用程序,您可以考虑直接使用定制中间件(参见第19章)或gRPC等替代协议(https://docs.microsoft.com/ASP.NET/core/grpc)。你可能还想看看Christian Horsdal Gammelgaard(Manning,2017)的《Microservices in .NET Core》。
或者,如果您正在构建具有实时功能的应用程序,您可能会考虑使用WebSocket而不是传统的HTTP请求。ASP.NET Core SignalR可以通过在WebSocket上提供抽象来为应用程序添加实时功能。SignalR还提供了简单的传输回退和远程过程调用(RPC)应用程序模型。有关详细信息,请参阅文档https://docs.microsoft.com/ASP.NET/core/signalr。
ASP.NET Core 5.0中的另一个选项是Blazor。此框架允许您通过利用WebAssembly标准直接在浏览器中运行.NET代码,或者使用SignalR的有状态模型来构建交互式客户端web应用程序。有关详细信息,请参阅文档,网址:https://docs.microsoft.com/ASP.NET/core/blazor/。

希望此时您已在Razor Pages及其整体设计上售出。到目前为止,我们看过的所有RazorPages都使用了一个页面处理程序。在下一节中,我们将更深入地研究页面处理程序:如何定义它们,如何调用它们,以及如何使用它们来呈现Razor视图。

4.3 Razor Pages和页面处理程序

在本章的第一节中,我描述了MVC设计模式及其与ASP.NET Core的关系。在设计模式中,控制器接收请求,并且是UI生成的入口点。对于RazorPages,入口点是驻留在RazorPage的PageModel中的页面处理程序。页面处理程序是响应请求而运行的方法。

默认情况下,磁盘上Razor Page的路径控制Razor页响应的URL路径。例如,对URL/products/list的请求对应于路径pages/products/list.cshtml上的Razor页面。RazorPages可以包含任意数量的页面处理程序,但只有一个页面处理程序响应给定的请求运行。

注意:在下一章中,您将了解有关选择RazorPage和处理程序(称为路由)的更多信息。

页面处理程序的职责通常有三重:

  • 确认传入请求有效。
  • 调用与传入请求相对应的适当业务逻辑。
  • 选择要返回的适当类型的响应。

页面处理程序不需要执行所有这些操作,但至少它必须选择要返回的响应类型。页面处理程序通常返回以下三项之一:

  • PageResult对象——这将导致关联的Razor视图生成HTML响应。
  • Nothing(处理程序返回void或Task)——这与前面的情况相同,导致Razor视图生成HTML响应。
  • RedirectToPageResult——这表示应该将用户重定向到应用程序中的其他页面。

这些是Razor Pages最常用的结果,但我在第4.3.2节中描述了一些其他选项。

重要的是要认识到页面处理程序不会直接生成响应;它选择响应类型并为其准备数据。例如,返回PageResult时不会生成任何HTML;它仅仅指示应当呈现视图。这与MVC设计模式保持一致,其中生成响应的是视图,而不是控制器。

提示:页面处理程序负责选择要发送的响应类型;MVC框架中的视图引擎使用结果来生成响应。

还值得记住的是,页面处理程序通常不应该直接执行业务逻辑。相反,他们应该在应用程序模型中调用适当的服务来处理请求。例如,如果页面处理程序收到将产品添加到用户购物车的请求,则不应直接操作数据库或重新计算购物车总数。相反,它应该调用另一个类来处理细节。这种分离关注点的方法确保了代码在增长时保持可测试性和可维护性。

4.3.1 接受页面处理程序的参数

向页面处理程序发出的某些请求将需要附加值以及有关请求的详细信息。如果请求是搜索页面,则请求可能包含搜索词的详细信息和他们正在查看的页码。如果请求向应用程序发布表单,例如用户使用用户名和密码登录,则这些值必须包含在请求中。在其他情况下,将没有值,例如当用户请求应用程序的主页时。

请求可能包含来自各种不同来源的附加值。它们可以是URL、查询字符串、标头或请求本身的一部分。中间件将从每个源中提取值,并将它们转换为.NET类型。

定义:从请求中提取值并将其转换为.NET类型的过程称为模型绑定。我在第6章中讨论了模型绑定。

ASP.NET Core可以在Razor Pages中绑定两个不同的目标:

  • 方法参数——如果页面处理程序具有方法参数,则使用请求中的值来创建所需的参数。
  • 用[BindProperty]属性标记的属性——将绑定用该属性标记的任何属性。默认情况下,此属性对GET请求不起作用。

模型绑定值可以是简单类型,例如字符串和整数,也可以是复杂类型,如以下列表所示。如果请求中提供的任何值未绑定到属性或页面处理程序参数,则其他值将不使用。

清单4.3 Razor页面处理程序示例

public class SearchModel : PageModel
{
    private readonly SearchService _searchService; 
    //SearchService提供给SearchModel以用于页面处理程序。
    public SearchModel(SearchService searchService)
    {
        _searchService = searchService;
    }
    
    [BindProperty]
    public BindingModel Input { get; set; }     //用[BindProperty]属性修饰的属性将被模型绑定。
    public List<Product> Results { get; set; }    //未修饰的属性将不会绑定到模型。
    
    //页面处理程序不需要检查模型是否有效。返回void将渲染视图。
    public void OnGet()
    {
    }
    
    public IActionResult OnPost(int max)    //此页面处理程序中的max参数将使用请求中的值进行模型绑定。
    {
        //如果请求无效,则该方法指示应将用户重定向到索引页。 
        if (ModelState.IsValid)
        {
            Results = _searchService.Search (Input.SearchTerm, max); 
            return Page();
        }
        return RedirectToPage("./Index");
    }
}

在本例中,OnGet处理程序不需要任何参数,而且方法很简单,它返回void,这意味着将呈现关联的Razor视图。它还可能返回PageResult;效果也会是一样的。请注意,此处理程序用于HTTP GET请求,因此未绑定用[BindProperty]修饰的Input属性。

提示:要绑定GET请求的属性,请使用属性的SupportsGet属性;例如[BindProperty(SupportsGet=true)]。

相反,OnPost处理程序接受参数max作为参数。在本例中,它是一个简单的类型int,但也可以是一个复杂的对象。此外,由于此处理程序对应于HTTP POST请求,因此Input属性也被模型绑定到请求。

注意:与大多数.NET类不同,您不能使用方法重载在RazorPage上使用相同名称的多个页面处理程序。

当操作方法使用模型绑定属性或参数时,应始终使用ModelState.IsValid检查所提供的模型是否有效。ModelState属性作为基PageModel类上的属性公开,可用于检查所有绑定的属性和参数是否有效。当您了解验证时,您将在第6章中看到该过程是如何工作的。

一旦页面处理程序确定提供给操作的方法参数有效,它就可以执行适当的业务逻辑并处理请求。对于OnPost处理程序,这涉及调用提供的SearchService并在Results属性上设置结果。最后,处理程序通过调用基方法返回PageResult

return Page();

如果模型无效,则没有任何结果可显示!在此示例中,该操作使用RedirectToPage帮助器方法返回RedirectToPageResult。执行时,此结果将向用户发送302重定向响应,这将导致其浏览器导航到Index Razor Page。

注意,OnGet方法在方法签名中返回void,而OnPost方法返回IActionResult。这在OnPost方法中是必需的,以便允许C#编译(因为Page和RedirectToPage帮助器方法返回不同的类型),但它不会改变方法的最终行为。您可以很容易地在OnGet方法中调用Page并返回一个IActionResult,其行为将是相同的。

提示:如果要从页面处理程序返回多个类型的结果,则需要确保方法返回IActionResult。

在下一节中,我们将更深入地了解操作结果及其用途。

4.3.2 返回带有ActionResults的响应

在上一节中,我强调了页面处理程序决定返回什么类型的响应,但它们自己不会生成响应。它是页面处理程序返回的IActionResult,当RazorPages基础结构使用视图引擎执行该处理程序时,将生成响应。

这种方法是遵循MVC设计模式的关键。它将发送何种响应的决定与响应的生成分开。这允许您轻松测试动作方法逻辑,以确认为给定输入发送了正确类型的响应。例如,您可以单独测试给定的IActionResult是否生成预期的HTML。

ASP.NET Core有许多不同类型的IActionResult:

  • PageResult——为Razor Pages中的关联页面生成HTML视图
  • ViewResult——使用MVC控制器时为给定Razor视图生成HTML视图
  • RedirectToPageResult——发送302 HTTP重定向响应以自动将用户发送到另一个页面
  • RedirectResult——发送302 HTTP重定向响应,自动将用户发送到指定的URL(不必是Razor Page)
  • FileResult——返回文件作为响应
  • ContentResult——返回提供的字符串作为响应
  • StatusCodeResult——发送原始HTTP状态代码作为响应,可以选择与相关的响应正文内容
  • NotFoundResult——发送原始404 HTTP状态代码作为响应

当RazorPages执行这些命令时,将生成一个响应,通过中间件管道发送回用户。

提示:当您使用Razor Pages时,通常不会使用其中的一些操作结果,例如ContentResult和StatusCodeResult。不过,了解它们是很好的,因为如果您使用MVC控制器构建Web API,您可能会使用它们。

在本节中,我将简要介绍RazorPages中使用的最常见的IActionResult类。

PageResult和RedirectToPageResult

当您使用RazorPages构建传统的web应用程序时,通常会使用PageResult,后者使用Razor生成HTML响应。我们将在第7章中详细了解这是如何发生的。

您还通常使用各种基于重定向的结果将用户发送到新的网页。例如,当您在电子商务网站上下单时,通常会浏览多个页面,如图4.12所示。每当需要您移动到其他页面时,例如当用户提交表单时,web应用程序就会发送HTTP重定向。您的浏览器会自动跟踪重定向请求,从而在结账过程中创建无缝流程。

图4.12 通过网站的典型POST、REDIRECT和GET流程。用户将购物篮发送到结账页面,该页面验证其内容并重定向到付款页面,而无需用户手动更改URL。

在这个流程中,每当您返回HTML时,都会使用PageResult;重定向到新页面时,使用RedirectToPageResult。

提示:RazorPages通常被设计为无状态的,因此如果您想在多个页面之间持久化数据,则需要将其放置在数据库或类似的存储中。如果您只想为单个请求存储数据,您可以使用TempData,它为单个请求在cookie中存储少量数据。有关详细信息,请参阅文档:http://mng.bz/XdXp。

未找到结果和状态搜索结果

除了HTML和重定向响应之外,您有时还需要发送特定的HTTP状态代码。如果您请求在电子商务应用程序上查看产品的页面,而该产品不存在,则会向浏览器返回404 HTTP状态代码,您通常会看到“未找到”网页。RazorPages可以通过返回NotFoundResult来实现此行为,该结果将返回原始的404 HTTP状态代码。使用StatusCodeResult并将显式返回的状态代码设置为404,可以获得类似的结果。

注意:NotFoundResult不会生成任何HTML;它只生成一个原始的404状态代码,并通过中间件管道返回它。但是,如前一章所述,您可以使用StatusCodePagesMiddleware在生成原始404状态代码后拦截该代码,并为其提供用户友好的HTML响应。

使用助手方法创建ActionResult类

可以使用C#的普通新语法创建和返回ActionResult类:

return new PageResult()

然而,RazorPagesPageModel基类还提供了许多用于生成响应的帮助器方法。通常使用Page方法生成适当的PageResult,使用RedirectToPage方法生成RedirectToPageResult,或使用NotFound方法生成NotFoundResult。

提示:大多数ActionResult类在基本PageModel类上都有一个helper方法。它们通常命名为Type,生成的结果称为Type-result。例如,StatusCode方法返回StatusCodeResult实例。

如前所述,返回IActionResult的行为不会立即生成响应,而是RazorPages基础结构执行IActionResult,这发生在action方法之外。生成响应后,RazorPages将其返回到中间件管道。从那里,它通过管道中所有注册的中间件,然后ASP.NET Core web服务器最终将其发送给用户。

现在,您应该全面了解MVC设计模式,以及它与ASP.NET Core和RazorPages的关系。RazorPage上的页面处理程序方法是响应给定请求而调用的,用于通过返回IActionResult来选择要生成的响应类型。

重要的是要记住,ASP.NET Core中的MVC和Razor Pages基础架构作为EndpointMiddleware管道的一部分运行,正如您在上一章中所看到的。生成的任何响应,无论是PageResult还是RedirectToPageResult,都将通过中间件管道传回,从而为中间件提供了一个潜在的机会,以便在web服务器将响应发送给用户之前观察该响应。

我只模糊地谈到了RoutingMiddleware如何决定为给定请求调用哪个RazorPage和处理程序。你不希望应用程序中的每个URL都有Razor页面。例如,在电子商店中,每个产品都很难有不同的页面——每个产品都需要自己的Razor页面!处理这个和其他场景是路由基础设施的作用,也是ASP.NET Core的关键部分。在下一章中,您将看到如何定义路由,如何向路由添加约束,以及如何解构URL以匹配单个Razor Page处理程序。

总结

  • MVC设计模式允许在应用程序的业务逻辑、传递的数据和响应中的数据显示之间分离关注点。
  • RazorPages是基于ASP.NET Core MVC框架构建的,它们使用许多相同的原语。他们使用约定和不同的项目布局来优化基于页面的场景。
  • MVC控制器包含多个动作方法,通常围绕一个高级实体分组。RazorPages将单个页面的所有页面处理程序分组在一个位置,围绕页面/功能而不是实体分组。
  • 每个RazorPage相当于一个专注于单个页面的小型控制器,每个Razor Page处理程序对应于一个单独的操作方法。
  • RazorPages应该继承自PageModel基类。
  • 在一个称为路由的过程中,根据传入请求的URL、HTTP谓词和请求的查询字符串选择一个RazorPage处理程序。
  • 页面处理程序通常应该委托给服务来处理请求所需的业务逻辑,而不是自己执行更改。这确保了清晰的关注点分离,有助于测试并改进应用程序结构。
  • 页面处理程序可以具有参数,这些参数的值取自称为模型绑定的进程中传入请求的属性。用[BindProperty]修饰的属性也可以绑定到请求。
  • 默认情况下,用[BindProperty]修饰的属性不绑定GET请求。要启用绑定,请使用[BindProperty(SupportsGet=true)]。
  • 页面处理程序可以返回PageResult或void以生成HTML响应。
  • 您可以使用RedirectToPageResult将用户发送到新的Razor页面。
  • PageModel基类公开了许多用于创建ActionResult的帮助器方法。

 

标签:Razor,ASP,Core,应用程序,MVC,处理程序,视图,RazorPages,页面
From: https://www.cnblogs.com/SoftwareLife/p/16944207.html

相关文章