{"id":609,"date":"2025-04-05T11:42:02","date_gmt":"2025-04-05T03:42:02","guid":{"rendered":"https:\/\/www.hyy.net\/?p=609"},"modified":"2025-04-05T11:42:02","modified_gmt":"2025-04-05T03:42:02","slug":"asp-net-core-in-action-19-creating-a-website-with-mvc-controllers","status":"publish","type":"post","link":"https:\/\/diji.net\/?p=609","title":{"rendered":"ASP.NET Core in Action 19 Creating a website with MVC controllers"},"content":{"rendered":"<p>19 Creating a website with MVC controllers<br \/>\n19 \u4f7f\u7528 MVC \u63a7\u5236\u5668\u521b\u5efa\u7f51\u7ad9<\/p>\n<p>This chapter covers<br \/>\n\u672c\u7ae0\u6db5\u76d6<br \/>\n\u2022  Creating a Model-View-Controller (MVC) application<br \/>\n\u521b\u5efa\u6a21\u578b-\u89c6\u56fe-\u63a7\u5236\u5668 \uff08MVC\uff09 \u5e94\u7528\u7a0b\u5e8f<br \/>\n\u2022  Choosing between Razor Pages and MVC controllers<br \/>\n\u5728 Razor Pages \u548c MVC \u63a7\u5236\u5668\u4e4b\u95f4\u8fdb\u884c\u9009\u62e9<br \/>\n\u2022  Returning Razor views from MVC controllers<br \/>\n\u4ece MVC \u63a7\u5236\u5668\u8fd4\u56de Razor \u89c6\u56fe<\/p>\n<p>In this book I\u2019ve focused on Razor Pages over MVC controllers for server-rendered HTML apps, as I consider Razor Pages to be the preferable paradigm in most cases. In this chapter we dig a bit more into exactly why I consider Razor Pages to be the right choice and take a brief look at the alternative.<br \/>\n\u5728\u8fd9\u672c\u4e66\u4e2d\uff0c\u6211\u91cd\u70b9\u4ecb\u7ecd\u4e86\u670d\u52a1\u5668\u6e32\u67d3\u7684 HTML \u5e94\u7528\u7a0b\u5e8f\u7684 Razor Pages \u800c\u4e0d\u662f MVC \u63a7\u5236\u5668\uff0c\u56e0\u4e3a\u6211\u8ba4\u4e3a\u5728\u5927\u591a\u6570\u60c5\u51b5\u4e0b\uff0cRazor Pages \u662f\u66f4\u53ef\u53d6\u7684\u8303\u4f8b\u3002\u5728\u672c\u7ae0\u4e2d\uff0c\u6211\u4eec\u5c06\u66f4\u6df1\u5165\u5730\u63a2\u8ba8\u4e3a\u4ec0\u4e48\u6211\u8ba4\u4e3a Razor Pages \u662f\u6b63\u786e\u7684\u9009\u62e9\uff0c\u5e76\u7b80\u8981\u4ecb\u7ecd\u4e00\u4e0b\u66ff\u4ee3\u65b9\u6848\u3002<\/p>\n<p>In section 19.2 you\u2019ll create a default MVC application using a template so you can familiarize yourself with the general project layout of an MVC application. We\u2019ll look at some of the differences between an MVC application and a Razor Pages app, as well as the many similarities.<br \/>\n\u5728 Section 19.2 \u4e2d\uff0c\u60a8\u5c06\u4f7f\u7528\u6a21\u677f\u521b\u5efa\u9ed8\u8ba4\u7684 MVC \u5e94\u7528\u7a0b\u5e8f\uff0c\u4ee5\u4fbf\u719f\u6089 MVC \u5e94\u7528\u7a0b\u5e8f\u7684\u4e00\u822c\u9879\u76ee\u5e03\u5c40\u3002\u6211\u4eec\u5c06\u4e86\u89e3 MVC \u5e94\u7528\u7a0b\u5e8f\u548c Razor Pages \u5e94\u7528\u7a0b\u5e8f\u4e4b\u95f4\u7684\u4e00\u4e9b\u5dee\u5f02\uff0c\u4ee5\u53ca\u8bb8\u591a\u76f8\u4f3c\u4e4b\u5904\u3002<\/p>\n<p>Next, I\u2019ll dig into why I find Razor Pages to be a preferable application model compared with MVC controllers. You\u2019ll learn about the improved developer ergonomics of Razor Pages compared with MVC controllers, as well as the cases in which MVC controllers are nevertheless the right choice.<br \/>\n\u63a5\u4e0b\u6765\uff0c\u6211\u5c06\u6df1\u5165\u63a2\u8ba8\u4e3a\u4ec0\u4e48\u6211\u8ba4\u4e3a\u4e0e MVC \u63a7\u5236\u5668\u76f8\u6bd4\uff0cRazor Pages \u662f\u66f4\u53ef\u53d6\u7684\u5e94\u7528\u7a0b\u5e8f\u6a21\u578b\u3002\u60a8\u5c06\u4e86\u89e3 Razor Pages \u4e0e MVC \u63a7\u5236\u5668\u76f8\u6bd4\u6539\u8fdb\u7684\u5f00\u53d1\u4eba\u5458\u4eba\u4f53\u5de5\u7a0b\u5b66\uff0c\u4ee5\u53ca MVC \u63a7\u5236\u5668\u4ecd\u7136\u662f\u6b63\u786e\u9009\u62e9\u7684\u60c5\u51b5\u3002<\/p>\n<p>In section 19.4 you\u2019ll learn about rendering Razor views using MVC controllers. You\u2019ll learn how the MVC framework relies on conventions to locate view files and how to override these by selecting a specific Razor view template to render. Finally, you\u2019ll see the full view selection algorithm in all its glory.<br \/>\n\u5728\u7b2c 19.4 \u8282\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3\u5982\u4f55\u4f7f\u7528 MVC \u63a7\u5236\u5668\u6e32\u67d3 Razor \u89c6\u56fe\u3002\u60a8\u5c06\u4e86\u89e3 MVC \u6846\u67b6\u5982\u4f55\u4f9d\u8d56\u7ea6\u5b9a\u6765\u67e5\u627e\u89c6\u56fe\u6587\u4ef6\uff0c\u4ee5\u53ca\u5982\u4f55\u901a\u8fc7\u9009\u62e9\u8981\u5448\u73b0\u7684\u7279\u5b9a Razor \u89c6\u56fe\u6a21\u677f\u6765\u8986\u76d6\u8fd9\u4e9b\u6587\u4ef6\u3002\u6700\u540e\uff0c\u60a8\u5c06\u770b\u5230\u5b8c\u6574\u89c6\u56fe\u9009\u62e9\u7b97\u6cd5\u7684\u6240\u6709\u8363\u8000\u3002<\/p>\n<h2>19.1 Razor Pages vs. MVC in ASP.NET Core<\/h2>\n<p>19.1 Razor Pages \u4e0e ASP.NET Core \u4e2d\u7684 MVC<\/p>\n<p>In this book I focus on Razor Pages, but I have also mentioned that Razor Pages use the ASP.NET Core MVC framework behind the scenes and that you can choose to use the MVC framework directly if you wish. Additionally, if you\u2019re creating an API for working with mobile or client-side apps, and you don\u2019t want to (or can\u2019t) use minimal APIs, you may well use the MVC framework directly by creating web API controllers.<br \/>\n\u5728\u672c\u4e66\u4e2d\uff0c\u6211\u91cd\u70b9\u4ecb\u7ecd\u4e86 Razor Pages\uff0c\u4f46\u6211\u4e5f\u63d0\u5230\u4e86 Razor Pages \u5728\u540e\u53f0\u4f7f\u7528 ASP.NET Core MVC \u6846\u67b6\uff0c\u5982\u679c\u60a8\u613f\u610f\uff0c\u53ef\u4ee5\u9009\u62e9\u76f4\u63a5\u4f7f\u7528 MVC \u6846\u67b6\u3002\u6b64\u5916\uff0c\u5982\u679c\u60a8\u6b63\u5728\u521b\u5efa\u7528\u4e8e\u79fb\u52a8\u6216\u5ba2\u6237\u7aef\u5e94\u7528\u7a0b\u5e8f\u7684 API\uff0c\u5e76\u4e14\u60a8\u4e0d\u60f3\uff08\u6216\u4e0d\u80fd\uff09\u4f7f\u7528\u6700\u5c11\u7684 API\uff0c\u5219\u53ef\u4ee5\u901a\u8fc7\u521b\u5efa Web API \u63a7\u5236\u5668\u6765\u76f4\u63a5\u4f7f\u7528 MVC \u6846\u67b6\u3002<\/p>\n<p><b>NOTE<\/b> I look at how to build web APIs with the MVC framework in chapter 20.<br \/>\n\u6ce8\u610f:\u5728\u7b2c 20 \u7ae0\u4e2d\uff0c\u6211\u5c06\u4ecb\u7ecd\u5982\u4f55\u4f7f\u7528 MVC \u6846\u67b6\u6784\u5efa Web API\u3002<\/p>\n<p>So what are the differences between Razor Pages and the MVC framework, and when should you choose one or the other?<br \/>\n\u90a3\u4e48 Razor Pages \u548c MVC \u6846\u67b6\u6709\u4ec0\u4e48\u533a\u522b\uff0c\u4ec0\u4e48\u65f6\u5019\u5e94\u8be5\u9009\u62e9\u5176\u4e2d\u4e4b\u4e00\u5462\uff1f<\/p>\n<p>If you\u2019re new to ASP.NET Core, the answer is pretty simple: use Razor Pages for server-side rendered applications, and use web API controllers (or minimal APIs) for building APIs. There are nuances to this advice, which I discuss in section 19.5, but that distinction will serve you well for now.<br \/>\n\u5982\u679c\u4f60\u4e0d\u719f\u6089 ASP.NET Core\uff0c\u7b54\u6848\u975e\u5e38\u7b80\u5355\uff1a\u5c06 Razor Pages \u7528\u4e8e\u670d\u52a1\u5668\u7aef\u5448\u73b0\u7684\u5e94\u7528\u7a0b\u5e8f\uff0c\u5e76\u4f7f\u7528 Web API \u63a7\u5236\u5668\uff08\u6216\u6700\u5c0f API\uff09\u6765\u6784\u5efa API\u3002\u8fd9\u4e2a\u5efa\u8bae\u6709\u4e00\u4e9b\u7ec6\u5fae\u5dee\u522b\uff0c\u6211\u5728\u7b2c 19.5 \u8282\u4e2d\u8ba8\u8bba\uff0c\u4f46\u8fd9\u79cd\u533a\u522b\u73b0\u5728\u5bf9\u4f60\u5f88\u6709\u5e2e\u52a9\u3002<\/p>\n<blockquote>\n<p>Naming is hard, again<br \/>\n\u547d\u540d\u5f88\u56f0\u96be\uff0c\u540c\u6837<\/p>\n<p>Microsoft have a long history of creating a framework and naming it after a generic concept: MVC, Web Forms, Web Pages, Multi-platform App UI, and so on. it\u2019s frankly incredible that Blazor survived! Web API is no different.<br \/>\nMicrosoft \u521b\u5efa\u6846\u67b6\u5e76\u4ee5\u901a\u7528\u6982\u5ff5\u547d\u540d\u5b83\u7684\u5386\u53f2\u7531\u6765\u5df2\u4e45\uff1aMVC\u3001Web Forms\u3001Web Pages\u3001Multi-platform App UI \u7b49\u3002\u5766\u7387\u5730\u8bf4\uff0cBlazor \u5e78\u5b58\u4e0b\u6765\u771f\u662f\u4e0d\u53ef\u601d\u8bae\uff01Web API \u4e5f\u4e0d\u4f8b\u5916\u3002<\/p>\n<p>In legacy ASP.NET, Microsoft created a web API framework, which was similar in design to the existing MVC framework, but also was not interoperable. You therefore had MVC controllers, which were controller classes used with the MVC framework to generate HTML, and web API controllers, which were controller classes used with the web API framework, to generate JavaScript Object Notation (JSON) or Extensible Markup Language (XML).<br \/>\n\u5728\u65e7\u7248 ASP.NET \u4e2d\uff0cMicrosoft \u521b\u5efa\u4e86\u4e00\u4e2a Web API \u6846\u67b6\uff0c\u8be5\u6846\u67b6\u5728\u8bbe\u8ba1\u4e0a\u4e0e\u73b0\u6709\u7684 MVC \u6846\u67b6\u76f8\u4f3c\uff0c\u4f46\u4e5f\u4e0d\u53ef\u4e92\u4f5c\u3002\u56e0\u6b64\uff0c\u60a8\u6709 MVC \u63a7\u5236\u5668\uff08\u4e0e MVC \u6846\u67b6\u4e00\u8d77\u4f7f\u7528\u7684\u63a7\u5236\u5668\u7c7b\uff0c\u7528\u4e8e\u751f\u6210 HTML\uff09\u548c Web API \u63a7\u5236\u5668\uff08\u4e0e Web API \u6846\u67b6\u4e00\u8d77\u4f7f\u7528\u7684\u63a7\u5236\u5668\u7c7b\uff09\uff0c\u7528\u4e8e\u751f\u6210 JavaScript \u5bf9\u8c61\u8868\u793a\u6cd5 \uff08JSON\uff09 \u6216\u53ef\u6269\u5c55\u6807\u8bb0\u8bed\u8a00 \uff08XML\uff09\u3002<\/p>\n<p>In ASP.NET Core, Microsoft merged these two parallel stacks into a single ASP.NET Core MVC framework. Controllers in ASP.NET Core can generate both HTML and JSON\/XML; there is no separation. Nevertheless, it\u2019s common for a controller to be dedicated to either HTML generation or JSON\/XML. For that reason, the names MVC controller and web API controller are often used to refer to the two general types of controller: MVC for HTML and web API for JSON\/XML.<br \/>\n\u5728 ASP.NET Core \u4e2d\uff0cMicrosoft\u5c06\u8fd9\u4e24\u4e2a\u5e76\u884c\u5806\u6808\u5408\u5e76\u5230\u4e00\u4e2a ASP.NET Core MVC \u6846\u67b6\u4e2d\u3002ASP.NET Core \u4e2d\u7684\u63a7\u5236\u5668\u53ef\u4ee5\u751f\u6210 HTML \u548c JSON\/XML;\u6ca1\u6709\u5206\u79bb\u3002\u5c3d\u7ba1\u5982\u6b64\uff0c\u63a7\u5236\u5668\u901a\u5e38\u4e13\u7528\u4e8e HTML \u751f\u6210\u6216 JSON\/XML\u3002\u56e0\u6b64\uff0cMVC \u63a7\u5236\u5668\u548c Web API \u63a7\u5236\u5668\u8fd9\u4e24\u4e2a\u540d\u79f0\u901a\u5e38\u7528\u4e8e\u6307\u4ee3\u4e24\u79cd\u5e38\u89c4\u7c7b\u578b\u7684\u63a7\u5236\u5668\uff1a\u7528\u4e8e HTML \u7684 MVC \u548c\u7528\u4e8e JSON\/XML \u7684 Web API\u3002<\/p>\n<p>In this book when I refer to web API controllers, I\u2019m talking about standard ASP.NET Core controllers that are generating API responses. This may be described elsewhere as a web API application using MVC controllers or as a web API application. All three cases refer to the same concept: an HTTP API built using ASP.NET Core controllers.<br \/>\n\u5728\u672c\u4e66\u4e2d\uff0c\u5f53\u6211\u63d0\u5230 Web API \u63a7\u5236\u5668\u65f6\uff0c\u6211\u6307\u7684\u662f\u751f\u6210 API \u54cd\u5e94\u7684\u6807\u51c6 ASP.NET Core \u63a7\u5236\u5668\u3002\u8fd9\u53ef\u80fd\u5728\u5176\u4ed6\u5730\u65b9\u63cf\u8ff0\u4e3a\u4f7f\u7528 MVC \u63a7\u5236\u5668\u7684 Web API \u5e94\u7528\u7a0b\u5e8f\u6216 Web API \u5e94\u7528\u7a0b\u5e8f\u3002\u8fd9\u4e09\u79cd\u60c5\u51b5\u90fd\u662f\u6307\u540c\u4e00\u4e2a\u6982\u5ff5\uff1a\u4f7f\u7528 ASP.NET Core \u63a7\u5236\u5668\u6784\u5efa\u7684 HTTP API\u3002<\/p>\n<\/blockquote>\n<p>Before we can get to comparisons, though, we should take a brief look at the ASP.NET Core MVC framework itself. Understanding the similarities and differences between MVC controllers and Razor Pages can be useful, as you\u2019ll likely find a use for MVC controllers at some point, even if you use Razor Pages most of the time.<br \/>\n\u4e0d\u8fc7\uff0c\u5728\u8fdb\u884c\u6bd4\u8f83\u4e4b\u524d\uff0c\u6211\u4eec\u5e94\u8be5\u7b80\u8981\u4e86\u89e3\u4e00\u4e0b ASP.NET Core MVC \u6846\u67b6\u672c\u8eab\u3002\u4e86\u89e3 MVC \u63a7\u5236\u5668\u548c Razor Pages \u4e4b\u95f4\u7684\u5f02\u540c\u53ef\u80fd\u5f88\u6709\u7528\uff0c\u56e0\u4e3a\u5373\u4f7f\u60a8\u5927\u90e8\u5206\u65f6\u95f4\u90fd\u5728\u4f7f\u7528 Razor Pages\uff0c\u60a8\u4e5f\u53ef\u80fd\u4f1a\u5728\u67d0\u4e9b\u65f6\u5019\u53d1\u73b0 MVC \u63a7\u5236\u5668\u7684\u7528\u9014\u3002<\/p>\n<h3>19.2 Your first MVC web application<\/h3>\n<p>19.2 \u60a8\u7684\u7b2c\u4e00\u4e2a MVC Web \u5e94\u7528\u7a0b\u5e8f<\/p>\n<p>In this section you\u2019ll learn how to create your first MVC web application, which server-renders HTML pages using MVC controllers and Razor views. We use a template to create the app and compare the generated code to see how it differs from a Razor Pages application.<br \/>\n\u5728\u672c\u90e8\u5206\u4e2d\uff0c\u4f60\u5c06\u4e86\u89e3\u5982\u4f55\u521b\u5efa\u7b2c\u4e00\u4e2a MVC Web \u5e94\u7528\u7a0b\u5e8f\uff0c\u8be5\u5e94\u7528\u7a0b\u5e8f\u4f7f\u7528 MVC \u63a7\u5236\u5668\u548c Razor \u89c6\u56fe\u670d\u52a1\u5668\u5448\u73b0 HTML \u9875\u9762\u3002\u6211\u4eec\u4f7f\u7528\u6a21\u677f\u521b\u5efa\u5e94\u7528\u5e76\u6bd4\u8f83\u751f\u6210\u7684\u4ee3\u7801\uff0c\u4ee5\u4e86\u89e3\u5b83\u4e0e Razor Pages \u5e94\u7528\u7a0b\u5e8f\u6709\u4f55\u4e0d\u540c\u3002<\/p>\n<p>We\u2019ll again use a template to get an application up and running quickly. This time we\u2019ll use the ASP.NET Core Web App (Model-View-Controller) template. To create the application in Visual Studio, follow these steps:<br \/>\n\u6211\u4eec\u5c06\u518d\u6b21\u4f7f\u7528\u6a21\u677f\u6765\u5feb\u901f\u542f\u52a8\u548c\u8fd0\u884c\u5e94\u7528\u7a0b\u5e8f\u3002\u8fd9\u6b21\uff0c\u6211\u4eec\u5c06\u4f7f\u7528 ASP.NET Core Web \u5e94\u7528\u7a0b\u5e8f \uff08Model-View-Controller\uff09 \u6a21\u677f\u3002\u8981\u5728 Visual Studio \u4e2d\u521b\u5efa\u5e94\u7528\u7a0b\u5e8f\uff0c\u8bf7\u6267\u884c\u4ee5\u4e0b\u6b65\u9aa4\uff1a<\/p>\n<ol>\n<li>Choose File &gt; New.<br \/>\n\u9009\u62e9 File &gt; New \uff08\u6587\u4ef6\u65b0\u5efa\uff09\u3002<\/li>\n<li>In the Create a new project dialog box, select the ASP.NET Core Web App (Model-View-Controller) template.<br \/>\n\u5728 Create a new project \uff08\u521b\u5efa\u65b0\u9879\u76ee\uff09 \u5bf9\u8bdd\u6846\u4e2d\uff0c\u9009\u62e9 ASP.NET Core Web App \uff08Model-View-Controller\uff09 \u6a21\u677f\u3002<\/li>\n<li>In the Create a new project dialog box, enter your project name and review the Additional information box, shown in figure 19.1.<br \/>\n\u5728 Create a new project \u5bf9\u8bdd\u6846\u4e2d\uff0c\u8f93\u5165\u60a8\u7684\u9879\u76ee\u540d\u79f0\u5e76\u67e5\u770b Additional information \u6846\uff0c\u5982\u56fe 19.1 \u6240\u793a\u3002<\/li>\n<li>Choose Create. If you\u2019re using the command-line interface (CLI), you can create a similar template using dotnet new mvc.<br \/>\n\u9009\u62e9 Create \uff08\u521b\u5efa\uff09\u3002\u5982\u679c\u60a8\u4f7f\u7528\u7684\u662f\u547d\u4ee4\u884c\u754c\u9762 \uff08CLI\uff09\uff0c\u5219\u53ef\u4ee5\u4f7f\u7528 dotnet new mvc \u521b\u5efa\u7c7b\u4f3c\u7684\u6a21\u677f\u3002<\/li>\n<\/ol>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1901.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 19.1 The Additional information screen for the MVC template. This screen follows on from the Configure your new project dialog box and lets you customize the template that generates your application.<br \/>\n\u56fe 19.1 MVC \u6a21\u677f\u7684 Additional information \u5c4f\u5e55\u3002\u6b64\u5c4f\u5e55\u662f Configure your new project \u5bf9\u8bdd\u6846\u7684\u540e\u7eed\u5c4f\u5e55\uff0c\u5141\u8bb8\u60a8\u81ea\u5b9a\u4e49\u751f\u6210\u5e94\u7528\u7a0b\u5e8f\u7684\u6a21\u677f\u3002<\/p>\n<p>The MVC template configures the ASP.NET Core project to use MVC controllers with Razor views. As always, you configure your app to use MVC controllers in Program.cs, as shown in listing 19.1. If you compare this template with your Razor Pages projects, you\u2019ll see that the web API project uses AddControllersWithViews() instead of AddRazorPages(). The MVC controllers are mapped as endpoints by calling MapControllerRoute(). This method maps all the controllers in your app and configures a default conventional route for them. We discussed conventional routing in chapter 14, and I will discuss it again briefly shortly.<br \/>\nMVC \u6a21\u677f\u5c06 ASP.NET Core \u9879\u76ee\u914d\u7f6e\u4e3a\u5c06 MVC \u63a7\u5236\u5668\u4e0e Razor \u89c6\u56fe\u4e00\u8d77\u4f7f\u7528\u3002\u4e0e\u5f80\u5e38\u4e00\u6837\uff0c\u60a8\u5c06\u5e94\u7528\u7a0b\u5e8f\u914d\u7f6e\u4e3a\u5728 Program.cs\u4e2d\u4f7f\u7528 MVC \u63a7\u5236\u5668\uff0c\u5982\u6e05\u5355 19.1 \u6240\u793a\u3002\u5982\u679c\u5c06\u6b64\u6a21\u677f\u4e0e Razor Pages \u9879\u76ee\u8fdb\u884c\u6bd4\u8f83\uff0c\u4f60\u5c06\u770b\u5230 Web API \u9879\u76ee\u4f7f\u7528 AddControllersWithViews\uff08\uff09 \u800c\u4e0d\u662f AddRazorPages\uff08\uff09\u3002\u901a\u8fc7\u8c03\u7528 MapControllerRoute\uff08\uff09 \u5c06 MVC \u63a7\u5236\u5668\u6620\u5c04\u4e3a\u7aef\u70b9\u3002\u6b64\u65b9\u6cd5\u6620\u5c04\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u6240\u6709\u63a7\u5236\u5668\uff0c\u5e76\u4e3a\u5b83\u4eec\u914d\u7f6e\u9ed8\u8ba4\u7684\u5e38\u89c4\u8def\u7531\u3002\u6211\u4eec\u5728\u7b2c 14 \u7ae0\u4e2d\u8ba8\u8bba\u4e86 conventional routing\uff0c\u7a0d\u540e\u6211\u5c06\u518d\u6b21\u7b80\u8981\u8ba8\u8bba\u5b83\u3002<\/p>\n<p>Listing 19.1 Program.cs for the default MVC project<br \/>\n\u6e05\u5355 19.1 \u9ed8\u8ba4 MVC \u9879\u76ee\u7684 Program.cs<\/p>\n<pre><code>WebApplicationBuilder builder = WebApplication.CreateBuilder(args);\n\nbuilder.Services.AddControllersWithViews();  #A\n\nWebApplication app = builder.Build();\n\nif (!app.Environment.IsDevelopment())\n{\n    app.UseExceptionHandler(&quot;\/Home\/Error&quot;);  #B\n    app.UseHsts();\n}\n\napp.UseHttpsRedirection();\napp.UseStaticFiles();\napp.UseRouting();\napp.UseAuthorization();\n\napp.MapControllerRoute(    #C\n    name: &quot;default&quot;,    #C\n    pattern: &quot;{controller=Home}\/{action=Index}\/{id?}&quot;);    #D\n\napp.Run();<\/code><\/pre>\n<p>\u2776 AddControllersWithViews adds the services for MVC controllers with Razor Views.<br \/>\nAddControllersWithViews \u4e3a\u5177\u6709 Razor \u89c6\u56fe\u7684 MVC \u63a7\u5236\u5668\u6dfb\u52a0\u4e86\u670d\u52a1\u3002<\/p>\n<p>\u2777 The exception handler path differs from the default Razor Pages path of \/Error.<br \/>\n\u5f02\u5e38\u5904\u7406\u7a0b\u5e8f\u8def\u5f84\u4e0d\u540c\u4e8e\u9ed8\u8ba4\u7684 Razor Pages \u8def\u5f84 \/Error\u3002<br \/>\n\u2778 Adds all MVC controllers in your application using conventional routing<br \/>\n\u4f7f\u7528\u5e38\u89c4\u8def\u7531\u5728\u5e94\u7528\u7a0b\u5e8f\u4e2d\u6dfb\u52a0\u6240\u6709 MVC \u63a7\u5236\u5668<br \/>\n\u2779 Defines the default conventional route pattern<br \/>\n\u5b9a\u4e49\u9ed8\u8ba4\u7684\u5e38\u89c4\u8def\u7531\u6a21\u5f0f<\/p>\n<p>Much of the configuration for an MVC application is the same as for Razor Pages. The middleware configuration is essentially identical, which isn\u2019t that surprising considering that MVC and Razor Pages are the same type of application: a server-rendered app returning HTML. The main difference, as you\u2019ll see in section 19.3, is in the project structure.<br \/>\nMVC \u5e94\u7528\u7a0b\u5e8f\u7684\u5927\u90e8\u5206\u914d\u7f6e\u4e0e Razor Pages \u7684\u914d\u7f6e\u76f8\u540c\u3002\u4e2d\u95f4\u4ef6\u914d\u7f6e\u672c\u8d28\u4e0a\u662f\u76f8\u540c\u7684\uff0c\u8003\u8651\u5230 MVC \u548c Razor Pages \u662f\u540c\u4e00\u7c7b\u578b\u7684\u5e94\u7528\u7a0b\u5e8f\uff1a\u8fd4\u56de HTML \u7684\u670d\u52a1\u5668\u6e32\u67d3\u5e94\u7528\u7a0b\u5e8f\uff0c\u8fd9\u5e76\u4e0d\u5947\u602a\u3002\u6b63\u5982\u60a8\u5c06\u5728 19.3 \u8282\u4e2d\u770b\u5230\u7684\u90a3\u6837\uff0c\u4e3b\u8981\u533a\u522b\u5728\u4e8e\u9879\u76ee\u7ed3\u6784\u3002<\/p>\n<p>Before we go any further, run the MVC application by pressing F5 in Visual Studio or by running dotnet run in the project folder. The application should look remarkably familiar; it\u2019s essentially identical to the Razor Pages version of the application you created in chapter 13, as shown in figure 19.2.<br \/>\n\u5728\u7ee7\u7eed\u4e4b\u524d\uff0c\u8bf7\u5728 Visual Studio \u4e2d\u6309 F5 \u6216\u5728\u9879\u76ee\u6587\u4ef6\u5939\u4e2d\u8fd0\u884c dotnet run \u6765\u8fd0\u884c MVC \u5e94\u7528\u7a0b\u5e8f\u3002\u8be5\u5e94\u7528\u7a0b\u5e8f\u770b\u8d77\u6765\u5e94\u8be5\u975e\u5e38\u719f\u6089;\u5b83\u4e0e\u60a8\u5728\u7b2c 13 \u7ae0\u4e2d\u521b\u5efa\u7684\u5e94\u7528\u7a0b\u5e8f\u7684 Razor Pages \u7248\u672c\u57fa\u672c\u76f8\u540c\uff0c\u5982\u56fe 19.2 \u6240\u793a\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1902.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 19.2 The default MVC application. The resulting application is identical to the Razor Pages equivalent created in chapter 13.<br \/>\n\u56fe 19.2 \u9ed8\u8ba4\u7684 MVC \u5e94\u7528\u7a0b\u5e8f\u3002\u751f\u6210\u7684\u5e94\u7528\u7a0b\u5e8f\u4e0e\u7b2c 13 \u7ae0\u4e2d\u521b\u5efa\u7684 Razor Pages \u7b49\u6548\u9879\u76f8\u540c\u3002<\/p>\n<p>The output of the MVC app is identical to the default Razor Pages app, but the infrastructure used to generate the response differs. Instead of a Razor Page PageModel and page handler, MVC uses the concept of controllers and action methods. The following listing shows the HomeController class from the default application. Each nonabstract, public method is an action that runs in response to a request. You can ensure that a candidate method is not treated as an action method by decorating it with the [NonAction] attribute.<br \/>\nMVC \u5e94\u7528\u7684\u8f93\u51fa\u4e0e\u9ed8\u8ba4\u7684 Razor Pages \u5e94\u7528\u76f8\u540c\uff0c\u4f46\u7528\u4e8e\u751f\u6210\u54cd\u5e94\u7684\u57fa\u7840\u7ed3\u6784\u4e0d\u540c\u3002MVC \u4f7f\u7528\u63a7\u5236\u5668\u548c\u4f5c\u65b9\u6cd5\u7684\u6982\u5ff5\uff0c\u800c\u4e0d\u662f Razor Page PageModel \u548c\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u3002\u4e0b\u9762\u7684\u6e05\u5355\u663e\u793a\u4e86\u9ed8\u8ba4\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684 HomeController \u7c7b\u3002\u6bcf\u4e2a\u975e\u62bd\u8c61\u7684\u516c\u5171\u65b9\u6cd5\u90fd\u662f\u4e3a\u54cd\u5e94\u8bf7\u6c42\u800c\u8fd0\u884c\u7684\u4f5c\u3002\u60a8\u53ef\u4ee5\u901a\u8fc7\u4f7f\u7528 [NonAction] \u5c5e\u6027\u4fee\u9970\u5019\u9009\u65b9\u6cd5\uff0c\u786e\u4fdd\u5b83\u4e0d\u4f1a\u88ab\u89c6\u4e3a\u4f5c\u65b9\u6cd5\u3002<\/p>\n<p>Listing 19.2 The HomeController for the default MVC app<br \/>\n\u6e05\u5355 19.2 \u9ed8\u8ba4 MVC \u5e94\u7528\u7684 HomeController<\/p>\n<pre><code>public class HomeController : Controller  #A\n{\n    private readonly ILogger&lt;HomeController&gt; _logger;\n    public HomeController(Ilogger&lt;HomeController&gt; logger)\n    {\n        _logger = logger;\n    }\n\n    public IactionResult Index()  #B\n    {\n        return View();  #C\n    }\n\n    public IactionResult Privacy()\n    {\n        return View();\n    }\n\n    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None,  #D\n         NoStore = true)]    #D\n    public IactionResult Error()\n    {\n        return View(new ErrorViewModel      #E\n        {       #E\n            RequestId = Activity.Current?.Id     #E\n                ?? HttpContext.TraceIdentifier     #E\n        });    #E\n    }\n}<\/code><\/pre>\n<p>\u2776 MVC Controllers often inherit from the Controller base class.<br \/>\nMVC \u63a7\u5236\u5668\u901a\u5e38\u7ee7\u627f\u81ea Controller \u57fa\u7c7b\u3002<br \/>\n\u2777 Action methods are the endpoints that run in response to requests.<br \/>\nAction methods \u662f\u4e3a\u54cd\u5e94\u8bf7\u6c42\u800c\u8fd0\u884c\u7684\u7aef\u70b9\u3002<br \/>\n\u2778 Returning View() renders a Razor view.<br \/>\n\u8fd4\u56de View\uff08\uff09 \u4f1a\u5448\u73b0 Razor \u89c6\u56fe\u3002<br \/>\n\u2779 You can apply filters to actions, as you\u2019ll learn in chapters 21 and 22.<br \/>\n\u60a8\u53ef\u4ee5\u5c06\u8fc7\u6ee4\u5668\u5e94\u7528\u4e8e\u4f5c\uff0c\u60a8\u5c06\u5728\u7b2c 21 \u7ae0\u548c\u7b2c 22 \u7ae0\u4e2d\u5b66\u5230\u3002<br \/>\n\u277a Any object returned with View is passed to the Razor view as a view model.<br \/>\n\u4f7f\u7528 View \u8fd4\u56de\u7684\u4efb\u4f55\u5bf9\u8c61\u90fd\u5c06\u4f5c\u4e3a\u89c6\u56fe\u6a21\u578b\u4f20\u9012\u7ed9 Razor \u89c6\u56fe\u3002<\/p>\n<p><b>DEFINITION<\/b> An action (or action method) is a method that runs in response to a request. An MVC controller is a class that contains one or more logically grouped action methods.<br \/>\n\u5b9a\u4e49:\u4e00\u4e2a\u64cd\u4f5c \uff08\u6216\u4f5c\u65b9\u6cd5\uff09 \u662f\u4e3a\u54cd\u5e94\u8bf7\u6c42\u800c\u8fd0\u884c\u7684\u65b9\u6cd5\u3002MVC \u63a7\u5236\u5668\u662f\u5305\u542b\u4e00\u4e2a\u6216\u591a\u4e2a\u903b\u8f91\u5206\u7ec4\u7684\u4f5c\u65b9\u6cd5\u7684\u7c7b\u3002<\/p>\n<p>Each of the three action methods calls View() and returns the result. This returns a ViewResult, which instructs the MVC framework to render a Razor view for the action. You\u2019ll learn more about this process in section 19.4. The Error action method also sets an object in the call to View(). This is the view model, which is passed to the Razor view when it\u2019s rendered.<br \/>\n\u8fd9\u4e09\u4e2a\u4f5c\u65b9\u6cd5\u4e2d\u7684\u6bcf\u4e00\u4e2a\u90fd\u8c03\u7528 View\uff08\uff09 \u5e76\u8fd4\u56de\u7ed3\u679c\u3002\u8fd9\u5c06\u8fd4\u56de\u4e00\u4e2a ViewResult\uff0c\u5b83\u6307\u793a MVC \u6846\u67b6\u4e3a\u4f5c\u5448\u73b0 Razor \u89c6\u56fe\u3002\u60a8\u5c06\u5728 Section 19.4 \u4e2d\u4e86\u89e3\u6709\u5173\u6b64\u8fc7\u7a0b\u7684\u66f4\u591a\u4fe1\u606f\u3002Error\u4f5c\u65b9\u6cd5\u8fd8\u4f1a\u5728\u5bf9 View\uff08\uff09 \u7684\u8c03\u7528\u4e2d\u8bbe\u7f6e\u4e00\u4e2a\u5bf9\u8c61\u3002\u8fd9\u662f\u89c6\u56fe\u6a21\u578b\uff0c\u5728\u5448\u73b0\u89c6\u56fe\u65f6\u4f20\u9012\u7ed9 Razor \u89c6\u56fe\u3002<\/p>\n<p><b>NOTE<\/b> MVC controllers use explicit view models to pass data to a Razor view rather than expose the data as properties on themselves (as Razor Pages do with page models). This provides a clearer separation between the various \u201cmodels\u201d than in Razor Pages, though both Razor Pages cases use the same general MVC design pattern.<br \/>\n\u6ce8\u610f\uff1aMVC \u63a7\u5236\u5668\u4f7f\u7528\u663e\u5f0f\u89c6\u56fe\u6a21\u578b\u5c06\u6570\u636e\u4f20\u9012\u5230 Razor \u89c6\u56fe\uff0c\u800c\u4e0d\u662f\u5c06\u6570\u636e\u4f5c\u4e3a\u81ea\u8eab\u7684\u5c5e\u6027\u516c\u5f00\uff08\u5c31\u50cf Razor \u9875\u9762\u5bf9\u9875\u9762\u6a21\u578b\u6240\u505a\u7684\u90a3\u6837\uff09\u3002\u4e0e Razor Pages \u76f8\u6bd4\uff0c\u8fd9\u5728\u5404\u79cd\u201c\u6a21\u578b\u201d\u4e4b\u95f4\u63d0\u4f9b\u4e86\u66f4\u6e05\u6670\u7684\u5206\u79bb\uff0c\u5c3d\u7ba1\u4e24\u79cd Razor Pages \u60c5\u51b5\u90fd\u4f7f\u7528\u76f8\u540c\u7684\u901a\u7528 MVC \u8bbe\u8ba1\u6a21\u5f0f\u3002<\/p>\n<p>Another big difference between Razor Pages and MVC controllers is that MVC controllers typically use conventional routing, as opposed to the explicit routing used by Razor Pages. I touched on conventional routing and how it differs from explicit routing in chapter 14, but you can see it in action in this MVC application.<br \/>\nRazor Pages \u548c MVC \u63a7\u5236\u5668\u4e4b\u95f4\u7684\u53e6\u4e00\u4e2a\u91cd\u5927\u533a\u522b\u662f\uff0cMVC \u63a7\u5236\u5668\u901a\u5e38\u4f7f\u7528\u4f20\u7edf\u8def\u7531\uff0c\u800c\u4e0d\u662f Razor Pages \u4f7f\u7528\u7684\u663e\u5f0f\u8def\u7531\u3002\u6211\u5728\u7b2c 14 \u7ae0\u4e2d\u8c08\u5230\u4e86\u4f20\u7edf\u8def\u7531\u4ee5\u53ca\u5b83\u4e0e\u663e\u5f0f\u8def\u7531\u7684\u4e0d\u540c\u4e4b\u5904\uff0c\u4f46\u60a8\u53ef\u4ee5\u5728\u6b64 MVC \u5e94\u7528\u7a0b\u5e8f\u4e2d\u770b\u5230\u5b83\u7684\u5b9e\u9645\u5e94\u7528\u3002<\/p>\n<p>Conventional routing defines one or more route template patterns, which are used for all the MVC controllers in your app. The default route template, shown in listing 19.1, consists of three optional segments:<br \/>\n\u4f20\u7edf\u8def\u7531\u5b9a\u4e49\u4e00\u4e2a\u6216\u591a\u4e2a\u8def\u7531\u6a21\u677f\u6a21\u5f0f\uff0c\u8fd9\u4e9b\u6a21\u5f0f\u7528\u4e8e\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u6240\u6709 MVC \u63a7\u5236\u5668\u3002\u9ed8\u8ba4\u8def\u7531\u6a21\u677f\uff0c\u5982\u6e05\u5355 19.1 \u6240\u793a\uff0c\u7531\u4e09\u4e2a\u53ef\u9009\u6bb5\u7ec4\u6210\uff1a<\/p>\n<pre><code>&quot;{controller=Home}\/{action=Index}\/{id?}&quot;<\/code><\/pre>\n<p>Conventional routes must describe which controller and action should run for any given request, so they must include controller and action route parameters at a minimum. When a request is received, ASP.NET Core matches the route template and from that calculates which MVC controller and action method to use. For example, the default route would match all the following URLs:<br \/>\n\u4f20\u7edf\u8def\u7531\u5fc5\u987b\u63cf\u8ff0\u5e94\u8be5\u4e3a\u4efb\u4f55\u7ed9\u5b9a\u8bf7\u6c42\u8fd0\u884c\u54ea\u4e2a\u63a7\u5236\u5668\u548c\u4f5c\uff0c\u56e0\u6b64\u5b83\u4eec\u5fc5\u987b\u81f3\u5c11\u5305\u542b\u63a7\u5236\u5668\u548c\u4f5c\u8def\u7531\u53c2\u6570\u3002\u6536\u5230\u8bf7\u6c42\u65f6\uff0cASP.NET Core \u4f1a\u5339\u914d\u8def\u7531\u6a21\u677f\uff0c\u5e76\u4ece\u4e2d\u8ba1\u7b97\u8981\u4f7f\u7528\u7684 MVC \u63a7\u5236\u5668\u548c\u4f5c\u65b9\u6cd5\u3002\u4f8b\u5982\uff0c\u9ed8\u8ba4\u8def\u7531\u5c06\u5339\u914d\u4ee5\u4e0b\u6240\u6709 URL\uff1a<\/p>\n<p>\u2022  \/Home\/Privacy \u2014 Executes the HomeController.Privacy() action<br \/>\n\u2022  \/Home \u2014 Executes the HomeController.Index() action<br \/>\n\u2022  \/customer\/list \u2014 Executes the CustomerController.List() action<br \/>\n\u2022  \/products\/view\/123 \u2014 Executes the ProductsController.View() action, with the route parameter id=123<\/p>\n<p>With conventional routing, a single route template maps to multiple endpoints, whereas in explicit routing, one or more route templates typically map to a single endpoint. There are subtleties in both cases, but in general conventional routing is terser, and explicit routing is more expressive.<br \/>\n\u4f7f\u7528\u4f20\u7edf\u8def\u7531\u65f6\uff0c\u5355\u4e2a\u8def\u7531\u6a21\u677f\u6620\u5c04\u5230\u591a\u4e2a\u7ec8\u7aef\u8282\u70b9\uff0c\u800c\u5728\u663e\u5f0f\u8def\u7531\u4e2d\uff0c\u4e00\u4e2a\u6216\u591a\u4e2a\u8def\u7531\u6a21\u677f\u901a\u5e38\u6620\u5c04\u5230\u5355\u4e2a\u7ec8\u7aef\u8282\u70b9\u3002\u8fd9\u4e24\u79cd\u60c5\u51b5\u90fd\u6709\u5fae\u5999\u4e4b\u5904\uff0c\u4f46\u901a\u5e38 conventional routing \u66f4\u7b80\u6d01\uff0c\u800c explicit routing \u66f4\u5177\u8868\u73b0\u529b\u3002<\/p>\n<p><b>NOTE<\/b> As I mentioned in chapter 14, I won\u2019t discuss conventional routing any further in this book. It is often used only with MVC controllers, but even then, I generally prefer to use explicit routing with attributes. I describe how to use attribute routing in chapter 20 when I discuss web API controllers.<br \/>\n\u6ce8\u610f\uff1a\u6b63\u5982\u6211\u5728\u7b2c 14 \u7ae0\u4e2d\u63d0\u5230\u7684\uff0c\u6211\u4e0d\u4f1a\u5728\u672c\u4e66\u4e2d\u8fdb\u4e00\u6b65\u8ba8\u8bba conventional routing\u3002\u5b83\u901a\u5e38\u53ea\u4e0e MVC \u63a7\u5236\u5668\u4e00\u8d77\u4f7f\u7528\uff0c\u4f46\u5373\u4fbf\u5982\u6b64\uff0c\u6211\u901a\u5e38\u66f4\u559c\u6b22\u4f7f\u7528\u5e26\u6709\u5c5e\u6027\u7684\u663e\u5f0f\u8def\u7531\u3002\u5728\u7b2c 20 \u7ae0\u4e2d\u8ba8\u8bba Web API \u63a7\u5236\u5668\u65f6\uff0c\u6211\u5c06\u4ecb\u7ecd\u5982\u4f55\u4f7f\u7528\u5c5e\u6027\u8def\u7531\u3002<\/p>\n<p>Once you\u2019ve familiarized yourself with a basic MVC application you will likely have spotted many of the similarities and differences between the MVC framework and Razor Pages. In the next section we look at one aspect of this: MVC controllers and their Razor Page PageModel equivalent.<br \/>\n\u719f\u6089\u57fa\u672c\u7684 MVC \u5e94\u7528\u7a0b\u5e8f\u540e\uff0c\u60a8\u53ef\u80fd\u5df2\u7ecf\u53d1\u73b0\u4e86 MVC \u6846\u67b6\u548c Razor Pages \u4e4b\u95f4\u7684\u8bb8\u591a\u76f8\u4f3c\u4e4b\u5904\u548c\u4e0d\u540c\u4e4b\u5904\u3002\u5728\u4e0b\u4e00\u90e8\u5206\u4e2d\uff0c\u6211\u4eec\u5c06\u4ecb\u7ecd\u5176\u4e2d\u4e00\u4e2a\u65b9\u9762\uff1aMVC \u63a7\u5236\u5668\u53ca\u5176 Razor Page PageModel \u7b49\u6548\u9879\u3002<\/p>\n<h2>19.3 Comparing an MVC controller with a Razor Page PageModel<\/h2>\n<p>19.3 \u5c06 MVC \u63a7\u5236\u5668\u4e0e Razor Page PageModel \u8fdb\u884c\u6bd4\u8f83<\/p>\n<p>In chapter 13 we looked at the MVC design pattern, and at how it applies to Razor Pages in ASP.NET Core. Perhaps unsurprisingly, you can use MVC controllers with the MVC design pattern in almost exactly the same way.<br \/>\n\u5728\u7b2c 13 \u7ae0\u4e2d\uff0c\u6211\u4eec\u4e86\u89e3\u4e86 MVC \u8bbe\u8ba1\u6a21\u5f0f\uff0c\u4ee5\u53ca\u5b83\u5982\u4f55\u5e94\u7528\u4e8e ASP.NET Core \u4e2d\u7684 Razor \u9875\u9762\u3002\u4e5f\u8bb8\u4e0d\u8db3\u4e3a\u5947\u7684\u662f\uff0c\u60a8\u53ef\u4ee5\u4ee5\u51e0\u4e4e\u5b8c\u5168\u76f8\u540c\u7684\u65b9\u5f0f\u5c06 MVC \u63a7\u5236\u5668\u4e0e MVC \u8bbe\u8ba1\u6a21\u5f0f\u4e00\u8d77\u4f7f\u7528\u3002<\/p>\n<p>As mentioned in section 19.2, MVC controllers and actions are analogous to their Razor Pages counterparts of PageModel and page handlers. Figure 19.3 makes this clearer; it is the MVC controller equivalent of the Razor Pages version from chapter 13.<br \/>\n\u5982\u7b2c 19.2 \u8282\u6240\u8ff0\uff0cMVC \u63a7\u5236\u5668\u548c\u4f5c\u7c7b\u4f3c\u4e8e PageModel \u548c\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u7684 Razor Pages \u5bf9\u5e94\u9879\u3002\u56fe 19.3 \u66f4\u6e05\u695a\u5730\u8bf4\u660e\u4e86\u8fd9\u4e00\u70b9;\u5b83\u662f\u7b2c 13 \u7ae0\u4e2d Razor Pages \u7248\u672c\u7684 MVC \u63a7\u5236\u5668\u7b49\u6548\u9879\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1903.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 19.3 A complete MVC controller request for a category. The MVC controller pattern is almost identical to that of Razor Pages, which was shown in figure 13.12. The controller is equivalent to a Razor Page, and the action is equivalent to a page handler.<br \/>\n\u56fe 19.3 \u7c7b\u522b\u7684\u5b8c\u6574 MVC \u63a7\u5236\u5668\u8bf7\u6c42\u3002MVC \u63a7\u5236\u5668\u6a21\u5f0f\u4e0e Razor Pages \u7684\u6a21\u5f0f\u51e0\u4e4e\u76f8\u540c\uff0c\u5982\u56fe 13.12 \u6240\u793a\u3002\u63a7\u5236\u5668\u7b49\u6548\u4e8e Razor Page\uff0c\u4f5c\u7b49\u6548\u4e8e\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u3002<\/p>\n<p>In chapter 13 I showed a simple Razor Page PageModel for displaying all the to-do items in a given category in a ToDO application. The following listing reproduces that Razor Pages code from listing 13.5 for convenience.<br \/>\n\u5728\u7b2c 13 \u7ae0\u4e2d\uff0c\u6211\u5c55\u793a\u4e86\u4e00\u4e2a\u7b80\u5355\u7684 Razor Page PageModel\uff0c\u7528\u4e8e\u5728 ToDO \u5e94\u7528\u7a0b\u5e8f\u4e2d\u663e\u793a\u7ed9\u5b9a\u7c7b\u522b\u4e2d\u7684\u6240\u6709\u5f85\u529e\u4e8b\u9879\u3002\u4e3a\u65b9\u4fbf\u8d77\u89c1\uff0c\u4ee5\u4e0b\u6e05\u5355\u590d\u5236\u4e86\u6e05\u5355 13.5 \u4e2d\u7684 Razor Pages \u4ee3\u7801\u3002<\/p>\n<p>Listing 19.3 A Razor Page for viewing all to-do items in a given category<br \/>\n\u6e05\u5355 19.3 \u7528\u4e8e\u67e5\u770b\u7ed9\u5b9a\u7c7b\u522b\u4e2d\u6240\u6709\u5f85\u529e\u4e8b\u9879\u7684 Razor \u9875\u9762<\/p>\n<pre><code>public class CategoryModel : PageModel\n{\n    private readonly ToDoService _service;\n    public CategoryModel(ToDoService service)\n    {\n        _service = service;\n    }\n\n    public ActionResult OnGet(string category)\n    {\n        Items = _service.GetItemsForCategory(category);\n        return Page();\n    }\n\n    public List&lt;ToDoListModel&gt; Items { get; set; }\n}<\/code><\/pre>\n<p>The MVC equivalent of this Razor Page is shown in listing 19.4. In the MVC framework, controllers are often used to aggregate similar actions, so the controller in this case is called ToDoController, as it would typically contain additional action methods for working with to-do items, such as actions to view a specific item or to create a new one.<br \/>\n\u6b64 Razor Page \u7684 MVC \u7b49\u6548\u9879\u663e\u793a\u5728\u6e05\u5355 19.4 \u4e2d\u3002\u5728 MVC \u6846\u67b6\u4e2d\uff0c\u63a7\u5236\u5668\u901a\u5e38\u7528\u4e8e\u805a\u5408\u7c7b\u4f3c\u7684\u4f5c\uff0c\u56e0\u6b64\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u63a7\u5236\u5668\u79f0\u4e3a ToDoController\uff0c\u56e0\u4e3a\u5b83\u901a\u5e38\u5305\u542b\u7528\u4e8e\u5904\u7406\u5f85\u529e\u4e8b\u9879\u7684\u5176\u4ed6\u4f5c\u65b9\u6cd5\uff0c\u4f8b\u5982\u67e5\u770b\u7279\u5b9a\u9879\u6216\u521b\u5efa\u65b0\u9879\u7684\u4f5c\u3002<\/p>\n<p>Listing 19.4 An MVC controller for viewing all to-do items in a given category<br \/>\n\u6e05\u5355 19.4 \u4e00\u4e2a MVC \u63a7\u5236\u5668\uff0c\u7528\u4e8e\u67e5\u770b\u7ed9\u5b9a\u7c7b\u522b\u4e2d\u7684\u6240\u6709\u5f85\u529e\u4e8b\u9879<\/p>\n<pre><code>public class ToDoController : Controller\n{\n    private readonly ToDoService _service;       #A\n    public ToDoController(ToDoService service)   #A\n    {\n        _service = service;\n    }\n\n    public ActionResult Category(string id)     #B\n    {\n        var items = _service.GetItemsForCategory(id);     #C\n        return View(items);    #D\n    }\n\n    public ActionResult Create(ToDoListModel model)   #E\n    {                                                 #E\n        \/\/ ...                                        #E\n    }                                                 #E\n}<\/code><\/pre>\n<p>\u2776 The ToDoService is provided in the controller constructor using dependency injection.<br \/>\nToDoService \u4f7f\u7528\u4f9d\u8d56\u9879\u6ce8\u5165\u5728\u63a7\u5236\u5668\u6784\u9020\u51fd\u6570\u4e2d\u63d0\u4f9b\u3002<br \/>\n\u2777 The Category action method takes a parameter, id.<br \/>\nCategory\u4f5c\u65b9\u6cd5\u91c7\u7528\u53c2\u6570 id\u3002<br \/>\n\u2778 The action method calls out to the ToDoService to retrieve data and build a view model.<br \/>\n\u65b9\u6cd5\u8c03\u7528 ToDoService \u4ee5\u68c0\u7d22\u6570\u636e\u5e76\u6784\u5efa\u89c6\u56fe\u6a21\u578b\u3002<br \/>\n\u2779 Returns a ViewResult indicating the Razor view should be rendered, passing in the view model<br \/>\n\u8fd4\u56de\u4e00\u4e2a ViewResult\uff0c\u6307\u793a\u5e94\u5448\u73b0 Razor \u89c6\u56fe\uff0c\u4f20\u5165\u89c6\u56fe\u6a21\u578b<br \/>\n\u277a MVC controllers often contain multiple action methods that respond to different requests.<br \/>\nMVC \u63a7\u5236\u5668\u901a\u5e38\u5305\u542b\u591a\u4e2a\u54cd\u5e94\u4e0d\u540c\u8bf7\u6c42\u7684\u4f5c\u65b9\u6cd5\u3002<\/p>\n<p>Aside from some naming differences, the ToDoController looks similar to the Razor Page equivalent from listing 19.3:<br \/>\n\u9664\u4e86\u4e00\u4e9b\u547d\u540d\u5dee\u5f02\u4e4b\u5916\uff0cToDoController \u770b\u8d77\u6765\u7c7b\u4f3c\u4e8e\u6e05\u5355 19.3 \u4e2d\u7684 Razor Page \u7b49\u6548\u9879\uff1a<\/p>\n<p>\u2022  They both use dependency injection to access services.<br \/>\n\u5b83\u4eec\u90fd\u4f7f\u7528\u4f9d\u8d56\u5173\u7cfb\u6ce8\u5165\u6765\u8bbf\u95ee\u670d\u52a1\u3002<br \/>\n\u2022  Both handlers (page handler and action method) accept parameters created using model binding in exactly the same way.<br \/>\n\u4e24\u4e2a\u5904\u7406\u7a0b\u5e8f \uff08\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u548c\u4f5c\u65b9\u6cd5\uff09 \u90fd\u4ee5\u5b8c\u5168\u76f8\u540c\u7684\u65b9\u5f0f\u63a5\u53d7\u4f7f\u7528\u6a21\u578b\u7ed1\u5b9a\u521b\u5efa\u7684\u53c2\u6570\u3002<br \/>\n\u2022  Both interact with the application model in the same way to handle the request.<br \/>\n\u4e24\u8005\u4ee5\u76f8\u540c\u7684\u65b9\u5f0f\u4e0e\u5e94\u7528\u7a0b\u5e8f\u6a21\u578b\u4ea4\u4e92\u4ee5\u5904\u7406\u8bf7\u6c42\u3002<br \/>\n\u2022  They both create a view model for rendering the Razor view.<br \/>\n\u5b83\u4eec\u90fd\u521b\u5efa\u7528\u4e8e\u6e32\u67d3 Razor \u89c6\u56fe\u7684\u89c6\u56fe\u6a21\u578b\u3002<\/p>\n<p>One of the main differences between Razor Pages and MVC controllers is in the final step: rendering the Razor view. In the next section you\u2019ll see how to render Razor views from your MVC controller actions, how the views differ from the Razor views you\u2019ve seen with Razor Pages, and how the framework locates the correct Razor view to render.<br \/>\nRazor Pages \u548c MVC \u63a7\u5236\u5668\u4e4b\u95f4\u7684\u4e3b\u8981\u533a\u522b\u4e4b\u4e00\u662f\u6700\u540e\u4e00\u6b65\uff1a\u5448\u73b0 Razor \u89c6\u56fe\u3002\u5728\u4e0b\u4e00\u90e8\u5206\u4e2d\uff0c\u4f60\u5c06\u4e86\u89e3\u5982\u4f55\u4ece MVC \u63a7\u5236\u5668\u4f5c\u5448\u73b0 Razor \u89c6\u56fe\uff0c\u8fd9\u4e9b\u89c6\u56fe\u4e0e\u4f7f\u7528 Razor \u9875\u9762\u770b\u5230\u7684 Razor \u89c6\u56fe\u6709\u4f55\u4e0d\u540c\uff0c\u4ee5\u53ca\u6846\u67b6\u5982\u4f55\u627e\u5230\u8981\u5448\u73b0\u7684\u6b63\u786e Razor \u89c6\u56fe\u3002<\/p>\n<h2>19.4 Selecting a view from an MVC controller<\/h2>\n<p>19.4 \u4ece MVC \u63a7\u5236\u5668\u4e2d\u9009\u62e9\u89c6\u56fe<\/p>\n<p>This section covers<br \/>\n\u672c\u8282\u6db5\u76d6<br \/>\n\u2022  How MVC controllers use ViewResults to render Razor views<br \/>\nMVC \u63a7\u5236\u5668\u5982\u4f55\u4f7f\u7528 ViewResults \u5448\u73b0 Razor \u89c6\u56fe<br \/>\n\u2022  How to create a new Razor view<br \/>\n\u5982\u4f55\u521b\u5efa\u65b0\u7684 Razor \u89c6\u56fe<br \/>\n\u2022  How the framework locates a Razor view to render<br \/>\n\u6846\u67b6\u5982\u4f55\u67e5\u627e\u8981\u5448\u73b0\u7684 Razor \u89c6\u56fe<\/p>\n<p>One of the major differences between MVC controllers and Razor Pages is how the page handler or action method chooses a Razor view to render. For Razor Pages, it\u2019s easy; the page renders the Razor view associated with the page. For MVC controllers it\u2019s more complicated, so it\u2019s important to understand how you choose which view to render once an action method has executed. Figure 19.4 shows a zoomed-in view of this process, right after the action has invoked the application model and received some data back.<br \/>\nMVC \u63a7\u5236\u5668\u548c Razor Pages \u4e4b\u95f4\u7684\u4e3b\u8981\u533a\u522b\u4e4b\u4e00\u662f\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u6216\u4f5c\u65b9\u6cd5\u5982\u4f55\u9009\u62e9\u8981\u5448\u73b0\u7684 Razor \u89c6\u56fe\u3002\u5bf9\u4e8e Razor Pages\uff0c\u8fd9\u5f88\u5bb9\u6613;\u9875\u9762\u5448\u73b0\u4e0e\u9875\u9762\u5173\u8054\u7684 Razor \u89c6\u56fe\u3002\u5bf9\u4e8e MVC \u63a7\u5236\u5668\uff0c\u60c5\u51b5\u66f4\u590d\u6742\uff0c\u56e0\u6b64\u4e86\u89e3\u5728\u6267\u884c\u4f5c\u65b9\u6cd5\u540e\u5982\u4f55\u9009\u62e9\u8981\u5448\u73b0\u7684\u89c6\u56fe\u975e\u5e38\u91cd\u8981\u3002\u56fe 19.4 \u663e\u793a\u4e86\u6b64\u8fc7\u7a0b\u7684\u653e\u5927\u89c6\u56fe\uff0c\u8be5\u89c6\u56fe\u662f\u5728 action \u8c03\u7528\u5e94\u7528\u7a0b\u5e8f\u6a21\u578b\u5e76\u63a5\u6536\u4e00\u4e9b\u6570\u636e\u4e4b\u540e\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1904.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 19.4 The process of generating HTML from an MVC controller using a ViewResult. This is similar to the process for a Razor Page. The main difference is that for Razor Pages, the view is an integral part of the Razor Page; for MVC controllers, the view must be located at runtime.<br \/>\n\u56fe 19.4 \u4f7f\u7528 ViewResult \u4ece MVC \u63a7\u5236\u5668\u751f\u6210 HTML \u7684\u8fc7\u7a0b\u3002\u8fd9\u7c7b\u4f3c\u4e8e Razor \u9875\u9762\u7684\u8fc7\u7a0b\u3002\u4e3b\u8981\u533a\u522b\u5728\u4e8e\uff0c\u5bf9\u4e8e Razor Pages\uff0c\u89c6\u56fe\u662f Razor Page \u4e0d\u53ef\u6216\u7f3a\u7684\u4e00\u90e8\u5206;\u5bf9\u4e8e MVC \u63a7\u5236\u5668\uff0c\u89c6\u56fe\u5fc5\u987b\u4f4d\u4e8e\u8fd0\u884c\u65f6\u3002<\/p>\n<p>Some of this figure should be familiar; it\u2019s the bottom half of figure 19.3 (with a couple of additions). It shows that the MVC controller action method uses a ViewResult object to indicate that a Razor view should be rendered. This ViewResult contains the name of the Razor view template to render and a view model, an arbitrary plain old CLR object (POCO) class containing the data to render.<br \/>\n\u8fd9\u4e2a\u4eba\u7269\u4e2d\u7684\u4e00\u4e9b\u4eba\u5e94\u8be5\u5f88\u719f\u6089;\u5b83\u662f\u56fe 19.3 \u7684\u4e0b\u534a\u90e8\u5206\uff08\u6dfb\u52a0\u4e86\u4e00\u4e9b\u5185\u5bb9\uff09\u3002\u5b83\u663e\u793a MVC \u63a7\u5236\u5668\u4f5c\u65b9\u6cd5\u4f7f\u7528 ViewResult \u5bf9\u8c61\u6765\u6307\u793a\u5e94\u5448\u73b0 Razor \u89c6\u56fe\u3002\u6b64 ViewResult \u5305\u542b\u8981\u5448\u73b0\u7684 Razor \u89c6\u56fe\u6a21\u677f\u7684\u540d\u79f0\uff0c\u4ee5\u53ca\u89c6\u56fe\u6a21\u578b\uff0c\u5373\u5305\u542b\u8981\u5448\u73b0\u7684\u6570\u636e\u7684\u4efb\u610f\u666e\u901a\u65e7 CLR \u5bf9\u8c61 \uff08POCO\uff09 \u7c7b\u3002<\/p>\n<p><b>NOTE<\/b> ViewResult is the MVC equivalent of a Razor Page\u2019s PageResult. The main difference is that a ViewResult includes a view name to render and a model to pass to the view template, while a PageResult always renders the Razor Page\u2019s associated view and always passes the PageModel to the view template.<br \/>\n\u6ce8\u610f\uff1aViewResult \u662f Razor \u9875\u9762\u7684 PageResult \u7684 MVC \u7b49\u6548\u9879\u3002\u4e3b\u8981\u533a\u522b\u5728\u4e8e ViewResult \u5305\u62ec\u8981\u5448\u73b0\u7684\u89c6\u56fe\u540d\u79f0\u548c\u8981\u4f20\u9012\u7ed9\u89c6\u56fe\u6a21\u677f\u7684\u6a21\u578b\uff0c\u800c PageResult \u59cb\u7ec8\u5448\u73b0 Razor Page \u7684\u5173\u8054\u89c6\u56fe\uff0c\u5e76\u59cb\u7ec8\u5c06 PageModel \u4f20\u9012\u7ed9\u89c6\u56fe\u6a21\u677f\u3002<\/p>\n<p>After returning a ViewResult from an action method, the control flow passes back to the MVC framework, which uses a series of heuristics to locate the view, based on the template name provided. Once it locates the Razor view template, the Razor engine passes the view model from the ViewResult to the view and executes the template to generate the final HTML. This final step, rendering the HTML, is essentially the same process as for Razor Pages.<br \/>\n\u4ece\u4f5c\u65b9\u6cd5\u8fd4\u56de ViewResult \u540e\uff0c\u63a7\u5236\u6d41\u5c06\u4f20\u9012\u56de MVC \u6846\u67b6\uff0c\u8be5\u6846\u67b6\u6839\u636e\u63d0\u4f9b\u7684\u6a21\u677f\u540d\u79f0\u4f7f\u7528\u4e00\u7cfb\u5217\u542f\u53d1\u5f0f\u65b9\u6cd5\u6765\u67e5\u627e\u89c6\u56fe\u3002\u627e\u5230 Razor \u89c6\u56fe\u6a21\u677f\u540e\uff0cRazor \u5f15\u64ce\u4f1a\u5c06\u89c6\u56fe\u6a21\u578b\u4ece ViewResult \u4f20\u9012\u5230\u89c6\u56fe\uff0c\u5e76\u6267\u884c\u6a21\u677f\u4ee5\u751f\u6210\u6700\u7ec8 HTML\u3002\u6700\u540e\u4e00\u6b65\uff08\u5448\u73b0 HTML\uff09\u4e0e Razor Pages \u7684\u8fc7\u7a0b\u57fa\u672c\u76f8\u540c\u3002<\/p>\n<p>You can add a new Razor view template to your application in Visual Studio by right-clicking the folder you wish to add the view to in Solution Explorer. Choose <code>Add &gt; New Item<\/code> and then select Razor View - Empty from the dialog, as shown in figure 19.5. If you aren\u2019t using Visual Studio, create a blank new file in the Views folder with the file extension .cshtml.<br \/>\n\u901a\u8fc7\u5728\u89e3\u51b3\u65b9\u6848\u8d44\u6e90\u7ba1\u7406\u5668\u4e2d\u53f3\u952e\u5355\u51fb\u8981\u5411\u5176\u6dfb\u52a0\u89c6\u56fe\u7684\u6587\u4ef6\u5939\uff0c\u53ef\u4ee5\u5728 Visual Studio \u4e2d\u5c06\u65b0\u7684 Razor \u89c6\u56fe\u6a21\u677f\u6dfb\u52a0\u5230\u5e94\u7528\u7a0b\u5e8f\u4e2d\u3002\u4ece\u5bf9\u8bdd\u6846\u4e2d\u9009\u62e9<code>Add &gt; New Item<\/code> \u5e76\u9009\u62e9 Razor View - Empty\uff0c\u5982\u56fe 19.5 \u6240\u793a\u3002\u5982\u679c\u4e0d\u4f7f\u7528 Visual Studio\uff0c\u8bf7\u5728 Views \u6587\u4ef6\u5939\u4e2d\u521b\u5efa\u4e00\u4e2a\u6587\u4ef6\u6269\u5c55\u540d\u4e3a .cshtml \u7684\u7a7a\u767d\u65b0\u6587\u4ef6\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1905.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 19.5 The Add New Item dialog box. Choosing Razor View - Empty adds a new Razor view template file to your application.<br \/>\n\u56fe 19.5 \u201c\u6dfb\u52a0\u65b0\u9879\u201d\u5bf9\u8bdd\u6846\u3002\u9009\u62e9\u201cRazor \u89c6\u56fe - \u7a7a\u201d\u4f1a\u5c06\u65b0\u7684 Razor \u89c6\u56fe\u6a21\u677f\u6587\u4ef6\u6dfb\u52a0\u5230\u5e94\u7528\u7a0b\u5e8f\u4e2d\u3002<\/p>\n<p>Razor view files are almost identical to the Razor Page .cshtml files you saw in chapter 17. The only difference is that Razor view files must not specify a @page directive at the top of the file. Aside from that, they\u2019re identical; you can use the same syntax, partial views, layouts, and view models as you can with Razor Pages. The following listing, for example, shows part of the Error.cshtml Razor view for the default MVC template. This is all recognizable as standard Razor syntax.<br \/>\nRazor \u89c6\u56fe\u6587\u4ef6\u4e0e\u4f60\u5728\u7b2c 17 \u7ae0\u4e2d\u770b\u5230\u7684 Razor Page .cshtml \u6587\u4ef6\u51e0\u4e4e\u76f8\u540c\u3002\u552f\u4e00\u7684\u533a\u522b\u662f Razor \u89c6\u56fe\u6587\u4ef6\u4e0d\u5f97\u5728\u6587\u4ef6\u9876\u90e8\u6307\u5b9a @page \u6307\u4ee4\u3002\u9664\u6b64\u4e4b\u5916\uff0c\u5b83\u4eec\u662f\u76f8\u540c\u7684;\u60a8\u53ef\u4ee5\u4f7f\u7528\u4e0e Razor Pages \u76f8\u540c\u7684\u8bed\u6cd5\u3001\u5206\u90e8\u89c6\u56fe\u3001\u5e03\u5c40\u548c\u89c6\u56fe\u6a21\u578b\u3002\u4f8b\u5982\uff0c\u4ee5\u4e0b\u5217\u8868\u663e\u793a\u4e86\u9ed8\u8ba4 MVC \u6a21\u677f\u7684 Error.cshtml Razor \u89c6\u56fe\u7684\u4e00\u90e8\u5206\u3002\u8fd9\u90fd\u662f\u53ef\u8bc6\u522b\u4e3a\u6807\u51c6 Razor \u8bed\u6cd5\u7684\u3002<\/p>\n<p>Listing 19.5 A Razor view<br \/>\n\u6e05\u5355 19.5 Razor \u89c6\u56fe<\/p>\n<pre><code>@model ErrorViewModel    #A\n@{\n    ViewData[&quot;Title&quot;] = &quot;Error&quot;;    #B\n}\n\n&lt;h1 class=&quot;text-danger&quot;&gt;Error.&lt;\/h1&gt;    #C\n&lt;h2 class=&quot;text-danger&quot;&gt;An error occurred while \n    processing your request.&lt;\/h2&gt;\n\n@if (Model.ShowRequestId)    #D\n{\n    &lt;p&gt;\n        &lt;strong&gt;Request ID:&lt;\/strong&gt; &lt;code&gt;@Model.RequestId&lt;\/code&gt;    #E\n    &lt;\/p&gt;\n}<\/code><\/pre>\n<p>\u2776 Razor views may specify a view model.<br \/>\nRazor \u89c6\u56fe\u53ef\u4ee5\u6307\u5b9a\u89c6\u56fe\u6a21\u578b\u3002<br \/>\n\u2777 You can access ViewData, and execute arbitrary C# statements.<br \/>\n\u60a8\u53ef\u4ee5\u8bbf\u95ee ViewData \u5e76\u6267\u884c\u4efb\u610f C# \u8bed\u53e5\u3002<br \/>\n\u2778 Standard HTML is written directly to the output.<br \/>\n\u6807\u51c6 HTML \u76f4\u63a5\u5199\u5165\u8f93\u51fa\u3002<br \/>\n\u2779 You can use standard Razor control statements and can access the view model using Model.<br \/>\n\u60a8\u53ef\u4ee5\u4f7f\u7528\u6807\u51c6 Razor \u63a7\u5236\u8bed\u53e5\uff0c\u5e76\u53ef\u4ee5\u4f7f\u7528 Model \u8bbf\u95ee\u89c6\u56fe\u6a21\u578b\u3002<br \/>\n\u277a You can write C# expressions using @.<br \/>\n\u60a8\u53ef\u4ee5\u4f7f\u7528 @ \u7f16\u5199 C# \u8868\u8fbe\u5f0f\u3002<\/p>\n<p>With your view template created, you now need to execute it. In most cases you won\u2019t create a ViewResult directly in your action methods. Instead, you\u2019ll use one of the View() helper methods on the Controller base class. These helper methods simplify passing in a view model and selecting a view template, but there\u2019s nothing magic about them; all they do is create ViewResult objects.<br \/>\n\u521b\u5efa\u89c6\u56fe\u6a21\u677f\u540e\uff0c\u60a8\u73b0\u5728\u9700\u8981\u6267\u884c\u5b83\u3002\u5728\u5927\u591a\u6570\u60c5\u51b5\u4e0b\uff0c\u60a8\u4e0d\u4f1a\u76f4\u63a5\u5728\u4f5c\u65b9\u6cd5\u4e2d\u521b\u5efa ViewResult\u3002\u76f8\u53cd\uff0c\u4f60\u5c06\u5728 Controller \u57fa\u7c7b\u4e0a\u4f7f\u7528 View\uff08\uff09 \u5e2e\u52a9\u7a0b\u5e8f\u65b9\u6cd5\u4e4b\u4e00\u3002\u8fd9\u4e9b\u5e2e\u52a9\u7a0b\u5e8f\u65b9\u6cd5\u7b80\u5316\u4e86\u89c6\u56fe\u6a21\u578b\u7684\u4f20\u5165\u548c\u89c6\u56fe\u6a21\u677f\u7684\u9009\u62e9\uff0c\u4f46\u5b83\u4eec\u5e76\u6ca1\u6709\u4ec0\u4e48\u795e\u5947\u4e4b\u5904;\u4ed6\u4eec\u6240\u505a\u7684\u53ea\u662f\u521b\u5efa ViewResult \u5bf9\u8c61\u3002<\/p>\n<p>In the simplest case you can call the View method without any arguments, as shown in the following listing, taken from the default MVC application. The View() helper method returns a ViewResult that uses conventions to find the view template to render and does not supply a view model when executing the view.<br \/>\n\u5728\u6700\u7b80\u5355\u7684\u60c5\u51b5\u4e0b\uff0c\u53ef\u4ee5\u8c03\u7528 View \u65b9\u6cd5\uff0c\u4e0d\u5e26\u4efb\u4f55\u53c2\u6570\uff0c\u5982\u4e0b\u9762\u7684\u6e05\u5355\u6240\u793a\uff0c\u5b83\u53d6\u81ea\u9ed8\u8ba4 MVC \u5e94\u7528\u7a0b\u5e8f\u3002\u5e2e\u52a9\u7a0b\u5e8f\u65b9\u6cd5\u8fd4\u56de\u4e00\u4e2a ViewResult\uff0c\u8be5\u65b9\u6cd5\u4f7f\u7528\u7ea6\u5b9a\u67e5\u627e\u8981\u5448\u73b0\u7684\u89c6\u56fe\u6a21\u677f\uff0c\u5e76\u4e14\u5728\u6267\u884c\u89c6\u56fe\u65f6\u4e0d\u63d0\u4f9b\u89c6\u56fe\u6a21\u578b\u3002<\/p>\n<p>Listing 19.6 Returning ViewResult from an action method using default conventions<br \/>\n\u793a\u4f8b 19.6 \u4f7f\u7528\u9ed8\u8ba4\u7ea6\u5b9a\u4ece\u4f5c\u65b9\u6cd5\u8fd4\u56de ViewResult<\/p>\n<pre><code>public class HomeController : Controller     #A\n{\n    public IActionResult Index()\n    {\n        return View();     #B\n    }\n}<\/code><\/pre>\n<p>In this example, the View helper method returns a ViewResult without specifying the name of the template to run. Instead, the name of the template to use is based on the name of the controller and the name of the action method. Given that the controller is called HomeController and the method is called Index, by default the Razor template engine looks for a template at the Views\/Home\/Index.cshtml location, as shown in figure 19.6.<br \/>\n\u5728\u6b64\u793a\u4f8b\u4e2d\uff0c View \u5e2e\u52a9\u7a0b\u5e8f\u65b9\u6cd5\u8fd4\u56de ViewResult\uff0c\u800c\u4e0d\u6307\u5b9a\u8981\u8fd0\u884c\u7684\u6a21\u677f\u7684\u540d\u79f0\u3002\u76f8\u53cd\uff0c\u8981\u4f7f\u7528\u7684\u6a21\u677f\u7684\u540d\u79f0\u57fa\u4e8e\u63a7\u5236\u5668\u7684\u540d\u79f0\u548c\u4f5c\u65b9\u6cd5\u7684\u540d\u79f0\u3002\u9274\u4e8e\u63a7\u5236\u5668\u540d\u4e3a HomeController \u4e14\u65b9\u6cd5\u540d\u4e3a Index\uff0c\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cRazor \u6a21\u677f\u5f15\u64ce\u4f1a\u5728 Views\/Home\/Index.cshtml \u4f4d\u7f6e\u67e5\u627e\u6a21\u677f\uff0c\u5982\u56fe 19.6 \u6240\u793a\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1906.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 19.6 View files are located at runtime based on naming conventions. Razor view files reside in a folder based on the name of the associated MVC controller and are named with the name of the action method that requested them. Views in the Shared folder can be used by any controller.<br \/>\n\u56fe 19.6 \u89c6\u56fe\u6587\u4ef6\u5728\u8fd0\u884c\u65f6\u6839\u636e\u547d\u540d\u7ea6\u5b9a\u8fdb\u884c\u5b9a\u4f4d\u3002Razor \u89c6\u56fe\u6587\u4ef6\u9a7b\u7559\u5728\u57fa\u4e8e\u5173\u8054 MVC \u63a7\u5236\u5668\u540d\u79f0\u7684\u6587\u4ef6\u5939\u4e2d\uff0c\u5e76\u4f7f\u7528\u8bf7\u6c42\u5b83\u4eec\u7684\u4f5c\u65b9\u6cd5\u7684\u540d\u79f0\u547d\u540d\u3002Shared \u6587\u4ef6\u5939\u4e2d\u7684\u89c6\u56fe\u53ef\u7531\u4efb\u4f55\u63a7\u5236\u5668\u4f7f\u7528\u3002<\/p>\n<p>This is another case of using conventions in MVC to reduce the amount of boilerplate you have to write. As always, the conventions are optional. You can also explicitly pass the name of the template to run as a string to the View method. For example, if the Index method in listing 19.6 instead returned View(&quot;ListView&quot;), the templating engine would look for a template called ListView.cshtml instead. You can even specify the complete path to the view file, relative to your application\u2019s root folder, such as View(&quot;Views\/global.cshtml&quot;), which would look for the template at the Views\/global.chtml location.<br \/>\n\u8fd9\u662f\u5728 MVC \u4e2d\u4f7f\u7528\u7ea6\u5b9a\u6765\u51cf\u5c11\u5fc5\u987b\u7f16\u5199\u7684\u6837\u677f\u6570\u91cf\u7684\u53e6\u4e00\u79cd\u60c5\u51b5\u3002\u4e0e\u5f80\u5e38\u4e00\u6837\uff0c\u7ea6\u5b9a\u662f\u53ef\u9009\u7684\u3002\u8fd8\u53ef\u4ee5\u5c06\u8981\u4f5c\u4e3a\u5b57\u7b26\u4e32\u8fd0\u884c\u7684\u6a21\u677f\u7684\u540d\u79f0\u663e\u5f0f\u4f20\u9012\u7ed9 View \u65b9\u6cd5\u3002\u4f8b\u5982\uff0c\u5982\u679c\u5217\u8868 19.6 \u4e2d\u7684 Index \u65b9\u6cd5\u8fd4\u56de View\uff08\u201cListView\u201d\uff09\uff0c\u5219\u6a21\u677f\u5316\u5f15\u64ce\u5c06\u6539\u4e3a\u67e5\u627e\u540d\u4e3a ListView.cshtml \u7684\u6a21\u677f\u3002\u60a8\u751a\u81f3\u53ef\u4ee5\u6307\u5b9a\u89c6\u56fe\u6587\u4ef6\u76f8\u5bf9\u4e8e\u5e94\u7528\u7a0b\u5e8f\u6839\u6587\u4ef6\u5939\u7684\u5b8c\u6574\u8def\u5f84\uff0c\u4f8b\u5982 View\uff08\u201cViews\/global.cshtml\u201d\uff09\uff0c\u5b83\u5c06\u5728 Views\/global.chtml \u4f4d\u7f6e\u67e5\u627e\u6a21\u677f\u3002<\/p>\n<p><b>NOTE<\/b> When specifying the absolute path to a view, you must include both the top-level Views folder and the .cshtml file extension in the path. This is similar to the rules for locating partial view templates.<br \/>\n\u6ce8\u610f\uff1a\u6307\u5b9a\u89c6\u56fe\u7684\u7edd\u5bf9\u8def\u5f84\u65f6\uff0c\u5fc5\u987b\u5728\u8def\u5f84\u4e2d\u540c\u65f6\u5305\u542b\u9876\u7ea7 Views \u6587\u4ef6\u5939\u548c .cshtml \u6587\u4ef6\u6269\u5c55\u540d\u3002\u8fd9\u7c7b\u4f3c\u4e8e\u67e5\u627e\u5c40\u90e8\u89c6\u56fe\u6a21\u677f\u7684\u89c4\u5219\u3002<\/p>\n<p>The process of locating an MVC Razor view is similar to the process of locating a partial view to render, which you learned about in chapter 17. The framework searches in multiple locations to find the requested view. The difference is that for Razor Pages the search process happens only for partial view rendering, as the main Razor view to render is already known; it\u2019s the Razor Page\u2019s view template.<br \/>\n\u67e5\u627e MVC Razor \u89c6\u56fe\u7684\u8fc7\u7a0b\u7c7b\u4f3c\u4e8e\u67e5\u627e\u8981\u5448\u73b0\u7684\u90e8\u5206\u89c6\u56fe\u7684\u8fc7\u7a0b\uff0c\u60a8\u5728\u7b2c 17 \u7ae0\u4e2d\u4e86\u89e3\u4e86\u8be5\u8fc7\u7a0b\u3002\u6846\u67b6\u5728\u591a\u4e2a\u4f4d\u7f6e\u641c\u7d22\u4ee5\u67e5\u627e\u8bf7\u6c42\u7684\u89c6\u56fe\u3002\u533a\u522b\u5728\u4e8e\uff0c\u5bf9\u4e8e Razor Pages\uff0c\u641c\u7d22\u8fc7\u7a0b\u4ec5\u9488\u5bf9\u90e8\u5206\u89c6\u56fe\u5448\u73b0\u8fdb\u884c\uff0c\u56e0\u4e3a\u8981\u5448\u73b0\u7684\u4e3b Razor \u89c6\u56fe\u662f\u5df2\u77e5\u7684;\u5b83\u662f Razor \u9875\u9762\u7684\u89c6\u56fe\u6a21\u677f\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1907.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 19.7 shows the complete process used by the MVC framework to locate the correct View template to execute when a ViewResult is returned from an MVC controller. It\u2019s possible for more than one template to be eligible, such as if an Index.chstml file exists in both the Home and Shared folders. Similar to the rules for locating partial views, the engine uses the first template it finds.<br \/>\n\u56fe 19.7 \u663e\u793a\u4e86 MVC \u6846\u67b6\u7528\u4e8e\u67e5\u627e\u4ece MVC \u63a7\u5236\u5668\u8fd4\u56de ViewResult \u65f6\u8981\u6267\u884c\u7684\u6b63\u786e View \u6a21\u677f\u7684\u5b8c\u6574\u8fc7\u7a0b\u3002\u591a\u4e2a\u6a21\u677f\u53ef\u80fd\u7b26\u5408\u6761\u4ef6\uff0c\u4f8b\u5982\uff0c\u5982\u679c Index .chstml \u6587\u4ef6\u540c\u65f6\u5b58\u5728\u4e8e Home \u548c Shared \u6587\u4ef6\u5939\u4e2d\u3002\u4e0e\u67e5\u627e\u5206\u90e8\u89c6\u56fe\u7684\u89c4\u5219\u7c7b\u4f3c\uff0c\u5f15\u64ce\u4f7f\u7528\u5b83\u627e\u5230\u7684\u7b2c\u4e00\u4e2a\u6a21\u677f\u3002<\/p>\n<p>Figure 19.7 A flow chart describing how the Razor templating engine locates the correct view template to execute. Avoiding the complexity of this diagram is one of the reasons I recommend using Razor Pages wherever possible!<br \/>\n\u56fe 19.7 \u63cf\u8ff0 Razor \u6a21\u677f\u5316\u5f15\u64ce\u5982\u4f55\u67e5\u627e\u8981\u6267\u884c\u7684\u6b63\u786e\u89c6\u56fe\u6a21\u677f\u7684\u6d41\u7a0b\u56fe\u3002\u907f\u514d\u6b64\u56fe\u8868\u7684\u590d\u6742\u6027\u662f\u6211\u5efa\u8bae\u5c3d\u53ef\u80fd\u4f7f\u7528 Razor Pages \u7684\u539f\u56e0\u4e4b\u4e00\uff01<\/p>\n<p><b>Tip<\/b> You can modify all these conventions, including the algorithm shown in figure 19.8, during initial configuration. In fact, you can replace the whole Razor templating engine if you really want to!<br \/>\n\u63d0\u793a:\u5728\u521d\u59cb\u914d\u7f6e\u671f\u95f4\uff0c\u60a8\u53ef\u4ee5\u4fee\u6539\u6240\u6709\u8fd9\u4e9b\u7ea6\u5b9a\uff0c\u5305\u62ec\u56fe 19.8 \u4e2d\u6240\u793a\u7684\u7b97\u6cd5\u3002\u4e8b\u5b9e\u4e0a\uff0c\u5982\u679c\u60a8\u771f\u7684\u613f\u610f\uff0c\u60a8\u53ef\u4ee5\u66ff\u6362\u6574\u4e2a Razor \u6a21\u677f\u5f15\u64ce\uff01<\/p>\n<p>You may find it tempting to explicitly provide the name of the view file you want to render in your controller; if so, I\u2019d encourage you to fight that urge. You\u2019ll have a much simpler time if you embrace the conventions as they are and go with the flow. That extends to anyone else who looks at your code; if you stick to the standard conventions, there\u2019ll be a comforting familiarity when they look at your app. That can only be a good thing!<br \/>\n\u4f60\u53ef\u80fd\u4f1a\u53d1\u73b0\u663e\u5f0f\u63d0\u4f9b\u8981\u5728\u63a7\u5236\u5668\u4e2d\u6e32\u67d3\u7684\u89c6\u56fe\u6587\u4ef6\u7684\u540d\u79f0\u5f88\u8bf1\u4eba;\u5982\u679c\u662f\u8fd9\u6837\uff0c\u6211\u9f13\u52b1\u4f60\u514b\u5236\u8fd9\u79cd\u51b2\u52a8\u3002\u5982\u679c\u60a8\u63a5\u53d7\u60ef\u4f8b\u5e76\u987a\u5176\u81ea\u7136\uff0c\u60a8\u5c06\u5ea6\u8fc7\u4e00\u6bb5\u8f7b\u677e\u5f97\u591a\u7684\u65f6\u5149\u3002\u8fd9\u5ef6\u4f38\u5230\u67e5\u770b\u4f60\u7684\u4ee3\u7801\u7684\u4efb\u4f55\u5176\u4ed6\u4eba;\u5982\u679c\u60a8\u9075\u5b88\u6807\u51c6\u7ea6\u5b9a\uff0c\u5f53\u4ed6\u4eec\u67e5\u770b\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u65f6\uff0c\u4f1a\u6709\u4e00\u79cd\u4ee4\u4eba\u6b23\u6170\u7684\u719f\u6089\u611f\u3002\u90a3\u53ea\u80fd\u662f\u4e00\u4ef6\u597d\u4e8b\uff01<\/p>\n<p>As well as providing a view template name, you can also pass an object to act as the view model for the Razor view. This object should match the type specified in the view\u2019s @model directive, and it\u2019s accessed in exactly the same way as for Razor Pages; using the Model property.<br \/>\n\u9664\u4e86\u63d0\u4f9b\u89c6\u56fe\u6a21\u677f\u540d\u79f0\u5916\uff0c\u60a8\u8fd8\u53ef\u4ee5\u4f20\u9012\u4e00\u4e2a\u5bf9\u8c61\u4ee5\u5145\u5f53 Razor \u89c6\u56fe\u7684\u89c6\u56fe\u6a21\u578b\u3002\u6b64\u5bf9\u8c61\u5e94\u4e0e\u89c6\u56fe\u7684 @model \u6307\u4ee4\u4e2d\u6307\u5b9a\u7684\u7c7b\u578b\u5339\u914d\uff0c\u5e76\u4e14\u8bbf\u95ee\u65b9\u5f0f\u4e0e Razor Pages \u5b8c\u5168\u76f8\u540c;\u4f7f\u7528 Model \u5c5e\u6027\u3002<\/p>\n<p><b>Tip<\/b> All the other ways of passing data to the view I described in chapter 17 are available in MVC controllers too. You should generally favor the view model where possible, but you can also use ViewData, TempData, or @inject services, for example.<br \/>\n\u63d0\u793a:\u6211\u5728\u7b2c 17 \u7ae0\u4e2d\u63cf\u8ff0\u7684\u6240\u6709\u5176\u4ed6\u5c06\u6570\u636e\u4f20\u9012\u7ed9\u89c6\u56fe\u7684\u65b9\u6cd5\u5728 MVC \u63a7\u5236\u5668\u4e2d\u4e5f\u53ef\u7528\u3002\u901a\u5e38\uff0c\u60a8\u5e94\u8be5\u5c3d\u53ef\u80fd\u4f7f\u7528\u89c6\u56fe\u6a21\u578b\uff0c\u4f46\u4e5f\u53ef\u4ee5\u4f7f\u7528 ViewData\u3001TempData \u6216 @inject \u670d\u52a1\u7b49\u3002<\/p>\n<p>The following listing shows two examples of passing a view model to a view.<br \/>\n\u4e0b\u9762\u7684\u6e05\u5355\u663e\u793a\u4e86\u5c06\u89c6\u56fe\u6a21\u578b\u4f20\u9012\u7ed9\u89c6\u56fe\u7684\u4e24\u4e2a\u793a\u4f8b\u3002<\/p>\n<p>Listing 19.7 Returning ViewResult from an action method using default conventions<br \/>\n\u793a\u4f8b 19.7 \u4f7f\u7528\u9ed8\u8ba4\u7ea6\u5b9a\u4ece\u4f5c\u65b9\u6cd5\u8fd4\u56de ViewResult<\/p>\n<pre><code>public class ToDoController : Controller\n{\n    public IActionResult Index()\n    {\n        var listViewModel = new ToDoListModel();     #A\n        return View(listViewModel);      #B\n    }\n    public IActionResult View(int id)\n    {\n        var viewModel = new ViewToDoModel();\n        return View(&quot;ViewToDo&quot;, viewModel);    #C\n    }\n\n}<\/code><\/pre>\n<p>Once the Razor view template has been located, the view is rendered using the Razor syntax you learned about in chapters 17 and 18. You can use all the features you\u2019ve already seen\u2014layouts, partial views, _ViewImports, and _ViewStart, for example. From the point of view of the Razor view, there\u2019s no difference between a Razor Pages view and an MVC Razor view.<br \/>\n\u627e\u5230 Razor \u89c6\u56fe\u6a21\u677f\u540e\uff0c\u5c06\u4f7f\u7528\u60a8\u5728\u7b2c 17 \u7ae0\u548c\u7b2c 18 \u7ae0\u4e2d\u5b66\u5230\u7684 Razor \u8bed\u6cd5\u5448\u73b0\u89c6\u56fe\u3002\u60a8\u53ef\u4ee5\u4f7f\u7528\u60a8\u5df2\u7ecf\u89c1\u8fc7\u7684\u6240\u6709\u529f\u80fd \u2014 \u4f8b\u5982\u5e03\u5c40\u3001\u5206\u90e8\u89c6\u56fe\u3001_ViewImports \u548c _ViewStart\u3002\u4ece Razor \u89c6\u56fe\u7684\u89d2\u5ea6\u6765\u770b\uff0cRazor \u9875\u9762\u89c6\u56fe\u548c MVC Razor \u89c6\u56fe\u4e4b\u95f4\u6ca1\u6709\u533a\u522b\u3002<\/p>\n<p>Now you\u2019ve had a brief overview of an MVC application, we can look in more depth about when to choose MVC controllers over Razor Pages.<br \/>\n\u73b0\u5728\u60a8\u5df2\u7ecf\u7b80\u8981\u6982\u8ff0\u4e86 MVC \u5e94\u7528\u7a0b\u5e8f\uff0c\u6211\u4eec\u53ef\u4ee5\u66f4\u6df1\u5165\u5730\u4e86\u89e3\u4f55\u65f6\u9009\u62e9 MVC \u63a7\u5236\u5668\u800c\u4e0d\u662f Razor Pages\u3002<\/p>\n<h2>19.5 Choosing between Razor Pages and MVC controllers<\/h2>\n<p>19.5 \u5728 Razor Pages \u548c MVC \u63a7\u5236\u5668\u4e4b\u95f4\u8fdb\u884c\u9009\u62e9<\/p>\n<p>Throughout this book, I have said that you should generally choose Razor Pages for server-rendered applications instead of using MVC controllers. In this section I show the difference between Razor Pages and MVC controllers from a project structure point of view and defend my reasoning. I also describe the cases where MVC controllers are a good choice.<br \/>\n\u5728\u672c\u4e66\u4e2d\uff0c\u6211\u4e00\u76f4\u8bf4\u8fc7\uff0c\u60a8\u901a\u5e38\u5e94\u8be5\u4e3a\u670d\u52a1\u5668\u5448\u73b0\u7684\u5e94\u7528\u7a0b\u5e8f\u9009\u62e9 Razor Pages\uff0c\u800c\u4e0d\u662f\u4f7f\u7528 MVC \u63a7\u5236\u5668\u3002\u5728\u672c\u8282\u4e2d\uff0c\u6211\u5c06\u4ece\u9879\u76ee\u7ed3\u6784\u7684\u89d2\u5ea6\u5c55\u793a Razor Pages \u548c MVC \u63a7\u5236\u5668\u4e4b\u95f4\u7684\u533a\u522b\uff0c\u5e76\u4e3a\u6211\u7684\u63a8\u7406\u8fa9\u62a4\u3002\u6211\u8fd8\u4ecb\u7ecd\u4e86 MVC \u63a7\u5236\u5668\u662f\u4e0d\u9519\u9009\u62e9\u7684\u60c5\u51b5\u3002<\/p>\n<p>If you\u2019re familiar with legacy .NET Framework ASP.NET or earlier versions of ASP.NET Core, you may already be familiar and comfortable with MVC controllers. If you\u2019re unsure whether to stick to what you know or switch to Razor Pages, this section should help you choose. Developers coming from those backgrounds often have misconceptions about Razor Pages initially (as I did!), incorrectly equating them with Web Forms and overlooking their underlying basis of the MVC framework. This section attempts to set the record straight.<br \/>\n\u5982\u679c\u60a8\u719f\u6089\u65e7\u7248 .NET Framework ASP.NET \u6216 ASP.NET Core \u7684\u65e9\u671f\u7248\u672c\uff0c\u5219\u60a8\u53ef\u80fd\u5df2\u7ecf\u719f\u6089\u5e76\u719f\u6089 MVC \u63a7\u5236\u5668\u3002\u5982\u679c\u60a8\u4e0d\u786e\u5b9a\u662f\u575a\u6301\u60a8\u6240\u77e5\u9053\u7684\u8fd8\u662f\u5207\u6362\u5230 Razor Pages\uff0c\u672c\u8282\u5e94\u8be5\u53ef\u4ee5\u5e2e\u52a9\u60a8\u8fdb\u884c\u9009\u62e9\u3002\u6765\u81ea\u8fd9\u4e9b\u80cc\u666f\u7684\u5f00\u53d1\u4eba\u5458\u6700\u521d\u901a\u5e38\u5bf9 Razor Pages \u6709\u8bef\u89e3\uff08\u5c31\u50cf\u6211\u4e00\u6837\uff09\uff0c\u9519\u8bef\u5730\u5c06\u5b83\u4eec\u7b49\u540c\u4e8e Web \u7a97\u4f53\uff0c\u800c\u5ffd\u7565\u4e86\u5b83\u4eec\u4f5c\u4e3a MVC \u6846\u67b6\u7684\u5e95\u5c42\u57fa\u7840\u3002\u672c\u8282\u8bd5\u56fe\u6f84\u6e05\u4e8b\u5b9e\u3002<\/p>\n<p>Indeed, architecturally, Razor Pages and MVC are essentially equivalent, as they both use the MVC design pattern. The most obvious differences relate to where the files are placed in your project, as I discuss in the next section.<br \/>\n\u4e8b\u5b9e\u4e0a\uff0c\u4ece\u67b6\u6784\u4e0a\u8bb2\uff0cRazor Pages \u548c MVC \u672c\u8d28\u4e0a\u662f\u7b49\u6548\u7684\uff0c\u56e0\u4e3a\u5b83\u4eec\u90fd\u4f7f\u7528 MVC \u8bbe\u8ba1\u6a21\u5f0f\u3002\u6700\u660e\u663e\u7684\u533a\u522b\u4e0e\u6587\u4ef6\u5728\u9879\u76ee\u4e2d\u7684\u653e\u7f6e\u4f4d\u7f6e\u6709\u5173\uff0c\u6211\u5c06\u5728\u4e0b\u4e00\u8282\u4e2d\u8ba8\u8bba\u3002<\/p>\n<h3>19.5.1 The benefits of Razor Pages<\/h3>\n<p>19.5.1 Razor Pages \u7684\u4f18\u52bf<\/p>\n<p>In section 19.5 I showed that the code for an MVC controller looks similar to the code for a Razor Page PageModel. If that\u2019s the case, what benefit is there to using Razor Pages? In this section I discuss some of the pain points of MVC controllers and how Razor Pages attempts to address them.<br \/>\n\u5728\u7b2c 19.5 \u8282\u4e2d\uff0c\u6211\u5c55\u793a\u4e86 MVC \u63a7\u5236\u5668\u7684\u4ee3\u7801\u770b\u8d77\u6765\u7c7b\u4f3c\u4e8e Razor Page PageModel \u7684\u4ee3\u7801\u3002\u5982\u679c\u662f\u8fd9\u6837\u7684\u8bdd\uff0c\u4f7f\u7528 Razor Pages \u6709\u4ec0\u4e48\u597d\u5904\uff1f\u5728\u672c\u8282\u4e2d\uff0c\u6211\u5c06\u8ba8\u8bba MVC \u63a7\u5236\u5668\u7684\u4e00\u4e9b\u75db\u70b9\uff0c\u4ee5\u53ca Razor Pages \u5982\u4f55\u5c1d\u8bd5\u89e3\u51b3\u8fd9\u4e9b\u75db\u70b9\u3002<\/p>\n<blockquote>\n<p>Razor Pages are not Web Forms<br \/>\nRazor Pages \u4e0d\u662f Web Forms<\/p>\n<p>A common argument I hear from existing ASP.NET developers against Razor Pages is \u201cOh, they\u2019re just Web Forms.\u201d That sentiment misses the mark in many ways, but it\u2019s common enough that it\u2019s worth addressing directly.<br \/>\n\u6211\u4ece\u73b0\u6709\u7684 ASP.NET \u5f00\u53d1\u4eba\u5458\u90a3\u91cc\u542c\u5230\u7684\u53cd\u5bf9 Razor Pages \u7684\u5e38\u89c1\u8bba\u70b9\u662f\u201c\u54e6\uff0c\u5b83\u4eec\u53ea\u662f Web Forms\u201d\u3002\u8fd9\u79cd\u60c5\u7eea\u5728\u5f88\u591a\u65b9\u9762\u90fd\u9519\u5931\u4e86\u76ee\u6807\uff0c\u4f46\u5b83\u8db3\u591f\u666e\u904d\uff0c\u503c\u5f97\u76f4\u63a5\u89e3\u51b3\u3002<\/p>\n<p>Web Forms was a web-programming model that was released as part of .NET Framework 1.0 in 2002. It attempted to provide a highly productive experience for developers moving from desktop development to the web for the first time.<br \/>\nWeb Forms\u662f\u4e00\u79cd Web \u7f16\u7a0b\u6a21\u578b\uff0c\u4e8e 2002 \u5e74\u4f5c\u4e3a .NET Framework 1.0 \u7684\u4e00\u90e8\u5206\u53d1\u5e03\u3002\u5b83\u8bd5\u56fe\u4e3a\u9996\u6b21\u4ece\u684c\u9762\u5f00\u53d1\u8f6c\u5411 Web \u7684\u5f00\u53d1\u4eba\u5458\u63d0\u4f9b\u9ad8\u6548\u7684\u4f53\u9a8c\u3002<\/p>\n<p>Web Forms are much maligned now, but their weaknesses only became apparent later. Web Forms attempted to hide the complexities of the web from you, to give you the impression of developing a desktop app. That often resulted in apps that were slow, with lots of interdependencies, and that were hard to maintain.<br \/>\nWeb Forms\u73b0\u5728\u53d7\u5230\u4e86\u5f88\u591a\u8bdf\u75c5\uff0c\u4f46\u5b83\u4eec\u7684\u5f31\u70b9\u540e\u6765\u624d\u663e\u73b0\u51fa\u6765\u3002Web Forms \u8bd5\u56fe\u5411\u60a8\u9690\u85cf Web \u7684\u590d\u6742\u6027\uff0c\u8ba9\u60a8\u89c9\u5f97\u81ea\u5df1\u5728\u5f00\u53d1\u684c\u9762\u5e94\u7528\u7a0b\u5e8f\u3002\u8fd9\u901a\u5e38\u4f1a\u5bfc\u81f4\u5e94\u7528\u7a0b\u5e8f\u8fd0\u884c\u7f13\u6162\u3001\u5b58\u5728\u5927\u91cf\u76f8\u4e92\u4f9d\u8d56\u5173\u7cfb\u5e76\u4e14\u96be\u4ee5\u7ef4\u62a4\u3002<\/p>\n<p>Web Forms provided a page-based programming model, which is why Razor Pages sometimes gets associated with them. However, as you\u2019ve seen, Razor Pages is based on the MVC design pattern, and it exposes the intrinsic features of the web without trying to hide them from you.<br \/>\nWeb Forms \u63d0\u4f9b\u4e86\u57fa\u4e8e\u9875\u9762\u7684\u7f16\u7a0b\u6a21\u578b\uff0c\u8fd9\u5c31\u662f Razor Pages \u6709\u65f6\u4f1a\u4e0e\u5b83\u4eec\u76f8\u5173\u8054\u7684\u539f\u56e0\u3002\u4f46\u662f\uff0c\u6b63\u5982\u4f60\u6240\u770b\u5230\u7684\uff0cRazor Pages \u57fa\u4e8e MVC \u8bbe\u8ba1\u6a21\u5f0f\uff0c\u5b83\u516c\u5f00\u4e86 Web \u7684\u5185\u5728\u529f\u80fd\uff0c\u800c\u4e0d\u4f1a\u8bd5\u56fe\u5bf9\u4f60\u9690\u85cf\u5b83\u4eec\u3002<\/p>\n<p>Razor Pages optimizes certain flows using conventions, but it\u2019s not trying to build a stateful application model over the top of a stateless web application, in the way that Web Forms did.<br \/>\nRazor Pages \u4f7f\u7528\u7ea6\u5b9a\u4f18\u5316\u67d0\u4e9b\u6d41\uff0c\u4f46\u5b83\u4e0d\u4f1a\u50cf Web \u7a97\u4f53\u90a3\u6837\u5c1d\u8bd5\u5728\u65e0\u72b6\u6001 Web \u5e94\u7528\u7a0b\u5e8f\u4e4b\u4e0a\u6784\u5efa\u6709\u72b6\u6001\u5e94\u7528\u7a0b\u5e8f\u6a21\u578b\u3002<\/p>\n<p>If you were a fan of Web Forms\u2019 stateful application model, you should consider Blazor Server, which uses a similar paradigm but embraces the web instead of fighting against it. You can read more about the similarities at <a href=\"https:\/\/learn.microsoft.com\/zh-cn\/dotnet\/architecture\/blazor-for-web-forms-developers\/\">https:\/\/learn.microsoft.com\/zh-cn\/dotnet\/architecture\/blazor-for-web-forms-developers\/<\/a>.<br \/>\n\u5982\u679c\u4f60\u662f Web Forms \u7684\u6709\u72b6\u6001\u5e94\u7528\u7a0b\u5e8f\u6a21\u578b\u7684\u7c89\u4e1d\uff0c\u4f60\u5e94\u8be5\u8003\u8651 Blazor Server\uff0c\u5b83\u4f7f\u7528\u7c7b\u4f3c\u7684\u8303\u4f8b\uff0c\u4f46\u62e5\u62b1 Web\uff0c\u800c\u4e0d\u662f\u4e0e\u4e4b\u5bf9\u6297\u3002\u60a8\u53ef\u4ee5\u5728 <a href=\"https:\/\/learn.microsoft.com\/zh-cn\/dotnet\/architecture\/blazor-for-web-forms-developers\/\">https:\/\/learn.microsoft.com\/zh-cn\/dotnet\/architecture\/blazor-for-web-forms-developers\/<\/a> \u4e0a\u9605\u8bfb\u6709\u5173\u76f8\u4f3c\u4e4b\u5904\u7684\u66f4\u591a\u4fe1\u606f\u3002<\/p>\n<\/blockquote>\n<p>In MVC, a single controller can have multiple action methods. Each action handles a different request and generates a different response. The grouping of multiple actions in a controller is somewhat arbitrary, but it\u2019s typically used to group actions related to a specific entity or resource: to-do list items in this case. A more complete version of the ToDoController in listing 19.4 might include action methods for listing all to-do items, for creating new items, and for deleting items, for example. Unfortunately, you can often find that your controllers become large and bloated, with many dependencies.[1]<br \/>\n\u5728 MVC \u4e2d\uff0c\u5355\u4e2a\u63a7\u5236\u5668\u53ef\u4ee5\u6709\u591a\u4e2a\u65b9\u6cd5\u3002\u6bcf\u4e2a\u4f5c\u5904\u7406\u4e0d\u540c\u7684\u8bf7\u6c42\u5e76\u751f\u6210\u4e0d\u540c\u7684\u54cd\u5e94\u3002\u63a7\u5236\u5668\u4e2d\u591a\u4e2a\u4f5c\u7684\u5206\u7ec4\u5728\u67d0\u79cd\u7a0b\u5ea6\u4e0a\u662f\u4efb\u610f\u7684\uff0c\u4f46\u5b83\u901a\u5e38\u7528\u4e8e\u5bf9\u4e0e\u7279\u5b9a\u5b9e\u4f53\u6216\u8d44\u6e90\u76f8\u5173\u7684\u4f5c\u8fdb\u884c\u5206\u7ec4\uff1a\u5728\u672c\u4f8b\u4e2d\u4e3a\u5f85\u529e\u4e8b\u9879\u5217\u8868\u9879\u3002\u4f8b\u5982\uff0c\u6e05\u5355 19.4 \u4e2d\u66f4\u5b8c\u6574\u7684 ToDoController \u7248\u672c\u53ef\u80fd\u5305\u62ec\u7528\u4e8e\u5217\u51fa\u6240\u6709\u5f85\u529e\u4e8b\u9879\u3001\u521b\u5efa\u65b0\u9879\u548c\u5220\u9664\u9879\u7684\u4f5c\u65b9\u6cd5\u3002\u4e0d\u5e78\u7684\u662f\uff0c\u60a8\u7ecf\u5e38\u4f1a\u53d1\u73b0\u60a8\u7684\u63a7\u5236\u5668\u53d8\u5f97\u5e9e\u5927\u800c\u81c3\u80bf\uff0c\u5e76\u4e14\u5177\u6709\u8bb8\u591a\u4f9d\u8d56\u9879\u3002[1]<\/p>\n<p><b>NOTE<\/b> You don\u2019t have to make your controllers very large like this. It\u2019s just a common pattern. You could, for example, create a separate controller for every action instead.<br \/>\n\u6ce8\u610f:\u60a8\u4e0d\u5fc5\u50cf\u8fd9\u6837\u5c06\u63a7\u5236\u5668\u505a\u5f97\u975e\u5e38\u5927\u3002\u8fd9\u53ea\u662f\u4e00\u79cd\u5e38\u89c1\u7684\u6a21\u5f0f\u3002\u4f8b\u5982\uff0c\u60a8\u53ef\u4ee5\u4e3a\u6bcf\u4e2a\u4f5c\u521b\u5efa\u4e00\u4e2a\u5355\u72ec\u7684\u63a7\u5236\u5668\u3002<\/p>\n<p>Another pitfall of MVC controllers is the way they\u2019re typically organized in your project. Most action methods in a controller need an associated Razor view, for generating the HTML, and a view model for passing data to the view. The MVC approach in .NET traditionally groups classes by type (controller, view, view model), while the Razor Page approach groups by function; everything related to a specific page is co-located.<br \/>\nMVC \u63a7\u5236\u5668\u7684\u53e6\u4e00\u4e2a\u7f3a\u9677\u662f\u5b83\u4eec\u5728\u9879\u76ee\u4e2d\u7684\u7ec4\u7ec7\u65b9\u5f0f\u3002\u63a7\u5236\u5668\u4e2d\u7684\u5927\u591a\u6570\u4f5c\u65b9\u6cd5\u90fd\u9700\u8981\u4e00\u4e2a\u5173\u8054\u7684 Razor \u89c6\u56fe\uff08\u7528\u4e8e\u751f\u6210 HTML\uff09\u548c\u4e00\u4e2a\u89c6\u56fe\u6a21\u578b\uff08\u7528\u4e8e\u5c06\u6570\u636e\u4f20\u9012\u5230\u89c6\u56fe\uff09\u3002.NET \u4e2d\u7684 MVC \u65b9\u6cd5\u4f20\u7edf\u4e0a\u6309\u7c7b\u578b\uff08\u63a7\u5236\u5668\u3001\u89c6\u56fe\u3001\u89c6\u56fe\u6a21\u578b\uff09\u5bf9\u7c7b\u8fdb\u884c\u5206\u7ec4\uff0c\u800c Razor Page \u65b9\u6cd5\u6309\u51fd\u6570\u5206\u7ec4;\u4e0e\u7279\u5b9a\u9875\u9762\u76f8\u5173\u7684\u6240\u6709\u5185\u5bb9\u90fd\u4f4d\u4e8e\u540c\u4e00\u4f4d\u7f6e\u3002<\/p>\n<p>Figure 19.8 compares the file layout for a simple Razor Pages project with the MVC equivalent. Using Razor Pages means much less scrolling up and down between the controller, views, and view model folders whenever you\u2019re working on a particular page. Everything you need is found in two files, the .cshtml Razor view and the (nested) .cshtml.cs PageModel file.<br \/>\n\u56fe 19.8 \u5c06\u7b80\u5355 Razor Pages \u9879\u76ee\u7684\u6587\u4ef6\u5e03\u5c40\u4e0e MVC \u7b49\u6548\u9879\u8fdb\u884c\u4e86\u6bd4\u8f83\u3002\u4f7f\u7528 Razor Pages \u610f\u5473\u7740\u5728\u5904\u7406\u7279\u5b9a\u9875\u9762\u65f6\uff0c\u5728\u63a7\u5236\u5668\u3001\u89c6\u56fe\u548c\u89c6\u56fe\u6a21\u578b\u6587\u4ef6\u5939\u4e4b\u95f4\u4e0a\u4e0b\u6eda\u52a8\u7684\u65f6\u95f4\u8981\u5c11\u5f97\u591a\u3002\u60a8\u9700\u8981\u7684\u6240\u6709\u5185\u5bb9\u90fd\u53ef\u4ee5\u5728\u4e24\u4e2a\u6587\u4ef6\u4e2d\u627e\u5230\uff1a.cshtml Razor \u89c6\u56fe\u548c\uff08\u5d4c\u5957\u7684\uff09.cshtml.cs PageModel \u6587\u4ef6\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1908.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 19.8 Comparing the folder structure for an MVC project with the folder structure for a Razor Pages project<br \/>\n\u56fe 19.8 \u5c06 MVC \u9879\u76ee\u7684\u6587\u4ef6\u5939\u7ed3\u6784\u4e0e Razor Pages \u9879\u76ee\u7684\u6587\u4ef6\u5939\u7ed3\u6784\u8fdb\u884c\u6bd4\u8f83<\/p>\n<p>There are additional differences between MVC and Razor Pages, which I have highlighted throughout the book, but this layout difference is really the biggest win. Razor Pages embraces the fact that you\u2019re building a page-based application and optimizes your workflow by keeping everything related to a single page together.<br \/>\nMVC \u548c Razor Pages \u4e4b\u95f4\u8fd8\u6709\u5176\u4ed6\u5dee\u5f02\uff0c\u6211\u5728\u6574\u672c\u4e66\u4e2d\u90fd\u5f3a\u8c03\u4e86\u8fd9\u4e9b\u5dee\u5f02\uff0c\u4f46\u8fd9\u79cd\u5e03\u5c40\u5dee\u5f02\u786e\u5b9e\u662f\u6700\u5927\u7684\u80dc\u5229\u3002Razor Pages \u63a5\u53d7\u4e86\u60a8\u6b63\u5728\u6784\u5efa\u57fa\u4e8e\u9875\u9762\u7684\u5e94\u7528\u7a0b\u5e8f\u8fd9\u4e00\u4e8b\u5b9e\uff0c\u5e76\u901a\u8fc7\u5c06\u4e0e\u5355\u4e2a\u9875\u9762\u76f8\u5173\u7684\u6240\u6709\u5185\u5bb9\u653e\u5728\u4e00\u8d77\u6765\u4f18\u5316\u60a8\u7684\u5de5\u4f5c\u6d41\u7a0b\u3002<\/p>\n<p><b>Tip<\/b> You can think of each Razor Page as a mini controller focused on a single page. Page handlers are functionally equivalent to MVC controller action methods.<br \/>\n\u63d0\u793a:\u60a8\u53ef\u4ee5\u5c06\u6bcf\u4e2a Razor \u9875\u9762\u89c6\u4e3a\u4e00\u4e2a\u4e13\u6ce8\u4e8e\u5355\u4e2a\u9875\u9762\u7684\u8ff7\u4f60\u63a7\u5236\u5668\u3002\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u5728\u529f\u80fd\u4e0a\u7b49\u540c\u4e8e MVC \u63a7\u5236\u5668\u4f5c\u65b9\u6cd5\u3002<\/p>\n<p>This layout also has the benefit of making each page a separate class. This contrasts with the MVC approach of making each page an action on a given controller. Each Razor Page is cohesive for a particular feature, such as displaying a to-do item. MVC controllers contain action methods that handle multiple different features for a more abstract concept, such as all the features related to to-do items.<br \/>\n\u6b64\u5e03\u5c40\u8fd8\u5177\u6709\u4f7f\u6bcf\u4e2a\u9875\u9762\u6210\u4e3a\u5355\u72ec\u7c7b\u7684\u4f18\u70b9\u3002\u8fd9\u4e0e MVC \u65b9\u6cd5\u5f62\u6210\u9c9c\u660e\u5bf9\u6bd4\uff0c\u540e\u8005\u5c06\u6bcf\u4e2a\u9875\u9762\u90fd\u8bbe\u7f6e\u4e3a\u7ed9\u5b9a\u63a7\u5236\u5668\u4e0a\u7684\u4f5c\u3002\u6bcf\u4e2a Razor \u9875\u9762\u5bf9\u4e8e\u7279\u5b9a\u529f\u80fd\uff08\u4f8b\u5982\u663e\u793a\u5f85\u529e\u4e8b\u9879\uff09\u90fd\u662f\u5185\u805a\u7684\u3002MVC \u63a7\u5236\u5668\u5305\u542b\u4f5c\u65b9\u6cd5\uff0c\u8fd9\u4e9b\u65b9\u6cd5\u5904\u7406\u591a\u4e2a\u4e0d\u540c\u529f\u80fd\uff0c\u4ee5\u5b9e\u73b0\u66f4\u62bd\u8c61\u7684\u6982\u5ff5\uff0c\u4f8b\u5982\u4e0e\u5f85\u529e\u4e8b\u9879\u76f8\u5173\u7684\u6240\u6709\u529f\u80fd\u3002<\/p>\n<p><b>NOTE<\/b> ASP.NET Core is eminently customizable, so you don\u2019t have to group your MVC applications by type; it\u2019s simply the default state and the easy path. In fact, if you do choose to use MVC controllers, I strongly suggest grouping using feature folders instead. This MSDN article provides a good introduction: <a href=\"http:\/\/mng.bz\/mVOr\">http:\/\/mng.bz\/mVOr<\/a>.<br \/>\n\u6ce8\u610f: ASP.NET Core \u662f\u9ad8\u5ea6\u53ef\u5b9a\u5236\u7684\uff0c\u56e0\u6b64\u60a8\u4e0d\u5fc5\u6309\u7c7b\u578b\u5bf9 MVC \u5e94\u7528\u7a0b\u5e8f\u8fdb\u884c\u5206\u7ec4;\u5b83\u53ea\u662f\u9ed8\u8ba4\u72b6\u6001\u548c\u7b80\u5355\u7684\u8def\u5f84\u3002\u4e8b\u5b9e\u4e0a\uff0c\u5982\u679c\u60a8\u786e\u5b9e\u9009\u62e9\u4f7f\u7528 MVC \u63a7\u5236\u5668\uff0c\u6211\u5f3a\u70c8\u5efa\u8bae\u6539\u7528\u529f\u80fd\u6587\u4ef6\u5939\u8fdb\u884c\u5206\u7ec4\u3002\u8fd9\u7bc7 MSDN \u6587\u7ae0\u63d0\u4f9b\u4e86\u4e00\u4e2a\u5f88\u597d\u7684\u4ecb\u7ecd\uff1a<a href=\"http:\/\/mng.bz\/mVOr\">http:\/\/mng.bz\/mVOr<\/a>\u3002<\/p>\n<p>Another important point is that Razor Pages doesn\u2019t lose any of the separation of concerns that MVC has. The view part of Razor Pages is still concerned only with rendering HTML, and the handler is the coordinator that calls out to the application model. The only real difference is the lack of the explicit view model that you have in MVC, but it\u2019s perfectly possible to emulate this in Razor Pages if that\u2019s a deal-breaker for you.<br \/>\n\u53e6\u4e00\u4e2a\u91cd\u8981\u7684\u4e00\u70b9\u662f\uff0cRazor Pages \u4e0d\u4f1a\u5931\u53bb MVC \u6240\u5177\u6709\u7684\u4efb\u4f55\u5173\u6ce8\u70b9\u5206\u79bb\u3002Razor Pages \u7684\u89c6\u56fe\u90e8\u5206\u4ecd\u7136\u53ea\u5173\u5fc3\u5448\u73b0 HTML\uff0c\u5904\u7406\u7a0b\u5e8f\u662f\u8c03\u7528\u5e94\u7528\u7a0b\u5e8f\u6a21\u578b\u7684\u534f\u8c03\u5668\u3002\u552f\u4e00\u771f\u6b63\u7684\u533a\u522b\u662f\u7f3a\u5c11 MVC \u4e2d\u7684\u663e\u5f0f\u89c6\u56fe\u6a21\u578b\uff0c\u4f46\u5982\u679c\u8fd9\u5bf9\u60a8\u6765\u8bf4\u662f\u4e00\u4e2a\u4ea4\u6613\u7834\u574f\u8005\uff0c\u90a3\u4e48\u5728 Razor Pages \u4e2d\u5b8c\u5168\u53ef\u4ee5\u6a21\u62df\u5b83\u3002<\/p>\n<p>The benefits of using Razor Pages are particularly noticeable when you have content websites, such as marketing websites, where you\u2019re mostly displaying static data and there\u2019s no real logic. In that case, MVC adds complexity without any real benefits, as there\u2019s not really any logic in the controllers at all. Another great use case is when you\u2019re creating forms for users to submit data. Razor Pages is especially optimized for this scenario, as you saw in previous chapters.<br \/>\n\u5f53\u4f60\u62e5\u6709\u5185\u5bb9\u7f51\u7ad9\uff08\u5982\u8425\u9500\u7f51\u7ad9\uff09\u65f6\uff0c\u4f7f\u7528 Razor Pages \u7684\u597d\u5904\u5c24\u5176\u660e\u663e\uff0c\u56e0\u4e3a\u4f60\u4e3b\u8981\u663e\u793a\u9759\u6001\u6570\u636e\uff0c\u6ca1\u6709\u771f\u6b63\u7684\u903b\u8f91\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0cMVC \u589e\u52a0\u4e86\u590d\u6742\u6027\uff0c\u4f46\u6ca1\u6709\u4efb\u4f55\u5b9e\u9645\u7684\u597d\u5904\uff0c\u56e0\u4e3a\u63a7\u5236\u5668\u4e2d\u6839\u672c\u6ca1\u6709\u4efb\u4f55\u771f\u6b63\u7684\u903b\u8f91\u3002\u53e6\u4e00\u4e2a\u5f88\u597d\u7684\u7528\u4f8b\u662f\u5f53\u60a8\u4e3a\u7528\u6237\u521b\u5efa\u8868\u5355\u4ee5\u63d0\u4ea4\u6570\u636e\u65f6\u3002Razor Pages \u7279\u522b\u9488\u5bf9\u6b64\u65b9\u6848\u8fdb\u884c\u4e86\u4f18\u5316\uff0c\u5982\u524d\u51e0\u7ae0\u6240\u793a\u3002<\/p>\n<p>Clearly, I\u2019m a fan of Razor Pages, but that\u2019s not to say they\u2019re perfect for every situation. In the next section I discuss some of the cases when you might choose to use MVC controllers in your application. Bear in mind it\u2019s not an either-or choice; it\u2019s possible to use MVC controllers, Razor Pages, and even minimal APIs in the same application, and in many cases that may be the best option.<br \/>\n\u663e\u7136\uff0c\u6211\u662f Razor Pages \u7684\u7c89\u4e1d\uff0c\u4f46\u8fd9\u5e76\u4e0d\u662f\u8bf4\u5b83\u4eec\u9002\u5408\u6240\u6709\u60c5\u51b5\u3002\u5728\u4e0b\u4e00\u8282\u4e2d\uff0c\u6211\u5c06\u8ba8\u8bba\u4e00\u4e9b\u60a8\u53ef\u80fd\u4f1a\u9009\u62e9\u5728\u5e94\u7528\u7a0b\u5e8f\u4e2d\u4f7f\u7528 MVC \u63a7\u5236\u5668\u7684\u60c5\u51b5\u3002\u8bf7\u8bb0\u4f4f\uff0c\u8fd9\u4e0d\u662f\u4e00\u4e2a\u975e\u6b64\u5373\u5f7c\u7684\u9009\u62e9;\u53ef\u4ee5\u5728\u540c\u4e00\u5e94\u7528\u7a0b\u5e8f\u4e2d\u4f7f\u7528 MVC \u63a7\u5236\u5668\u3001Razor Pages \u751a\u81f3\u6700\u5c0f\u7684 API\uff0c\u5728\u8bb8\u591a\u60c5\u51b5\u4e0b\uff0c\u8fd9\u53ef\u80fd\u662f\u6700\u4f73\u9009\u62e9\u3002<\/p>\n<h3>19.5.2 When to choose MVC controllers over Razor Pages<\/h3>\n<p>19.5.2 \u4f55\u65f6\u9009\u62e9 MVC \u63a7\u5236\u5668\u800c\u4e0d\u662f Razor Pages<\/p>\n<p>Razor Pages are great for building page-based server-side rendered applications. But not all applications fit that mold, and even some applications that do fall in that category might be best developed using MVC controllers instead of Razor Pages. These are a few such scenarios:<br \/>\nRazor Pages \u975e\u5e38\u9002\u5408\u6784\u5efa\u57fa\u4e8e\u9875\u9762\u7684\u670d\u52a1\u5668\u7aef\u6e32\u67d3\u5e94\u7528\u7a0b\u5e8f\u3002\u4f46\u5e76\u975e\u6240\u6709\u5e94\u7528\u7a0b\u5e8f\u90fd\u9002\u5408\u8fd9\u79cd\u6a21\u5f0f\uff0c\u751a\u81f3\u4e00\u4e9b\u5c5e\u4e8e\u8be5\u7c7b\u522b\u7684\u5e94\u7528\u7a0b\u5e8f\u4e5f\u53ef\u80fd\u6700\u597d\u4f7f\u7528 MVC \u63a7\u5236\u5668\u800c\u4e0d\u662f Razor Pages \u8fdb\u884c\u5f00\u53d1\u3002\u4ee5\u4e0b\u662f\u4e00\u4e9b\u8fd9\u6837\u7684\u573a\u666f\uff1a<\/p>\n<p>\u2022  When you don\u2019t want to render views\u2014Razor Pages are best for page-based applications, where you\u2019re rendering a view for the user. If you\u2019re building an HTTP API, you should use minimal APIs or MVC (web API) controllers instead. You\u2019ll learn about web API controllers in chapter 20.<br \/>\n\u5f53\u60a8\u4e0d\u60f3\u5448\u73b0\u89c6\u56fe\u65f6 - Razor Pages \u6700\u9002\u5408\u57fa\u4e8e\u9875\u9762\u7684\u5e94\u7528\u7a0b\u5e8f\uff0c\u60a8\u53ef\u4ee5\u5728\u5176\u4e2d\u4e3a\u7528\u6237\u5448\u73b0\u89c6\u56fe\u3002\u5982\u679c\u8981\u6784\u5efa HTTP API\uff0c\u5219\u5e94\u6539\u7528\u6700\u5c11\u7684 API \u6216 MVC \uff08Web API\uff09 \u63a7\u5236\u5668\u3002\u60a8\u5c06\u5728\u7b2c 20 \u7ae0\u4e2d\u4e86\u89e3 Web API \u63a7\u5236\u5668\u3002<\/p>\n<p>\u2022  When you\u2019re converting an existing MVC application to ASP.NET Core\u2014If you already have a legacy ASP.NET application that you\u2019re converting to ASP.NET Core or an app using an early version of ASP.NET Core that you\u2019re updating, you\u2019re likely using MVC controllers. It\u2019s probably not worth converting your existing MVC controllers to Razor Pages in this case. It makes more sense to keep your existing code and consider whether to do new development in the application with Razor Pages.<br \/>\n\u5c06\u73b0\u6709 MVC \u5e94\u7528\u7a0b\u5e8f\u8f6c\u6362\u4e3a ASP.NET Core \u65f6 - \u5982\u679c\u60a8\u5df2\u7ecf\u6709\u4e00\u4e2a\u8981\u8f6c\u6362\u4e3a ASP.NET Core \u7684\u65e7\u7248 ASP.NET \u5e94\u7528\u7a0b\u5e8f\uff0c\u6216\u8005\u4f7f\u7528\u8981\u66f4\u65b0\u7684 ASP.NET Core \u65e9\u671f\u7248\u672c\u7684\u5e94\u7528\u7a0b\u5e8f\uff0c\u5219\u60a8\u53ef\u80fd\u4f7f\u7528\u7684\u662f MVC \u63a7\u5236\u5668\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u53ef\u80fd\u4e0d\u503c\u5f97\u5c06\u73b0\u6709\u7684 MVC \u63a7\u5236\u5668\u8f6c\u6362\u4e3a Razor Pages\u3002\u4fdd\u7559\u73b0\u6709\u4ee3\u7801\u5e76\u8003\u8651\u662f\u5426\u4f7f\u7528 Razor Pages \u5728\u5e94\u7528\u7a0b\u5e8f\u4e2d\u8fdb\u884c\u65b0\u5f00\u53d1\u66f4\u6709\u610f\u4e49\u3002<\/p>\n<p>\u2022  When you\u2019re doing a lot of partial page updates\u2014It\u2019s possible to use JavaScript in an MVC application to avoid doing full page navigations by updating only part of the page at a time. This approach, halfway between fully server-side rendered and a client-side application, may be easier to achieve with MVC controllers than Razor Pages. On the other hand, you can easily mix Razor Pages and MVC controllers, using Razor Pages where appropriate and MVC controllers for the partial view results.<br \/>\n\u5f53\u60a8\u6267\u884c\u5927\u91cf\u90e8\u5206\u9875\u9762\u66f4\u65b0\u65f6 - \u53ef\u4ee5\u5728 MVC \u5e94\u7528\u7a0b\u5e8f\u4e2d\u4f7f\u7528 JavaScript\uff0c\u901a\u8fc7\u4e00\u6b21\u53ea\u66f4\u65b0\u9875\u9762\u7684\u4e00\u90e8\u5206\u6765\u907f\u514d\u6267\u884c\u6574\u4e2a\u9875\u9762\u5bfc\u822a\u3002\u8fd9\u79cd\u65b9\u6cd5\u4ecb\u4e8e\u5b8c\u5168\u670d\u52a1\u5668\u7aef\u6e32\u67d3\u548c\u5ba2\u6237\u7aef\u5e94\u7528\u7a0b\u5e8f\u4e4b\u95f4\uff0c\u4f7f\u7528 MVC \u63a7\u5236\u5668\u53ef\u80fd\u6bd4 Razor Pages \u66f4\u5bb9\u6613\u5b9e\u73b0\u3002\u53e6\u4e00\u65b9\u9762\uff0c\u60a8\u53ef\u4ee5\u8f7b\u677e\u5730\u6df7\u5408\u4f7f\u7528 Razor Pages \u548c MVC \u63a7\u5236\u5668\uff0c\u5728\u9002\u5f53\u7684\u60c5\u51b5\u4e0b\u4f7f\u7528 Razor Pages\uff0c\u5e76\u4f7f\u7528 MVC \u63a7\u5236\u5668\u83b7\u5f97\u90e8\u5206\u89c6\u56fe\u7ed3\u679c\u3002<\/p>\n<blockquote>\n<p>When not to use Razor Pages or MVC controllers<br \/>\n\u4f55\u65f6\u4e0d\u4f7f\u7528 Razor Pages \u6216 MVC \u63a7\u5236\u5668<\/p>\n<p>Typically, you\u2019ll use either Razor Pages or MVC controllers to write most of the UI logic for an app. You\u2019ll use it to define the APIs and pages in your application and to define how they interface with your business logic. Razor Pages and MVC provide an extensive framework and include a great deal of functionality to help build your apps quickly and efficiently. But they\u2019re not suited to every app.<br \/>\n\u901a\u5e38\uff0c\u4f60\u5c06\u4f7f\u7528 Razor Pages \u6216 MVC \u63a7\u5236\u5668\u6765\u7f16\u5199\u5e94\u7528\u7684\u5927\u90e8\u5206 UI \u903b\u8f91\u3002\u60a8\u5c06\u4f7f\u7528\u5b83\u6765\u5b9a\u4e49\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684 API \u548c\u9875\u9762\uff0c\u5e76\u5b9a\u4e49\u5b83\u4eec\u5982\u4f55\u4e0e\u60a8\u7684\u4e1a\u52a1\u903b\u8f91\u4ea4\u4e92\u3002Razor Pages \u548c MVC \u63d0\u4f9b\u4e86\u4e00\u4e2a\u5e7f\u6cdb\u7684\u6846\u67b6\uff0c\u5e76\u5305\u542b\u5927\u91cf\u529f\u80fd\u6765\u5e2e\u52a9\u5feb\u901f\u6709\u6548\u5730\u6784\u5efa\u5e94\u7528\u3002\u4f46\u5b83\u4eec\u5e76\u4e0d\u9002\u5408\u6bcf\u4e2a\u5e94\u7528\u7a0b\u5e8f\u3002<\/p>\n<p>Providing so much functionality necessarily comes with a certain degree of performance overhead. For typical line-of-business apps, the productivity gains from using MVC or Razor Pages often outweighs any performance effect. But if you\u2019re building a JSON API you will likely want to consider minimal APIs for the performance improvements. For server-to-server APIs or nonbrowser clients, an alternative protocol like gRPC (<a href=\"https:\/\/docs.microsoft.com\/aspnet\/core\/grpc\">https:\/\/docs.microsoft.com\/aspnet\/core\/grpc<\/a>) may be a good fit. You might also consider protocols like GraphQL, as discussed in Building Web APIs in ASP.NET Core, by Valerio De Sanctis (Manning, 2023).<br \/>\n\u63d0\u4f9b\u5982\u6b64\u591a\u7684\u529f\u80fd\u5fc5\u7136\u4f1a\u5e26\u6765\u4e00\u5b9a\u7a0b\u5ea6\u7684\u6027\u80fd\u5f00\u9500\u3002\u5bf9\u4e8e\u5178\u578b\u7684\u4e1a\u52a1\u7ebf\u5e94\u7528\uff0c\u4f7f\u7528 MVC \u6216 Razor Pages \u5e26\u6765\u7684\u5de5\u4f5c\u6548\u7387\u63d0\u5347\u901a\u5e38\u8d85\u8fc7\u4efb\u4f55\u6027\u80fd\u5f71\u54cd\u3002\u4f46\u662f\uff0c\u5982\u679c\u60a8\u6b63\u5728\u6784\u5efa JSON API\uff0c\u5219\u53ef\u80fd\u9700\u8981\u8003\u8651\u4f7f\u7528\u6700\u5c11\u7684 API \u6765\u63d0\u9ad8\u6027\u80fd\u3002\u5bf9\u4e8e\u670d\u52a1\u5668\u5230\u670d\u52a1\u5668 API \u6216\u975e\u6d4f\u89c8\u5668\u5ba2\u6237\u7aef\uff0cgRPC \uff08<a href=\"https:\/\/docs.microsoft.com\/aspnet\/core\/grpc\">https:\/\/docs.microsoft.com\/aspnet\/core\/grpc<\/a>\uff09 \u7b49\u66ff\u4ee3\u534f\u8bae\u53ef\u80fd\u5f88\u5408\u9002\u3002\u60a8\u8fd8\u53ef\u4ee5\u8003\u8651\u50cf GraphQL \u8fd9\u6837\u7684\u534f\u8bae\uff0c\u5982 Valerio De Sanctis \u5728 ASP.NET Core \u4e2d\u6784\u5efa Web API \u4e2d\u6240\u8ff0\uff08Manning\uff0c2023 \u5e74\uff09\u3002<\/p>\n<p>Alternatively, if you\u2019re building an app with real-time functionality, you\u2019ll probably want to consider using WebSockets instead of traditional HTTP requests. ASP.NET Core SignalR can be used to add real-time functionality to your app by providing an abstraction over WebSockets. SignalR also provides simple transport fallbacks and a remote procedure call (RPC) app model. For details, see the documentation at <a href=\"https:\/\/docs.microsoft.com\/aspnet\/core\/signalr\">https:\/\/docs.microsoft.com\/aspnet\/core\/signalr<\/a>.<br \/>\n\u6216\u8005\uff0c\u5982\u679c\u60a8\u6b63\u5728\u6784\u5efa\u5177\u6709\u5b9e\u65f6\u529f\u80fd\u7684\u5e94\u7528\u7a0b\u5e8f\uff0c\u5219\u53ef\u80fd\u9700\u8981\u8003\u8651\u4f7f\u7528 WebSockets \u800c\u4e0d\u662f\u4f20\u7edf\u7684 HTTP \u8bf7\u6c42\u3002ASP.NET Core SignalR \u53ef\u7528\u4e8e\u901a\u8fc7\u901a\u8fc7 WebSockets \u63d0\u4f9b\u62bd\u8c61\u6765\u5411\u5e94\u7528\u6dfb\u52a0\u5b9e\u65f6\u529f\u80fd\u3002SignalR \u8fd8\u63d0\u4f9b\u7b80\u5355\u7684\u4f20\u8f93\u56de\u9000\u548c\u8fdc\u7a0b\u8fc7\u7a0b\u8c03\u7528 \uff08RPC\uff09 \u5e94\u7528\u7a0b\u5e8f\u6a21\u578b\u3002\u6709\u5173\u8be6\u7ec6\u4fe1\u606f\uff0c\u8bf7\u53c2\u9605 <a href=\"https:\/\/docs.microsoft.com\/aspnet\/core\/signalr\">https:\/\/docs.microsoft.com\/aspnet\/core\/signalr<\/a> \u4e2d\u7684\u6587\u6863\u3002<\/p>\n<p>Another option available in ASP.NET Core 7 is Blazor. This framework allows you to build interactive client-side web applications by using the WebAssembly standard to run .NET code directly in your browser or by using a stateful model with SignalR. See Blazor in Action, by Chris Sainty (Manning, 2022), for more details.<br \/>\nASP.NET Core 7 \u4e2d\u63d0\u4f9b\u7684\u53e6\u4e00\u4e2a\u9009\u9879\u662f Blazor\u3002\u6b64\u6846\u67b6\u5141\u8bb8\u60a8\u901a\u8fc7\u4f7f\u7528 WebAssembly \u6807\u51c6\u76f4\u63a5\u5728\u6d4f\u89c8\u5668\u4e2d\u8fd0\u884c .NET \u4ee3\u7801\uff0c\u6216\u8005\u5c06\u6709\u72b6\u6001\u6a21\u578b\u4e0e SignalR \u7ed3\u5408\u4f7f\u7528\u6765\u6784\u5efa\u4ea4\u4e92\u5f0f\u5ba2\u6237\u7aef Web \u5e94\u7528\u7a0b\u5e8f\u3002\u6709\u5173\u66f4\u591a\u8be6\u7ec6\u4fe1\u606f\uff0c\u8bf7\u53c2\u9605 Chris Sainty \u7684 Blazor in Action\uff08Manning, 2022\uff09\u3002<\/p>\n<\/blockquote>\n<p>I hope that by this point you\u2019re sold on Razor Pages and their overall design using the MVC pattern. Nevertheless, using MVC controllers makes sense in some situations, so it\u2019s worth bearing that in mind. Another important point to remember is that you can include both MVC controllers and Razor Pages in the same application if you need them.<br \/>\n\u6211\u5e0c\u671b\u5230\u6b64\u65f6\uff0c\u60a8\u5df2\u7ecf\u5bf9\u4f7f\u7528 MVC \u6a21\u5f0f\u7684 Razor Pages \u53ca\u5176\u6574\u4f53\u8bbe\u8ba1\u611f\u5230\u6ee1\u610f\u3002\u5c3d\u7ba1\u5982\u6b64\uff0c\u5728\u67d0\u4e9b\u60c5\u51b5\u4e0b\u4f7f\u7528 MVC \u63a7\u5236\u5668\u662f\u6709\u610f\u4e49\u7684\uff0c\u56e0\u6b64\u503c\u5f97\u7262\u8bb0\u8fd9\u4e00\u70b9\u3002\u8981\u8bb0\u4f4f\u7684\u53e6\u4e00\u4e2a\u91cd\u8981\u70b9\u662f\uff0c\u5982\u679c\u9700\u8981\uff0c\u60a8\u53ef\u4ee5\u5c06 MVC \u63a7\u5236\u5668\u548c Razor Pages \u5305\u542b\u5728\u540c\u4e00\u4e2a\u5e94\u7528\u7a0b\u5e8f\u4e2d\u3002<\/p>\n<p>You\u2019ve learned about MVC controllers as an alternative to Razor Pages, and in part 1 of this book you learned about using minimal APIs to build JSON API. Web API controllers sit somewhere in between; they use MVC controllers but generate JSON and other machine-friendly format data, not HTML. In chapter 20 you\u2019ll learn why you might choose to use web API controllers over minimal APIs and how to build a web API application.<br \/>\n\u60a8\u5df2\u7ecf\u4e86\u89e3\u4e86 MVC \u63a7\u5236\u5668\u4f5c\u4e3a Razor Pages \u7684\u66ff\u4ee3\u65b9\u6848\uff0c\u5728\u672c\u4e66\u7684\u7b2c 1 \u90e8\u5206\u4e2d\uff0c\u60a8\u4e86\u89e3\u4e86\u5982\u4f55\u4f7f\u7528\u6700\u5c11\u7684 API \u6765\u6784\u5efa JSON API\u3002Web API \u63a7\u5236\u5668\u4ecb\u4e8e\u4e24\u8005\u4e4b\u95f4;\u5b83\u4eec\u4f7f\u7528 MVC \u63a7\u5236\u5668\uff0c\u4f46\u751f\u6210 JSON \u548c\u5176\u4ed6\u673a\u5668\u53cb\u597d\u7684\u683c\u5f0f\u6570\u636e\uff0c\u800c\u4e0d\u662f HTML\u3002\u5728\u7b2c 20 \u7ae0\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3\u4e3a\u4ec0\u4e48\u60a8\u53ef\u80fd\u4f1a\u9009\u62e9\u4f7f\u7528 Web API \u63a7\u5236\u5668\u800c\u4e0d\u662f\u6700\u5c11\u7684 API\uff0c\u4ee5\u53ca\u5982\u4f55\u6784\u5efa Web API \u5e94\u7528\u7a0b\u5e8f\u3002<\/p>\n<h2>19.6 Summary<\/h2>\n<p>19.6 \u603b\u7ed3<\/p>\n<p>An action (or action method) is a method that runs in response to a request. An MVC controller is a class that contains one or more logically grouped action methods.<br \/>\naction \uff08\u6216\u4f5c\u65b9\u6cd5\uff09 \u662f\u4e3a\u54cd\u5e94\u8bf7\u6c42\u800c\u8fd0\u884c\u7684\u65b9\u6cd5\u3002MVC \u63a7\u5236\u5668\u662f\u5305\u542b\u4e00\u4e2a\u6216\u591a\u4e2a\u903b\u8f91\u5206\u7ec4\u7684\u4f5c\u65b9\u6cd5\u7684\u7c7b\u3002<\/p>\n<p>To use MVC controllers in an ASP.NET Core application, call AddControllersWithViews() on your WebApplicationBuilder. This adds all the required services for MVC controllers and Razor view rendering to the dependency injection container.<br \/>\n\u8981\u5728 ASP.NET Core \u5e94\u7528\u7a0b\u5e8f\u4e2d\u4f7f\u7528 MVC \u63a7\u5236\u5668\uff0c\u8bf7\u5728 WebApplicationBuilder \u4e0a\u8c03\u7528 AddControllersWithViews\uff08\uff09\u3002\u8fd9\u4f1a\u5c06 MVC \u63a7\u5236\u5668\u548c Razor \u89c6\u56fe\u5448\u73b0\u6240\u9700\u7684\u6240\u6709\u670d\u52a1\u6dfb\u52a0\u5230\u4f9d\u8d56\u9879\u6ce8\u5165\u5bb9\u5668\u4e2d\u3002<\/p>\n<p>MVC controllers typically use conventional routing to select an MVC controller and action method. Instead of associating a route template with each action method in your application, conventional routing specifies one or more route template patterns that map to multiple endpoints. Conventional routes must define a controller and action route parameter to determine the action to execute.<br \/>\nMVC \u63a7\u5236\u5668\u901a\u5e38\u4f7f\u7528\u4f20\u7edf\u8def\u7531\u6765\u9009\u62e9 MVC \u63a7\u5236\u5668\u548c\u4f5c\u65b9\u6cd5\u3002\u4f20\u7edf\u8def\u7531\u4e0d\u662f\u5c06\u8def\u7531\u6a21\u677f\u4e0e\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u6bcf\u4e2a\u4f5c\u65b9\u6cd5\u76f8\u5173\u8054\uff0c\u800c\u662f\u6307\u5b9a\u4e00\u4e2a\u6216\u591a\u4e2a\u6620\u5c04\u5230\u591a\u4e2a\u7ec8\u7aef\u8282\u70b9\u7684\u8def\u7531\u6a21\u677f\u6a21\u5f0f\u3002\u4f20\u7edf\u8def\u7531\u5fc5\u987b\u5b9a\u4e49\u63a7\u5236\u5668\u548c\u4f5c\u8def\u7531\u53c2\u6570\uff0c\u4ee5\u786e\u5b9a\u8981\u6267\u884c\u7684\u4f5c\u3002<\/p>\n<p>You can return IActionResult instances from MVC controllers and they are executed in the same way as for Razor Pages. The most commonly returned type is ViewResult, using the View() helper method, which instructs the framework to render a Razor view.<br \/>\n\u53ef\u4ee5\u4ece MVC \u63a7\u5236\u5668\u8fd4\u56de IActionResult \u5b9e\u4f8b\uff0c\u8fd9\u4e9b\u5b9e\u4f8b\u7684\u6267\u884c\u65b9\u5f0f\u4e0e Razor Pages \u76f8\u540c\u3002\u6700\u5e38\u8fd4\u56de\u7684\u7c7b\u578b\u662f ViewResult\uff0c\u5b83\u4f7f\u7528 View\uff08\uff09 \u5e2e\u52a9\u7a0b\u5e8f\u65b9\u6cd5\uff0c\u8be5\u65b9\u6cd5\u6307\u793a\u6846\u67b6\u5448\u73b0 Razor \u89c6\u56fe\u3002<\/p>\n<p>ViewResult may contain the name of the view to render and optionally a view model object to use when rendering the view. If the view name is not provided, a view is chosen using conventions.<br \/>\nViewResult \u53ef\u80fd\u5305\u542b\u8981\u6e32\u67d3\u7684\u89c6\u56fe\u7684\u540d\u79f0\uff0c\u4ee5\u53ca\u6e32\u67d3\u89c6\u56fe\u65f6\u8981\u4f7f\u7528\u7684\u89c6\u56fe\u6a21\u578b\u5bf9\u8c61\uff08\u53ef\u9009\uff09\u3002\u5982\u679c\u672a\u63d0\u4f9b\u89c6\u56fe\u540d\u79f0\uff0c\u5219\u4f7f\u7528\u7ea6\u5b9a\u9009\u62e9\u89c6\u56fe\u3002<\/p>\n<p>By convention, MVC Razor views are named the same as the action method that invokes them. They reside either in a folder with the same name as the action method\u2019s controller or in the Shared folder.<br \/>\n\u6309\u7167\u7ea6\u5b9a\uff0cMVC Razor \u89c6\u56fe\u7684\u540d\u79f0\u4e0e\u8c03\u7528\u5b83\u4eec\u7684\u4f5c\u65b9\u6cd5\u76f8\u540c\u3002\u5b83\u4eec\u4f4d\u4e8e\u4e0e\u4f5c\u65b9\u6cd5\u7684\u63a7\u5236\u5668\u540c\u540d\u7684\u6587\u4ef6\u5939\u4e2d\uff0c\u6216\u8005\u4f4d\u4e8e Shared \u6587\u4ef6\u5939\u4e2d\u3002<\/p>\n<p>MVC controllers contain multiple action methods, typically grouped around a high-level entity or resource. In contrast, Razor Pages groups all the page handlers for a single page in one place, grouping around a page\/feature instead of an entity. This gives improved developer ergonomics when working on an endpoint.<br \/>\nMVC \u63a7\u5236\u5668\u5305\u542b\u591a\u4e2a\u4f5c\u65b9\u6cd5\uff0c\u901a\u5e38\u56f4\u7ed5\u9ad8\u7ea7\u5b9e\u4f53\u6216\u8d44\u6e90\u8fdb\u884c\u5206\u7ec4\u3002\u76f8\u6bd4\u4e4b\u4e0b\uff0cRazor Pages \u5c06\u5355\u4e2a\u9875\u9762\u7684\u6240\u6709\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u5206\u7ec4\u5230\u4e00\u4e2a\u4f4d\u7f6e\uff0c\u56f4\u7ed5\u9875\u9762\/\u529f\u80fd\u800c\u4e0d\u662f\u5b9e\u4f53\u8fdb\u884c\u5206\u7ec4\u3002\u8fd9\u4e3a\u5f00\u53d1\u4eba\u5458\u5728\u7aef\u70b9\u4e0a\u5de5\u4f5c\u65f6\u63d0\u4f9b\u4e86\u6539\u8fdb\u7684\u4eba\u4f53\u5de5\u7a0b\u5b66\u3002<\/p>\n<p>MVC controllers may make sense over Razor Pages if you are upgrading an application that already uses MVC controllers or if your application is using a lot of partial page updates.<br \/>\n\u5982\u679c\u8981\u5347\u7ea7\u5df2\u4f7f\u7528 MVC \u63a7\u5236\u5668\u7684\u5e94\u7528\u7a0b\u5e8f\uff0c\u6216\u8005\u5e94\u7528\u7a0b\u5e8f\u6b63\u5728\u4f7f\u7528\u5927\u91cf\u90e8\u5206\u9875\u9762\u66f4\u65b0\uff0c\u5219 MVC \u63a7\u5236\u5668\u53ef\u80fd\u5bf9 Razor Pages \u6709\u610f\u4e49\u3002<\/p>\n<p>[1] Before moving to Razor Pages, the ASP.NET Core template that includes user login functionality contained two such controllers, each containing more than 20 action methods and more than 500 lines of code!<br \/>\n[1] \u5728\u8fc1\u79fb\u5230 Razor Pages \u4e4b\u524d\uff0c\u5305\u542b\u7528\u6237\u767b\u5f55\u529f\u80fd\u7684 ASP.NET Core \u6a21\u677f\u5305\u542b\u4e24\u4e2a\u8fd9\u6837\u7684\u63a7\u5236\u5668\uff0c\u6bcf\u4e2a\u63a7\u5236\u5668\u5305\u542b 20 \u591a\u4e2a\u4f5c\u65b9\u6cd5\u548c 500 \u591a\u884c\u4ee3\u7801\uff01<\/p>\n","protected":false},"excerpt":{"rendered":"<p>19 Creating a website with MVC controllers 19 \u4f7f\u7528 MVC \u63a7\u5236\u5668\u521b\u5efa\u7f51\u7ad9 This chapter covers \u672c\u7ae0\u6db5\u76d6 \u2022 Creating a Model-View-Controller (MVC) application \u521b\u5efa\u6a21\u578b-\u89c6\u56fe-\u63a7\u5236\u5668 \uff08MVC\uff09 \u5e94\u7528\u7a0b\u5e8f \u2022 Choosing between Razor Pages and MVC controllers \u5728 Razor Pages \u548c MVC \u63a7\u5236\u5668\u4e4b\u95f4\u8fdb\u884c\u9009\u62e9 \u2022 Returning Razor views from MVC controllers \u4ece MVC \u63a7\u5236\u5668\u8fd4\u56de Razor \u89c6\u56fe In this book I\u2019ve focused [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[],"class_list":["post-609","post","type-post","status-publish","format-standard","hentry","category-csharp"],"_links":{"self":[{"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts\/609","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=609"}],"version-history":[{"count":0,"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts\/609\/revisions"}],"wp:attachment":[{"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=609"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=609"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=609"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}