{"id":597,"date":"2025-04-05T11:38:32","date_gmt":"2025-04-05T03:38:32","guid":{"rendered":"https:\/\/www.hyy.net\/?p=597"},"modified":"2025-04-05T11:38:32","modified_gmt":"2025-04-05T03:38:32","slug":"asp-net-core-in-action-13-creating-a-website-with-razor-pages","status":"publish","type":"post","link":"https:\/\/diji.net\/?p=597","title":{"rendered":"ASP.NET Core in Action 13 Creating a website with Razor Pages"},"content":{"rendered":"<h2>Part 3 Generating HTML with Razor Pages and MVC<\/h2>\n<h2>\u7b2c 3 \u90e8\u5206\uff1a\u4f7f\u7528 Razor Pages \u548c MVC \u751f\u6210 HTML<\/h2>\n<p>In parts 1 and 2 we looked in detail at how to create JSON API applications using minimal APIs. You learned how to configure your app from multiple sources, how to use dependency injection to reduce coupling in your app, and how to document your APIs with OpenAPI.<\/p>\n<p>\u5728\u7b2c 1 \u90e8\u5206\u548c\u7b2c 2 \u90e8\u5206\u4e2d\uff0c\u6211\u4eec\u8be6\u7ec6\u4ecb\u7ecd\u4e86\u5982\u4f55\u4f7f\u7528\u6700\u5c11\u7684 API \u521b\u5efa JSON API \u5e94\u7528\u7a0b\u5e8f\u3002\u60a8\u5b66\u4e60\u4e86\u5982\u4f55\u4ece\u591a\u4e2a\u6765\u6e90\u914d\u7f6e\u5e94\u7528\u7a0b\u5e8f\uff0c\u5982\u4f55\u4f7f\u7528\u4f9d\u8d56\u5173\u7cfb\u6ce8\u5165\u6765\u51cf\u5c11\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u8026\u5408\uff0c\u4ee5\u53ca\u5982\u4f55\u4f7f\u7528 OpenAPI \u8bb0\u5f55 API\u3002<\/p>\n<p>API apps are everywhere these days. Mobile apps use them; clients-side Single Page Applications (SPAs) like Angular, React, or Blazor use them; even other apps use them for server-to-server communication. But in many cases, you don\u2019t need separate server-side and client-side apps. Instead, you could create a server-rendered app.<\/p>\n<p>\u5982\u4eca\uff0cAPI \u5e94\u7528\u7a0b\u5e8f\u65e0\u5904\u4e0d\u5728\u3002\u79fb\u52a8\u5e94\u7528\u7a0b\u5e8f\u4f7f\u7528\u5b83\u4eec;Angular\u3001React \u6216 Blazor \u7b49\u5ba2\u6237\u7aef\u5355\u9875\u5e94\u7528\u7a0b\u5e8f \uff08SPA\uff09 \u4f7f\u7528\u5b83\u4eec;\u751a\u81f3\u5176\u4ed6\u5e94\u7528\u7a0b\u5e8f\u4e5f\u4f7f\u7528\u5b83\u4eec\u8fdb\u884c\u670d\u52a1\u5668\u5230\u670d\u52a1\u5668\u7684\u901a\u4fe1\u3002\u4f46\u5728\u8bb8\u591a\u60c5\u51b5\u4e0b\uff0c\u60a8\u4e0d\u9700\u8981\u5355\u72ec\u7684\u670d\u52a1\u5668\u7aef\u548c\u5ba2\u6237\u7aef\u5e94\u7528\u7a0b\u5e8f\u3002\u76f8\u53cd\uff0c\u60a8\u53ef\u4ee5\u521b\u5efa\u670d\u52a1\u5668\u5448\u73b0\u7684\u5e94\u7528\u7a0b\u5e8f\u3002<\/p>\n<p>With server-rendering, your application generates the HTML on the server and the browser displays this directly in the browser; no extra client-side framework required. You can still add dynamic client-side behavior using JavaScript, but fundamentally each page in your app is a standalone request and response, which gives a simpler developer experience.<\/p>\n<p>\u4f7f\u7528\u670d\u52a1\u5668\u5448\u73b0\u65f6\uff0c\u5e94\u7528\u7a0b\u5e8f\u4f1a\u5728\u670d\u52a1\u5668\u4e0a\u751f\u6210 HTML\uff0c\u6d4f\u89c8\u5668\u4f1a\u76f4\u63a5\u5728\u6d4f\u89c8\u5668\u4e2d\u663e\u793a HTML;\u4e0d\u9700\u8981\u989d\u5916\u7684\u5ba2\u6237\u7aef\u6846\u67b6\u3002\u60a8\u4ecd\u7136\u53ef\u4ee5\u4f7f\u7528 JavaScript \u6dfb\u52a0\u52a8\u6001\u5ba2\u6237\u7aef\u884c\u4e3a\uff0c\u4f46\u4ece\u6839\u672c\u4e0a\u8bf4\uff0c\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u6bcf\u4e2a\u9875\u9762\u90fd\u662f\u4e00\u4e2a\u72ec\u7acb\u7684\u8bf7\u6c42\u548c\u54cd\u5e94\uff0c\u8fd9\u63d0\u4f9b\u4e86\u66f4\u7b80\u5355\u7684\u5f00\u53d1\u4eba\u5458\u4f53\u9a8c\u3002<\/p>\n<p>In part 3, you\u2019ll learn about the Razor Pages and MVC frameworks used by ASP.NET Core to create server-rendered apps. In chapters 13 through 16 we\u2019ll examine the behavior of the Razor Pages framework itself, routing, and model binding. In chapters 17 and 18 we\u2019ll look at how you can build the UI for your application using the Razor syntax and Tag Helpers, so that users can navigate and interact with your app.<\/p>\n<p>\u5728\u7b2c 3 \u90e8\u5206\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3 ASP.NET Core \u7528\u4e8e\u521b\u5efa\u670d\u52a1\u5668\u6e32\u67d3\u5e94\u7528\u7684 Razor Pages \u548c MVC \u6846\u67b6\u3002\u5728\u7b2c 13 \u7ae0\u5230\u7b2c 16 \u7ae0\u4e2d\uff0c\u6211\u4eec\u5c06\u7814\u7a76 Razor Pages \u6846\u67b6\u672c\u8eab\u7684\u884c\u4e3a\u3001\u8def\u7531\u548c\u6a21\u578b\u7ed1\u5b9a\u3002\u5728\u7b2c 17 \u7ae0\u548c\u7b2c 18 \u7ae0\u4e2d\uff0c\u6211\u4eec\u5c06\u4ecb\u7ecd\u5982\u4f55\u4f7f\u7528 Razor \u8bed\u6cd5\u548c\u6807\u8bb0\u5e2e\u52a9\u7a0b\u5e8f\u4e3a\u5e94\u7528\u7a0b\u5e8f\u6784\u5efa UI\uff0c\u4ee5\u4fbf\u7528\u6237\u53ef\u4ee5\u5bfc\u822a\u5e94\u7528\u5e76\u4e0e\u4e4b\u4ea4\u4e92\u3002<\/p>\n<p>In chapter 19 you\u2019ll learn how to use the MVC framework directly, instead of Razor Pages. You\u2019ll learn how to use MVC controllers to build server-rendered apps and when to choose MVC controllers instead of Razor Pages. In chapter 20 you\u2019ll learn to how to use MVC controllers to build API applications, as an alternative to minimal APIs. Finally, in chapters 21 and 22 you\u2019ll learn how to refactor your apps to extract common code out of your Razor Pages and API controllers using filters.<\/p>\n<p>\u5728\u7b2c 19 \u7ae0\u4e2d\uff0c\u60a8\u5c06\u5b66\u4e60\u5982\u4f55\u76f4\u63a5\u4f7f\u7528 MVC \u6846\u67b6\uff0c\u800c\u4e0d\u662f Razor Pages\u3002\u60a8\u5c06\u5b66\u4e60\u5982\u4f55\u4f7f\u7528 MVC \u63a7\u5236\u5668\u6784\u5efa\u670d\u52a1\u5668\u5448\u73b0\u7684\u5e94\u7528\u7a0b\u5e8f\uff0c\u4ee5\u53ca\u4f55\u65f6\u9009\u62e9 MVC \u63a7\u5236\u5668\u800c\u4e0d\u662f Razor Pages\u3002\u5728\u7b2c 20 \u7ae0\u4e2d\uff0c\u60a8\u5c06\u5b66\u4e60\u5982\u4f55\u4f7f\u7528 MVC \u63a7\u5236\u5668\u6765\u6784\u5efa API \u5e94\u7528\u7a0b\u5e8f\uff0c\u4f5c\u4e3a\u6700\u5c0f API \u7684\u66ff\u4ee3\u65b9\u6848\u3002\u6700\u540e\uff0c\u5728\u7b2c 21 \u7ae0\u548c\u7b2c 22 \u7ae0\u4e2d\uff0c\u60a8\u5c06\u5b66\u4e60\u5982\u4f55\u91cd\u6784\u5e94\u7528\u7a0b\u5e8f\uff0c\u4ee5\u4f7f\u7528\u7b5b\u9009\u5668\u4ece Razor Pages \u548c API \u63a7\u5236\u5668\u4e2d\u63d0\u53d6\u5e38\u89c1\u4ee3\u7801\u3002<\/p>\n<p>13 Creating a website with Razor Pages<br \/>\n13 \u4f7f\u7528 Razor Pages \u521b\u5efa\u7f51\u7ad9<\/p>\n<h2>This chapter covers<\/h2>\n<h2>\u672c\u7ae0\u6db5\u76d6<\/h2>\n<ul>\n<li>\n<p>Getting started with Razor Pages<br \/>\nRazor Pages \u5165\u95e8<\/p>\n<\/li>\n<li>\n<p>Introducing Razor Pages and the Model-View-Controller (MVC) design pattern<br \/>\nRazor Pages \u548c\u6a21\u578b-\u89c6\u56fe-\u63a7\u5236\u5668 \uff08MVC\uff09 \u8bbe\u8ba1\u6a21\u5f0f\u7b80\u4ecb<\/p>\n<\/li>\n<li>\n<p>Using Razor Pages in ASP.NET Core<br \/>\n\u5728 ASP.NET Core \u4e2d\u4f7f\u7528 Razor Pages<\/p>\n<\/li>\n<\/ul>\n<p>So far in this book you\u2019ve built one type of ASP.NET Core application: minimal API apps that return JavaScript Object Notation (JSON). In this chapter you\u2019ll learn how to build server-rendered, page-based applications using Razor Pages. Most ASP.NET Core apps fall into one of three categories:<\/p>\n<p>\u5230\u76ee\u524d\u4e3a\u6b62\uff0c\u5728\u672c\u4e66\u4e2d\uff0c\u60a8\u5df2\u7ecf\u6784\u5efa\u4e86\u4e00\u79cd\u7c7b\u578b\u7684 ASP.NET Core \u5e94\u7528\u7a0b\u5e8f\uff1a\u8fd4\u56de JavaScript \u5bf9\u8c61\u8868\u793a\u6cd5 \uff08JSON\uff09 \u7684\u6700\u5c0f API \u5e94\u7528\u7a0b\u5e8f\u3002\u5728\u672c\u7ae0\u4e2d\uff0c\u60a8\u5c06\u5b66\u4e60\u5982\u4f55\u4f7f\u7528 Razor Pages \u6784\u5efa\u670d\u52a1\u5668\u6e32\u67d3\u7684\u3001\u57fa\u4e8e\u9875\u9762\u7684\u5e94\u7528\u7a0b\u5e8f\u3002\u5927\u591a\u6570 ASP.NET Core \u5e94\u7528\u7a0b\u5e8f\u90fd\u5c5e\u4e8e\u4ee5\u4e0b\u4e09\u7c7b\u4e4b\u4e00\uff1a<\/p>\n<ul>\n<li>\n<p>An API designed for consumption by another machine or in code\u2014Web apps often serve as an API to backend server processes, to a mobile app, or to a client framework for building single-page applications (SPAs). In this case your application serves data in machine-readable formats such as JSON or Extensible Markup Language (XML) instead of the human-focused HTML output.<br \/>\n\u4f9b\u5176\u4ed6\u8ba1\u7b97\u673a\u4f7f\u7528\u6216\u5728\u4ee3\u7801\u4e2d\u4f7f\u7528\u7684 API \u2014 Web \u5e94\u7528\u7a0b\u5e8f\u901a\u5e38\u7528\u4f5c\u540e\u7aef\u670d\u52a1\u5668\u8fdb\u7a0b\u3001\u79fb\u52a8\u5e94\u7528\u7a0b\u5e8f\u6216\u7528\u4e8e\u6784\u5efa\u5355\u9875\u5e94\u7528\u7a0b\u5e8f \uff08SPA\uff09 \u7684\u5ba2\u6237\u7aef\u6846\u67b6\u7684 API\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u4ee5\u673a\u5668\u53ef\u8bfb\u683c\u5f0f\uff08\u5982 JSON \u6216\u53ef\u6269\u5c55\u6807\u8bb0\u8bed\u8a00 \uff08XML\uff09\uff09\u800c\u4e0d\u662f\u4ee5\u4eba\u7c7b\u4e3a\u4e2d\u5fc3\u7684 HTML \u8f93\u51fa\u63d0\u4f9b\u6570\u636e\u3002<\/p>\n<\/li>\n<li>\n<p>An HTML web application designed for direct use by users\u2014If the application is consumed directly by users, as in a traditional web application, Razor Pages is responsible for generating the web pages that the user interacts with. It handles requests for URLs, receives data posted via forms, and generates the HTML that enables users to view and navigate your app.<br \/>\n\u4e13\u4e3a\u7528\u6237\u76f4\u63a5\u4f7f\u7528\u800c\u8bbe\u8ba1\u7684 HTML Web \u5e94\u7528\u7a0b\u5e8f \u2013 \u5982\u679c\u5e94\u7528\u7a0b\u5e8f\u7531\u7528\u6237\u76f4\u63a5\u4f7f\u7528\uff0c\u5c31\u50cf\u5728\u4f20\u7edf Web \u5e94\u7528\u7a0b\u5e8f\u4e2d\u4e00\u6837\uff0cRazor Pages \u8d1f\u8d23\u751f\u6210\u7528\u6237\u4e0e\u4e4b\u4ea4\u4e92\u7684\u7f51\u9875\u3002\u5b83\u5904\u7406\u5bf9 URL \u7684\u8bf7\u6c42\uff0c\u63a5\u6536\u901a\u8fc7\u8868\u5355\u53d1\u5e03\u7684\u6570\u636e\uff0c\u5e76\u751f\u6210\u4f7f\u7528\u6237\u80fd\u591f\u67e5\u770b\u548c\u5bfc\u822a\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u7684 HTML\u3002<\/p>\n<\/li>\n<li>\n<p>Both an HTML web application and an API\u2014It\u2019s also possible to have applications that serve both needs, which can let you cater to a wider range of clients while sharing logic in your application.<br \/>\nHTML Web \u5e94\u7528\u7a0b\u5e8f\u548c API \u2014 \u4e5f\u53ef\u4ee5\u62e5\u6709\u540c\u65f6\u6ee1\u8db3\u8fd9\u4e24\u79cd\u9700\u6c42\u7684\u5e94\u7528\u7a0b\u5e8f\uff0c\u8fd9\u6837\u60a8\u5c31\u53ef\u4ee5\u5728\u5e94\u7528\u7a0b\u5e8f\u4e2d\u5171\u4eab\u903b\u8f91\u7684\u540c\u65f6\u6ee1\u8db3\u66f4\u5e7f\u6cdb\u7684\u5ba2\u6237\u7aef\u9700\u6c42\u3002<\/p>\n<\/li>\n<\/ul>\n<p>In this chapter you\u2019ll learn how ASP.NET Core uses Razor Pages to handle the second of these options: creating server-side rendered HTML pages. We\u2019ll get started quickly, using a template to create a simple Razor Pages application and comparing the features of a Razor Pages app with the minimal API apps you\u2019ve seen so far. In section 13.2 we look at a more complex example of a Razor Page.<\/p>\n<p>\u5728\u672c\u7ae0\u4e2d\uff0c\u4f60\u5c06\u4e86\u89e3 ASP.NET Core \u5982\u4f55\u4f7f\u7528 Razor Pages \u6765\u5904\u7406\u7b2c\u4e8c\u4e2a\u9009\u9879\uff1a\u521b\u5efa\u670d\u52a1\u5668\u7aef\u5448\u73b0\u7684 HTML \u9875\u9762\u3002\u6211\u4eec\u5c06\u5feb\u901f\u5165\u95e8\uff0c\u4f7f\u7528\u6a21\u677f\u521b\u5efa\u7b80\u5355\u7684 Razor Pages \u5e94\u7528\u7a0b\u5e8f\uff0c\u5e76\u5c06 Razor Pages \u5e94\u7528\u7684\u529f\u80fd\u4e0e\u4f60\u76ee\u524d\u770b\u5230\u7684\u6700\u5c0f API \u5e94\u7528\u8fdb\u884c\u6bd4\u8f83\u3002\u5728 Section 13.2 \u4e2d\uff0c\u6211\u4eec\u770b\u4e00\u4e2a\u66f4\u590d\u6742\u7684 Razor Page \u793a\u4f8b\u3002<\/p>\n<p>Next, we take a step back in section 13.3 to look at the MVC design pattern. I discuss some of the benefits of using this pattern, and you\u2019ll learn why it\u2019s been adopted by so many web frameworks as a model for building maintainable applications.<\/p>\n<p>\u63a5\u4e0b\u6765\uff0c\u6211\u4eec\u5728 Section 13.3 \u4e2d\u540e\u9000\u4e00\u6b65\uff0c\u770b\u770b MVC \u8bbe\u8ba1\u6a21\u5f0f\u3002\u6211\u5c06\u8ba8\u8bba\u4f7f\u7528\u6b64\u6a21\u5f0f\u7684\u4e00\u4e9b\u597d\u5904\uff0c\u60a8\u5c06\u4e86\u89e3\u4e3a\u4ec0\u4e48\u5b83\u88ab\u5982\u6b64\u591a\u7684 Web \u6846\u67b6\u7528\u4f5c\u6784\u5efa\u53ef\u7ef4\u62a4\u5e94\u7528\u7a0b\u5e8f\u7684\u6a21\u578b\u3002<\/p>\n<p>In section 13.4 you\u2019ll learn how the MVC design pattern applies to ASP.NET Core. The MVC pattern is a broad concept that can be applied in a variety of situations, but the use case in ASP.NET Core is specifically as a UI abstraction. You\u2019ll see how Razor Pages implements the MVC design pattern and builds on top of the ASP.NET Core MVC framework.<\/p>\n<p>\u5728\u7b2c 13.4 \u8282\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3 MVC \u8bbe\u8ba1\u6a21\u5f0f\u5982\u4f55\u5e94\u7528\u4e8e ASP.NET Core\u3002MVC \u6a21\u5f0f\u662f\u4e00\u4e2a\u5e7f\u6cdb\u7684\u6982\u5ff5\uff0c\u53ef\u4ee5\u5e94\u7528\u4e8e\u5404\u79cd\u60c5\u51b5\uff0c\u4f46 ASP.NET Core \u4e2d\u7684\u7528\u4f8b\u4e13\u95e8\u7528\u4f5c UI \u62bd\u8c61\u3002\u60a8\u5c06\u4e86\u89e3 Razor Pages \u5982\u4f55\u5b9e\u73b0 MVC \u8bbe\u8ba1\u6a21\u5f0f\u5e76\u5728 ASP.NET Core MVC \u6846\u67b6\u4e4b\u4e0a\u6784\u5efa\u3002<\/p>\n<p>In this chapter I\u2019ll try to prepare you for each of the upcoming topics, but you may find that some of the behavior feels a bit like magic at this stage. Try not to become too concerned about exactly how all the Razor Pages pieces tie together yet; focus on the specific concepts being addressed and how they tie into concepts you\u2019ve already met. We\u2019ll start by creating a Razor Pages app to explore.<\/p>\n<p>\u5728\u672c\u7ae0\u4e2d\uff0c\u6211\u5c06\u5c1d\u8bd5\u8ba9\u60a8\u4e3a\u5373\u5c06\u5230\u6765\u7684\u6bcf\u4e2a\u4e3b\u9898\u505a\u597d\u51c6\u5907\uff0c\u4f46\u60a8\u53ef\u80fd\u4f1a\u53d1\u73b0\uff0c\u5728\u8fd9\u4e2a\u9636\u6bb5\uff0c\u67d0\u4e9b\u884c\u4e3a\u611f\u89c9\u6709\u70b9\u50cf\u9b54\u672f\u3002\u5c3d\u91cf\u4e0d\u8981\u592a\u5173\u5fc3\u6240\u6709 Razor Pages \u4f5c\u54c1\u7a76\u7adf\u662f\u5982\u4f55\u8054\u7cfb\u5728\u4e00\u8d77\u7684;\u4e13\u6ce8\u4e8e\u8981\u89e3\u51b3\u7684\u5177\u4f53\u6982\u5ff5\u4ee5\u53ca\u5b83\u4eec\u5982\u4f55\u4e0e\u60a8\u5df2\u7ecf\u9047\u5230\u7684\u6982\u5ff5\u76f8\u5173\u8054\u3002\u9996\u5148\uff0c\u6211\u4eec\u5c06\u521b\u5efa\u4e00\u4e2a Razor Pages \u5e94\u7528\u8fdb\u884c\u63a2\u7d22\u3002<\/p>\n<h2>13.1 Your first Razor Pages application<\/h2>\n<h2>13.1 \u60a8\u7684\u7b2c\u4e00\u4e2a Razor Pages \u5e94\u7528\u7a0b\u5e8f<\/h2>\n<p>In this section you\u2019ll get started with Razor Pages by creating a new application from a template. After you\u2019ve created the app and had a look around, we\u2019ll look at some of the similarities and differences compared with a minimal API application. You\u2019ll learn about the extra middleware added in the default template, look at how HTML is generated by Razor Pages, and take a look at the Razor Page equivalent of minimal API endpoint handlers: page handlers.<\/p>\n<p>\u5728\u672c\u90e8\u5206\u4e2d\uff0c\u4f60\u5c06\u901a\u8fc7\u4ece\u6a21\u677f\u521b\u5efa\u65b0\u5e94\u7528\u7a0b\u5e8f\u6765\u5f00\u59cb\u4f7f\u7528 Razor Pages\u3002\u5728\u60a8\u521b\u5efa\u5e94\u7528\u7a0b\u5e8f\u5e76\u73af\u987e\u56db\u5468\u540e\uff0c\u6211\u4eec\u5c06\u4e86\u89e3\u4e0e\u6700\u5c0f API \u5e94\u7528\u7a0b\u5e8f\u76f8\u6bd4\u7684\u4e00\u4e9b\u76f8\u4f3c\u4e4b\u5904\u548c\u4e0d\u540c\u4e4b\u5904\u3002\u60a8\u5c06\u4e86\u89e3\u9ed8\u8ba4\u6a21\u677f\u4e2d\u6dfb\u52a0\u7684\u989d\u5916\u4e2d\u95f4\u4ef6\uff0c\u4e86\u89e3 Razor Pages \u5982\u4f55\u751f\u6210 HTML\uff0c\u5e76\u67e5\u770b Razor Page \u7b49\u4ef7\u7684\u6700\u5c0f API \u7aef\u70b9\u5904\u7406\u7a0b\u5e8f\uff1a\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u3002<\/p>\n<h3>13.1.1 Using the Web Application template<\/h3>\n<h3>13.1.1 \u4f7f\u7528 Web \u5e94\u7528\u7a0b\u5e8f\u6a21\u677f<\/h3>\n<p>Using a template is a quick way to get an application running, so we\u2019ll take that approach using the ASP.NET Core Web App template. To create a Razor Pages application in Visual Studio, perform the following steps:<\/p>\n<p>\u4f7f\u7528\u6a21\u677f\u662f\u8fd0\u884c\u5e94\u7528\u7a0b\u5e8f\u7684\u4e00\u79cd\u5feb\u901f\u65b9\u6cd5\uff0c\u56e0\u6b64\u6211\u4eec\u5c06\u4f7f\u7528 ASP.NET Core \u6765\u91c7\u7528\u8fd9\u79cd\u65b9\u6cd5Web App \u6a21\u677f\u3002\u8981\u5728 Visual Studio \u4e2d\u521b\u5efa Razor Pages \u5e94\u7528\u7a0b\u5e8f\uff0c\u8bf7\u6267\u884c\u4ee5\u4e0b\u6b65\u9aa4\uff1a<\/p>\n<ol>\n<li>\n<p>Choose Create a New Project from the splash screen or choose File &gt; New &gt; Project from the main Visual Studio screen.<br \/>\n\u4ece\u521d\u59cb\u5c4f\u5e55\u4e2d\u9009\u62e9 Create a New Project\uff0c\u6216\u4ece Visual Studio \u4e3b\u5c4f\u5e55\u4e2d\u9009\u62e9 File &gt; New &gt; Project\u3002<\/p>\n<\/li>\n<li>\n<p>From the list of templates, choose ASP.NET Core Web App, ensuring you select the C# language template.<br \/>\n\u4ece\u6a21\u677f\u5217\u8868\u4e2d\uff0c\u9009\u62e9 ASP.NET Core Web App\uff0c\u786e\u4fdd\u9009\u62e9 C# \u8bed\u8a00\u6a21\u677f\u3002<\/p>\n<\/li>\n<li>\n<p>On the next screen, enter a project name, location, and solution name, and click Next. You might use WebApplication1 as both the project and solution name, for example.<br \/>\n\u5728\u4e0b\u4e00\u4e2a\u5c4f\u5e55\u4e0a\uff0c\u8f93\u5165\u9879\u76ee\u540d\u79f0\u3001\u4f4d\u7f6e\u548c\u89e3\u51b3\u65b9\u6848\u540d\u79f0\uff0c\u7136\u540e\u5355\u51fb Next\u3002\u4f8b\u5982\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528 WebApplication1 \u4f5c\u4e3a\u9879\u76ee\u548c\u89e3\u51b3\u65b9\u6848\u540d\u79f0\u3002<\/p>\n<\/li>\n<li>\n<p>On the following screen (figure 13.1), do the following:<br \/>\n\u5728\u4ee5\u4e0b\u5c4f\u5e55\uff08\u56fe 13.1\uff09\u4e2d\uff0c\u6267\u884c\u4ee5\u4e0b\u4f5c\uff1a<\/p>\n<\/li>\n<\/ol>\n<ul>\n<li>Select .NET 7.0. If this option isn\u2019t available, ensure that you have .NET 7 installed. See appendix A for details on configuring your environment.<br \/>\n\u9009\u62e9 .NET 7.0\u3002\u5982\u679c\u6b64\u9009\u9879\u4e0d\u53ef\u7528\uff0c\u8bf7\u786e\u4fdd\u60a8\u5df2\u5b89\u88c5 .NET 7\u3002\u6709\u5173\u914d\u7f6e\u73af\u5883\u7684\u8be6\u7ec6\u4fe1\u606f\uff0c\u8bf7\u53c2\u9605\u9644\u5f55 A\u3002<\/li>\n<li>Ensure that Configure for HTTPS is checked.<br \/>\n\u786e\u4fdd\u9009\u4e2d Configure for HTTPS \uff08\u4e3a HTTPS \u914d\u7f6e\uff09\u3002<\/li>\n<li>Ensure that Enable Docker is unchecked.<br \/>\n\u786e\u4fdd Enable Docker \uff08\u542f\u7528 Docker\uff09 \u5904\u4e8e\u672a\u9009\u4e2d\u72b6\u6001\u3002<\/li>\n<li>Ensure that Do not use top-level statements is unchecked.<br \/>\n\u786e\u4fdd Do Not Use Top-level Statements \u672a\u9009\u4e2d\u3002<\/li>\n<li>Choose Create.<br \/>\n\u9009\u62e9 Create \uff08\u521b\u5efa\uff09\u3002<\/li>\n<\/ul>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1301.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 13.1 The additional information screen. This screen follows the Configure Your New Project dialog box and lets you customize the template that generates your application.<br \/>\n\u56fe 13.1 \u9644\u52a0\u4fe1\u606f\u5c4f\u5e55\u3002\u6b64\u5c4f\u5e55\u4f4d\u4e8e Configure Your New Project \u5bf9\u8bdd\u6846\u4e4b\u540e\uff0c\u5141\u8bb8\u60a8\u81ea\u5b9a\u4e49\u751f\u6210\u5e94\u7528\u7a0b\u5e8f\u7684\u6a21\u677f\u3002<\/p>\n<p>If you\u2019re not using Visual Studio, you can create a similar template using the .NET command-line interface (CLI). Create a folder to hold your new project. Open a PowerShell or cmd prompt in the folder (on Windows) or a terminal session (on Linux or macOS), and run the commands in the following listing.<\/p>\n<p>\u5982\u679c\u4e0d\u4f7f\u7528 Visual Studio\uff0c\u5219\u53ef\u4ee5\u4f7f\u7528 .NET \u547d\u4ee4\u884c\u754c\u9762 \uff08CLI\uff09 \u521b\u5efa\u7c7b\u4f3c\u7684\u6a21\u677f\u3002\u521b\u5efa\u4e00\u4e2a\u6587\u4ef6\u5939\u6765\u4fdd\u5b58\u60a8\u7684\u65b0\u9879\u76ee\u3002\u5728\u6587\u4ef6\u5939\uff08\u5728 Windows \u4e0a\uff09\u6216\u7ec8\u7aef\u4f1a\u8bdd\uff08\u5728 Linux \u6216 macOS \u4e0a\uff09\u4e2d\u6253\u5f00 PowerShell \u6216 cmd \u63d0\u793a\u7b26\uff0c\u7136\u540e\u8fd0\u884c\u4ee5\u4e0b\u5217\u8868\u4e2d\u7684\u547d\u4ee4\u3002<\/p>\n<p>Listing 13.1 Creating a new Razor Page application with the .NET CLI<br \/>\n\u6e05\u5355 13.1 \u4f7f\u7528 .NET CLI\u521b\u5efa\u65b0\u7684 Razor Page \u5e94\u7528\u7a0b\u5e8f<\/p>\n<pre><code>dotnet new sln -n WebApplication1     \u2776\ndotnet new razor -o WebApplication1   \u2777\ndotnet sln add WebApplication1        \u2778<\/code><\/pre>\n<p>\u2776 Creates a solution file called WebApplication1 in the current folder<br \/>\n\u5728\u5f53\u524d\u6587\u4ef6\u5939\u4e2d\u521b\u5efa\u540d\u4e3a WebApplication1 \u7684\u89e3\u51b3\u65b9\u6848\u6587\u4ef6<br \/>\n\u2777 Creates an ASP.NET Core Razor Pages project in a subfolder, WebApplication1<br \/>\n\u5728\u5b50\u6587\u4ef6\u5939 WebApplication1 \u4e2d\u521b\u5efa ASP.NET Core Razor Pages \u9879\u76ee<br \/>\n\u2778 Adds the new project to the solution file<br \/>\n\u5c06\u65b0\u9879\u76ee\u6dfb\u52a0\u5230\u89e3\u51b3\u65b9\u6848\u6587\u4ef6\u4e2d<\/p>\n<p>Whether you use Visual Studio or the .NET CLI, now you can build and run your application. Press F5 to run your app using Visual Studio, or use dotnet run in the project folder. This command opens the appropriate URL in a web browser and displays the basic Welcome page, shown in figure 13.2.<\/p>\n<p>\u65e0\u8bba\u60a8\u4f7f\u7528\u7684\u662f Visual Studio \u8fd8\u662f .NET CLI\uff0c\u73b0\u5728\u90fd\u53ef\u4ee5\u6784\u5efa\u548c\u8fd0\u884c\u5e94\u7528\u7a0b\u5e8f\u3002\u6309 F5 \u4f7f\u7528 Visual Studio \u8fd0\u884c\u5e94\u7528\uff0c\u6216\u4f7f\u7528\u9879\u76ee\u6587\u4ef6\u5939\u4e2d\u7684 dotnet run\u3002\u6b64\u547d\u4ee4\u5728 Web \u6d4f\u89c8\u5668\u4e2d\u6253\u5f00\u76f8\u5e94\u7684 URL\uff0c\u5e76\u663e\u793a\u57fa\u672c\u7684 Welcome \u9875\u9762\uff0c\u5982\u56fe 13.2 \u6240\u793a\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1302.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 13.2 The output of your new Razor Pages application. The template chooses a random port to use for your application\u2019s URL, which is opened automatically in the browser when you run the app.<br \/>\n\u56fe 13.2 \u65b0 Razor Pages \u5e94\u7528\u7a0b\u5e8f\u7684\u8f93\u51fa\u3002\u8be5\u6a21\u677f\u9009\u62e9\u4e00\u4e2a\u968f\u673a\u7aef\u53e3\u7528\u4e8e\u5e94\u7528\u7a0b\u5e8f\u7684 URL\uff0c\u5f53\u60a8\u8fd0\u884c\u5e94\u7528\u7a0b\u5e8f\u65f6\uff0c\u8be5\u7aef\u53e3\u4f1a\u81ea\u52a8\u5728\u6d4f\u89c8\u5668\u4e2d\u6253\u5f00\u3002<\/p>\n<p>By default, this page shows a simple Welcome banner and a link to the official Microsoft documentation for ASP.NET Core. At the top of the page are two links: Home and Privacy. The Home link is the page you\u2019re currently on. Clicking Privacy takes you to a new page, shown in figure 13.3. As you\u2019ll see in section 13.1.3, you can use Razor Pages in your application to define these two pages and build the HTML they display.<\/p>\n<p>\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u6b64\u9875\u9762\u663e\u793a\u4e00\u4e2a\u7b80\u5355\u7684\u6b22\u8fce\u6a2a\u5e45\u548c\u4e00\u4e2a\u6307\u5411 ASP.NET Core \u7684\u5b98\u65b9 Microsoft \u6587\u6863\u7684\u94fe\u63a5\u3002\u9875\u9762\u9876\u90e8\u6709\u4e24\u4e2a\u94fe\u63a5\uff1aHome \u548c Privacy\u3002Home link \uff08\u4e3b\u9875\uff09 \u94fe\u63a5\u662f\u60a8\u5f53\u524d\u6240\u5728\u7684\u9875\u9762\u3002\u70b9\u51fb Privacy \u5c06\u5e26\u4f60\u5230\u4e00\u4e2a\u65b0\u9875\u9762\uff0c\u5982\u56fe 13.3 \u6240\u793a\u3002\u5982\u7b2c 13.1.3 \u8282\u6240\u793a\uff0c\u60a8\u53ef\u4ee5\u5728\u5e94\u7528\u7a0b\u5e8f\u4e2d\u4f7f\u7528 Razor Pages \u6765\u5b9a\u4e49\u8fd9\u4e24\u4e2a\u9875\u9762\u5e76\u6784\u5efa\u5b83\u4eec\u663e\u793a\u7684 HTML\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1303.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 13.3 The Privacy page of your application. You can navigate between the two pages of the application using the Home and Privacy links in the application\u2019s header. The app generates the content of the pages using Razor Pages.<br \/>\n\u56fe 13.3 \u5e94\u7528\u7a0b\u5e8f\u7684 Privacy \u9875\u9762\u3002\u60a8\u53ef\u4ee5\u4f7f\u7528\u5e94\u7528\u7a0b\u5e8f\u6807\u9898\u4e2d\u7684 Home \u548c Privacy \u94fe\u63a5\u5728\u5e94\u7528\u7a0b\u5e8f\u7684\u4e24\u4e2a\u9875\u9762\u4e4b\u95f4\u5bfc\u822a\u3002\u8be5\u5e94\u7528\u4f7f\u7528 Razor Pages \u751f\u6210\u9875\u9762\u5185\u5bb9\u3002<\/p>\n<p>At this point, you should notice a couple of things:<br \/>\n\u6b64\u65f6\uff0c\u60a8\u5e94\u8be5\u6ce8\u610f\u4ee5\u4e0b\u51e0\u70b9\uff1a<\/p>\n<ul>\n<li>\n<p>The header containing the links and the application title, WebApplication1, is the same on both pages.<br \/>\n\u5305\u542b\u94fe\u63a5\u548c\u5e94\u7528\u7a0b\u5e8f\u6807\u9898 WebApplication1 \u7684\u6807\u9898\u5728\u4e24\u4e2a\u9875\u9762\u4e0a\u662f\u76f8\u540c\u7684\u3002<\/p>\n<\/li>\n<li>\n<p>The title of the page, as shown in the tab of the browser, changes to match the current page. You\u2019ll see how to achieve these features in chapter 17, when we discuss the rendering of HTML using Razor templates.<br \/>\n\u9875\u9762\u7684\u6807\u9898\uff08\u5982\u6d4f\u89c8\u5668\u9009\u9879\u5361\u4e2d\u6240\u793a\uff09\u4f1a\u66f4\u6539\u4ee5\u5339\u914d\u5f53\u524d\u9875\u9762\u3002\u60a8\u5c06\u5728\u7b2c 17 \u7ae0\u4e2d\u4e86\u89e3\u5982\u4f55\u5b9e\u73b0\u8fd9\u4e9b\u529f\u80fd\uff0c\u5c4a\u65f6\u6211\u4eec\u5c06\u8ba8\u8bba\u4f7f\u7528 Razor \u6a21\u677f\u5448\u73b0 HTML\u3002<\/p>\n<\/li>\n<\/ul>\n<p>There isn\u2019t any more to the user experience of the application at this stage. Click around a little, and when you\u2019re happy with the behavior of the application, return to your editor, and look at the files included in the template.<br \/>\n\u5728\u6b64\u9636\u6bb5\uff0c\u5e94\u7528\u7a0b\u5e8f\u7684\u7528\u6237\u4f53\u9a8c\u4e0d\u518d\u6709\u4efb\u4f55\u53d8\u5316\u3002\u5355\u51fb\u4e00\u4e0b\uff0c\u5f53\u60a8\u5bf9\u5e94\u7528\u7a0b\u5e8f\u7684\u884c\u4e3a\u611f\u5230\u6ee1\u610f\u65f6\uff0c\u8fd4\u56de\u5230\u7f16\u8f91\u5668\uff0c\u5e76\u67e5\u770b\u6a21\u677f\u4e2d\u5305\u542b\u7684\u6587\u4ef6\u3002<\/p>\n<p>This Razor Pages app has much the same structure as the minimal API applications you\u2019ve created throughout this book, as shown in figure 13.4. The overall structure is identical apart from two extra folders you haven\u2019t seen before:<br \/>\n\u6b64 Razor Pages \u5e94\u7528\u7a0b\u5e8f\u7684\u7ed3\u6784\u4e0e\u60a8\u5728\u672c\u4e66\u4e2d\u521b\u5efa\u7684\u6700\u5c0f API \u5e94\u7528\u7a0b\u5e8f\u5927\u81f4\u76f8\u540c\uff0c\u5982\u56fe 13.4 \u6240\u793a\u3002\u9664\u4e86\u4e24\u4e2a\u60a8\u4ee5\u524d\u4ece\u672a\u89c1\u8fc7\u7684\u989d\u5916\u6587\u4ef6\u5939\u5916\uff0c\u6574\u4f53\u7ed3\u6784\u662f\u76f8\u540c\u7684\uff1a<\/p>\n<ul>\n<li>\n<p>Pages folder\u2014This folder contains the Razor Pages files that define the various pages in your web app, including the Home and Privacy pages you\u2019ve already seen.<br \/>\nPages \u6587\u4ef6\u5939 - \u6b64\u6587\u4ef6\u5939\u5305\u542b Razor Pages \u6587\u4ef6\uff0c\u8fd9\u4e9b\u6587\u4ef6\u5b9a\u4e49 Web \u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u5404\u4e2a\u9875\u9762\uff0c\u5305\u62ec\u60a8\u5df2\u7ecf\u770b\u5230\u7684 Home \u548c Privacy \u9875\u9762\u3002<\/p>\n<\/li>\n<li>\n<p>wwwroot folder\u2014This folder is special in that it\u2019s the only folder in your application that browsers are allowed to access directly when browsing your web app. You can store your Cascading Style Sheets (CSS), JavaScript, images, or static HTML files here, and the static file middleware will serve them to browsers when requested. The template creates subfolders inside wwwroot, but you don\u2019t have to use them; you can structure your static files however you want inside wwwroot.<br \/>\nwwwroot \u6587\u4ef6\u5939 - \u6b64\u6587\u4ef6\u5939\u5f88\u7279\u6b8a\uff0c\u56e0\u4e3a\u5b83\u662f\u5e94\u7528\u7a0b\u5e8f\u4e2d\u552f\u4e00\u5141\u8bb8\u6d4f\u89c8\u5668\u5728\u6d4f\u89c8 Web \u5e94\u7528\u7a0b\u5e8f\u65f6\u76f4\u63a5\u8bbf\u95ee\u7684\u6587\u4ef6\u5939\u3002\u60a8\u53ef\u4ee5\u5728\u6b64\u5904\u5b58\u50a8\u7ea7\u8054\u6837\u5f0f\u8868 \uff08CSS\uff09\u3001JavaScript\u3001\u56fe\u50cf\u6216\u9759\u6001 HTML \u6587\u4ef6\uff0c\u9759\u6001\u6587\u4ef6\u4e2d\u95f4\u4ef6\u5c06\u5728\u9700\u8981\u65f6\u5c06\u5b83\u4eec\u63d0\u4f9b\u7ed9\u6d4f\u89c8\u5668\u3002\u8be5\u6a21\u677f\u4f1a\u5728 wwwroot \u4e2d\u521b\u5efa\u5b50\u6587\u4ef6\u5939\uff0c\u4f46\u60a8\u4e0d\u5fc5\u4f7f\u7528\u5b83\u4eec;\u60a8\u53ef\u4ee5\u5728 wwwroot \u4e2d\u6839\u636e\u9700\u8981\u6784\u5efa\u9759\u6001\u6587\u4ef6\u3002<\/p>\n<\/li>\n<\/ul>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1304.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 13.4 Comparing the project structure of a minimal API app with a Razor Pages app. The Razor Pages app contains all the same files and folders, as well as the Pages folder for the Razor Page definitions and the wwwroot file for static files that are served directly to the browser.<br \/>\n\u56fe 13.4 \u6bd4\u8f83\u6700\u5c0f API \u5e94\u7528\u4e0e Razor Pages \u5e94\u7528\u7684\u9879\u76ee\u7ed3\u6784\u3002Razor Pages \u5e94\u7528\u5305\u542b\u6240\u6709\u76f8\u540c\u7684\u6587\u4ef6\u548c\u6587\u4ef6\u5939\uff0c\u4ee5\u53ca Razor Page \u5b9a\u4e49\u7684 Pages \u6587\u4ef6\u5939\u4ee5\u53ca wwwroot \u6587\u4ef6\uff0c\u7528\u4e8e\u76f4\u63a5\u63d0\u4f9b\u7ed9\u6d4f\u89c8\u5668\u7684\u9759\u6001\u6587\u4ef6\u3002<\/p>\n<p>Aside from these extra files, the only other difference between a Razor Pages app and a minimal API app is the Program.cs file. In section 13.1.2 you\u2019ll see that the Razor Pages app uses the same basic structure in Program.cs but adds the extra services and middleware used in a typical Razor Pages app.<\/p>\n<p>\u9664\u4e86\u8fd9\u4e9b\u989d\u5916\u7684\u6587\u4ef6\u4e4b\u5916\uff0cRazor Pages \u5e94\u7528\u548c\u6700\u5c0f API \u5e94\u7528\u4e4b\u95f4\u7684\u552f\u4e00\u5176\u4ed6\u533a\u522b\u662f Program.cs \u6587\u4ef6\u3002\u5728\u7b2c 13.1.2 \u8282\u4e2d\uff0c\u4f60\u5c06\u770b\u5230 Razor Pages \u5e94\u7528\u5728 Program.cs \u4e2d\u4f7f\u7528\u76f8\u540c\u7684\u57fa\u672c\u7ed3\u6784\uff0c\u4f46\u6dfb\u52a0\u4e86\u5178\u578b Razor Pages \u5e94\u7528\u4e2d\u4f7f\u7528\u7684\u989d\u5916\u670d\u52a1\u548c\u4e2d\u95f4\u4ef6\u3002<\/p>\n<h3>13.1.2 Adding and configuring services<\/h3>\n<h3>13.1.2 \u6dfb\u52a0\u548c\u914d\u7f6e\u670d\u52a1<\/h3>\n<p>One of the nice things about working with ASP.NET Core applications is that the setup code is quite similar even for completely different application models. No matter whether you\u2019re creating a Razor Pages application or using minimal APIs, your Program.cs contains the same six steps:<\/p>\n<p>\u4f7f\u7528 ASP.NET Core \u5e94\u7528\u7a0b\u5e8f\u7684\u4e00\u4e2a\u597d\u5904\u662f\uff0c\u5373\u4f7f\u5bf9\u4e8e\u5b8c\u5168\u4e0d\u540c\u7684\u5e94\u7528\u7a0b\u5e8f\u6a21\u578b\uff0c\u8bbe\u7f6e\u4ee3\u7801\u4e5f\u975e\u5e38\u76f8\u4f3c\u3002\u65e0\u8bba\u60a8\u662f\u521b\u5efa Razor Pages \u5e94\u7528\u7a0b\u5e8f\u8fd8\u662f\u4f7f\u7528\u6700\u5c11\u7684 API\uff0c\u60a8\u7684 Program.cs \u90fd\u5305\u542b\u76f8\u540c\u7684\u516d\u4e2a\u6b65\u9aa4\uff1a<\/p>\n<ol>\n<li>\n<p>Create a WebApplicationBuilder instance.<br \/>\n\u521b\u5efa WebApplicationBuilder \u5b9e\u4f8b\u3002<\/p>\n<\/li>\n<li>\n<p>Register the required services with the WebApplicationBuilder.<br \/>\n\u5c06\u6240\u9700\u7684\u670d\u52a1\u6ce8\u518c\u5230WebApplicationBuilder \u7684 Web \u5e94\u7528\u7a0b\u5e8f\u6784\u5efa\u5668\u3002<\/p>\n<\/li>\n<li>\n<p>Call Build on the builder instance to create a WebApplication instance.<br \/>\n\u5728\u6784\u5efa\u5668\u5b9e\u4f8b\u4e0a\u8c03\u7528 Build\uff08\uff09 \u4ee5\u521b\u5efa\u4e00\u4e2aWebApplication \u5b9e\u4f8b\u3002<\/p>\n<\/li>\n<li>\n<p>Add middleware to the WebApplication to create a pipeline.<br \/>\n\u5c06\u4e2d\u95f4\u4ef6\u6dfb\u52a0\u5230 WebApplication \u4ee5\u521b\u5efa\u7ba1\u9053\u3002<\/p>\n<\/li>\n<li>\n<p>Map the endpoints in your application.<br \/>\n\u6620\u5c04\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u7ec8\u7aef\u8282\u70b9\u3002<\/p>\n<\/li>\n<li>\n<p>Call Run() on the WebApplication to start the server and handle requests.<br \/>\n\u5728 WebApplication \u4e0a\u8c03\u7528 Run\uff08\uff09 \u4ee5\u542f\u52a8\u670d\u52a1\u5668\u5e76\u5904\u7406\u8bf7\u6c42\u3002<\/p>\n<\/li>\n<\/ol>\n<p>The following listing shows the Program.cs file for the Razor Pages app. This file uses a lot more middleware than you\u2019ve seen previously, but the overall structure should be familiar.<\/p>\n<p>\u4ee5\u4e0b\u6e05\u5355\u663e\u793a\u4e86 Razor Pages \u5e94\u7528\u7684 Program.cs \u6587\u4ef6\u3002\u6b64\u6587\u4ef6\u4f7f\u7528\u7684\u4e2d\u95f4\u4ef6\u6bd4\u60a8\u4e4b\u524d\u770b\u5230\u7684\u8981\u591a\u5f97\u591a\uff0c\u4f46\u6574\u4f53\u7ed3\u6784\u5e94\u8be5\u5f88\u719f\u6089\u3002<\/p>\n<p>Listing 13.2 The Program.cs file for a Razor Pages app<br \/>\n\u5217\u8868 13.2 Razor Pages \u5e94\u7528\u7a0b\u5e8f\u7684 Program.cs \u6587\u4ef6<\/p>\n<pre><code>WebApplicationBuilder builder = WebApplication.CreateBuilder(args);\n\nbuilder.Services.AddRazorPages();    \u2776\n\nWebApplication app = builder.Build();\n\nif (!app.Environment.IsDevelopment())   \u2777\n{   \u2777\n    app.UseExceptionHandler(&quot;\/Error&quot;);  \u2777\n    app.UseHsts()\n}   \u2777\n\napp.UseHttpsRedirection();    \u2778\napp.UseStaticFiles();    \u2778\napp.UseRouting();     \u2778\napp.UseAuthorization();    \u2778\n\napp.MapRazorPages();    \u2779\n\napp.Run();<\/code><\/pre>\n<p>\u2776 Registers the required services to use the Razor Pages feature<br \/>\n\u6ce8\u518c\u4f7f\u7528 Razor Pages \u529f\u80fd\u6240\u9700\u7684\u670d\u52a1<br \/>\n\u2777 Conditionally adds middleware depending on the runtime environment<br \/>\n\u6839\u636e\u8fd0\u884c\u65f6\u73af\u5883\u6709\u6761\u4ef6\u5730\u6dfb\u52a0\u4e2d\u95f4\u4ef6<br \/>\n\u2778 Additional middleware can be added to the middleware pipeline.<br \/>\n\u4ee5\u5c06\u5176\u4ed6\u4e2d\u95f4\u4ef6\u6dfb\u52a0\u5230\u4e2d\u95f4\u4ef6\u7ba1\u9053\u4e2d\u3002<br \/>\n\u2779 Registers each Razor Page as an endpoint in your application<br \/>\n\u5c06\u6bcf\u4e2a Razor \u9875\u9762\u6ce8\u518c\u4e3a\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u7ec8\u7ed3\u70b9<\/p>\n<p>In chapter 4 you learned about middleware and the importance of ordering when adding middleware to the pipeline. This example adds six pieces of middleware to the pipeline, two of which are added only when not running in development:<br \/>\n\u5728\u7b2c 4 \u7ae0\u4e2d\uff0c\u60a8\u4e86\u89e3\u4e86\u4e2d\u95f4\u4ef6\u4ee5\u53ca\u5c06\u4e2d\u95f4\u4ef6\u6dfb\u52a0\u5230\u7ba1\u9053\u65f6\u6392\u5e8f\u7684\u91cd\u8981\u6027\u3002\u6b64\u793a\u4f8b\u5c06 6 \u4e2a\u4e2d\u95f4\u4ef6\u6dfb\u52a0\u5230pipeline \u4e2d\uff0c\u5176\u4e2d\u4e24\u4e2a\u4ec5\u5728\u672a\u5728 development \u4e2d\u8fd0\u884c\u65f6\u6dfb\u52a0\uff1a<\/p>\n<ul>\n<li>\n<p>ExceptionHandlerMiddleware\u2014You learned about this middleware in chapters 4 and 5. This middleware catches exceptions thrown by middleware later in the pipeline and generates a friendly error page.<br \/>\nExceptionHandlerMiddleware \u2014 \u60a8\u5728\u7b2c 4 \u7ae0\u548c\u7b2c 5 \u7ae0\u4e2d\u4e86\u89e3\u4e86\u6b64\u4e2d\u95f4\u4ef6\u3002\u6b64\u4e2d\u95f4\u4ef6\u7a0d\u540e\u5728\u7ba1\u9053\u4e2d\u6355\u83b7\u4e2d\u95f4\u4ef6\u5f15\u53d1\u7684\u5f02\u5e38\uff0c\u5e76\u751f\u6210\u4e00\u4e2a\u53cb\u597d\u7684\u9519\u8bef\u9875\u9762\u3002<\/p>\n<\/li>\n<li>\n<p>HstsMiddleware\u2014This middleware sets security headers in your response, in line with industry best practices. See chapter 28 for details about it and other security-related middleware.<br \/>\nHstsMiddleware \u2014 \u6b64\u4e2d\u95f4\u4ef6\u6839\u636e\u884c\u4e1a\u6700\u4f73\u5b9e\u8df5\u5728\u54cd\u5e94\u4e2d\u8bbe\u7f6e\u5b89\u5168\u6807\u5934\u3002\u6709\u5173\u5b83\u548c\u5176\u4ed6\u4e0e\u5b89\u5168\u76f8\u5173\u7684\u4e2d\u95f4\u4ef6\u7684\u8be6\u7ec6\u4fe1\u606f\uff0c\u8bf7\u53c2\u89c1 Chapter 28\u3002<\/p>\n<\/li>\n<li>\n<p>HttpsRedirectionMiddleware\u2014This middleware ensures that your application responds only to secure (HTTPS) requests and is an industry best practice. We\u2019ll look at HTTPS in chapter 28.<br \/>\nHttpsRedirectionMiddleware \u2014 \u6b64\u4e2d\u95f4\u4ef6\u53ef\u786e\u4fdd\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u4ec5\u54cd\u5e94\u5b89\u5168 \uff08HTTPS\uff09 \u8bf7\u6c42\uff0c\u662f\u884c\u4e1a\u6700\u4f73\u5b9e\u8df5\u3002\u6211\u4eec\u5c06\u5728\u7b2c 28 \u7ae0\u4e2d\u4ecb\u7ecd HTTPS\u3002<\/p>\n<\/li>\n<li>\n<p>StaticFileMiddleware\u2014As you saw in chapter 4, this middleware serves requests for static files (such as .css and .js files) from the wwwroot folder in your app.<br \/>\nStaticFileMiddleware \u2014 \u5982\u7b2c 4 \u7ae0\u6240\u793a\uff0c\u6b64\u4e2d\u95f4\u4ef6\u4e3a\u5e94\u7528\u7a0b\u5e8f\u4e2d wwwroot \u6587\u4ef6\u5939\u4e2d\u7684\u9759\u6001\u6587\u4ef6\uff08\u5982 .css \u548c .js \u6587\u4ef6\uff09\u7684\u8bf7\u6c42\u63d0\u4f9b\u670d\u52a1\u3002<\/p>\n<\/li>\n<li>\n<p>RoutingMiddleware\u2014The routing middleware is responsible for selecting the endpoint for an incoming request. WebApplication adds it by default, but as discussed in chapter 4, adding it explicitly ensures that it runs after the StaticFileMiddleware.<br \/>\nRoutingMiddleware \u2014 \u8def\u7531\u4e2d\u95f4\u4ef6\u8d1f\u8d23\u4e3a\u4f20\u5165\u8bf7\u6c42\u9009\u62e9\u7ec8\u7aef\u8282\u70b9\u3002 WebApplication \u9ed8\u8ba4\u4f1a\u6dfb\u52a0\u5b83\uff0c\u4f46\u6b63\u5982\u7b2c 4 \u7ae0\u6240\u8ba8\u8bba\u7684\uff0c\u663e\u5f0f\u6dfb\u52a0\u5b83\u53ef\u4ee5\u786e\u4fdd\u5b83\u5728 StaticFileMiddleware \u4e4b\u540e\u8fd0\u884c\u3002<\/p>\n<\/li>\n<li>\n<p>AuthorizationMiddleware\u2014This middleware controls whether an endpoint is allowed to run based on the user making the request, but requires you also to configure authentication for your application. You\u2019ll learn more about authentication in chapter 23 and authorization in chapter 24.<br \/>\nAuthorizationMiddleware \u2014 \u6b64\u4e2d\u95f4\u4ef6\u6839\u636e\u53d1\u51fa\u8bf7\u6c42\u7684\u7528\u6237\u63a7\u5236\u662f\u5426\u5141\u8bb8\u7ec8\u7aef\u8282\u70b9\u8fd0\u884c\uff0c\u4f46\u8fd8\u8981\u6c42\u60a8\u4e3a\u5e94\u7528\u7a0b\u5e8f\u914d\u7f6e\u8eab\u4efd\u9a8c\u8bc1\u3002\u60a8\u5c06\u5728\u7b2c 23 \u7ae0\u4e2d\u4e86\u89e3\u6709\u5173\u8eab\u4efd\u9a8c\u8bc1\u7684\u66f4\u591a\u4fe1\u606f\uff0c\u5728\u7b2c 24 \u7ae0\u4e2d\u4e86\u89e3\u6709\u5173\u6388\u6743\u7684\u66f4\u591a\u4fe1\u606f\u3002<\/p>\n<\/li>\n<\/ul>\n<p>In addition to the middleware added explicitly, WebApplication automatically adds some extra middleware (as discussed in chapter 4), such as the EndpointMiddleware, which is automatically added to the end of the middleware pipeline. As with minimal APIs, the RoutingMiddleware selects which endpoint handler to execute, and the EndpointMiddleware executes the handler to generate a response.<br \/>\n\u9664\u4e86\u663e\u5f0f\u6dfb\u52a0\u7684\u4e2d\u95f4\u4ef6\u4e4b\u5916\uff0cWebApplication \u8fd8\u4f1a\u81ea\u52a8\u6dfb\u52a0\u4e00\u4e9b\u989d\u5916\u7684\u4e2d\u95f4\u4ef6\uff08\u5982\u7b2c 4 \u7ae0\u6240\u8ff0\uff09\uff0c\u4f8b\u5982 EndpointMiddleware\uff0c\u5b83\u4f1a\u81ea\u52a8\u6dfb\u52a0\u5230\u4e2d\u95f4\u4ef6\u7ba1\u9053\u7684\u672b\u5c3e\u3002\u4e0e\u6700\u5c0f API \u4e00\u6837\uff0cRoutingMiddleware \u9009\u62e9\u8981\u6267\u884c\u7684\u7aef\u70b9\u5904\u7406\u7a0b\u5e8f\uff0c\u800c EndpointMiddleware \u6267\u884c\u5904\u7406\u7a0b\u5e8f\u4ee5\u751f\u6210\u54cd\u5e94\u3002<\/p>\n<p>Together, this pair of middleware is responsible for interpreting the request to determine which Razor Page to invoke, for reading parameters from the request, and for generating the final HTML. Little configuration is required; you need only add the middleware to the pipeline and specify that you want to use Razor Page endpoints by calling MapRazorPages. For each request, the routing middleware uses the request\u2019s URL to determine which Razor Page to invoke. Then the endpoint middleware executes the Razor Page to generate the HTML response.<\/p>\n<p>\u8fd9\u5bf9\u4e2d\u95f4\u4ef6\u5171\u540c\u8d1f\u8d23\u89e3\u91ca\u8bf7\u6c42\u4ee5\u786e\u5b9a\u8981\u8c03\u7528\u7684 Razor Page\u3001\u4ece\u8bf7\u6c42\u4e2d\u8bfb\u53d6\u53c2\u6570\u4ee5\u53ca\u751f\u6210\u6700\u7ec8 HTML\u3002\u51e0\u4e4e\u4e0d\u9700\u8981\u914d\u7f6e;\u60a8\u53ea\u9700\u5c06\u4e2d\u95f4\u4ef6\u6dfb\u52a0\u5230\u7ba1\u9053\uff0c\u5e76\u901a\u8fc7\u8c03\u7528 MapRazorPages \u6307\u5b9a\u8981\u4f7f\u7528 Razor Page \u7aef\u70b9\u3002\u5bf9\u4e8e\u6bcf\u4e2a\u8bf7\u6c42\uff0c\u8def\u7531\u4e2d\u95f4\u4ef6\u4f7f\u7528\u8bf7\u6c42\u7684 URL \u6765\u786e\u5b9a\u8981\u8c03\u7528\u7684 Razor Page\u3002\u7136\u540e\uff0c\u7ec8\u7ed3\u70b9\u4e2d\u95f4\u4ef6\u6267\u884c Razor Page \u4ee5\u751f\u6210 HTML \u54cd\u5e94\u3002<\/p>\n<p>When the application is configured, it can start handling requests. But how does it handle them? In section 13.1.3 you\u2019ll get a glimpse at Razor Pages and how they generate HTML.<\/p>\n<p>\u914d\u7f6e\u5e94\u7528\u7a0b\u5e8f\u540e\uff0c\u5b83\u53ef\u4ee5\u5f00\u59cb\u5904\u7406\u8bf7\u6c42\u3002\u4f46\u662f\u5b83\u662f\u5982\u4f55\u5904\u7406\u7684\u5462\uff1f\u5728\u7b2c 13.1.3 \u8282\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3 Razor Pages \u4ee5\u53ca\u5b83\u4eec\u5982\u4f55\u751f\u6210 HTML\u3002<\/p>\n<h3>13.1.3 Generating HTML with Razor Pages<\/h3>\n<h3>13.1.3 \u4f7f\u7528 Razor Pages \u751f\u6210 HTML<\/h3>\n<p>When an ASP.NET Core application receives a request, it progresses through the middleware pipeline until a middleware component handles it. Normally, the routing middleware matches a request URL\u2019s path to a configured route, which defines which Razor Page to invoke, and the endpoint middleware invokes it.<\/p>\n<p>\u5f53 ASP.NET Core \u5e94\u7528\u7a0b\u5e8f\u6536\u5230\u8bf7\u6c42\u65f6\uff0c\u5b83\u4f1a\u5728\u4e2d\u95f4\u4ef6\u7ba1\u9053\u4e2d\u524d\u8fdb\uff0c\u76f4\u5230\u4e2d\u95f4\u4ef6\u7ec4\u4ef6\u5904\u7406\u8be5\u8bf7\u6c42\u3002\u901a\u5e38\uff0c\u8def\u7531\u4e2d\u95f4\u4ef6\u5c06\u8bf7\u6c42 URL \u7684\u8def\u5f84\u4e0e\u914d\u7f6e\u7684\u8def\u7531\u5339\u914d\uff0c\u8be5\u8def\u7531\u5b9a\u4e49\u8981\u8c03\u7528\u7684 Razor Page\uff0c\u7136\u540e\u7ec8\u7ed3\u70b9\u4e2d\u95f4\u4ef6\u8c03\u7528\u5b83\u3002<\/p>\n<p>Razor Pages are stored in .cshtml files (a portmanteau of .cs and .html) within the Pages folder of your project. In general, the routing middleware maps request URL paths to a single Razor Page by looking in the Pages folder of your project for a Razor Page with the same path. If you look back at figure 13.3, for example, you see that the Privacy page of your app corresponds to the path \/Privacy in the browser\u2019s address bar. If you look inside the Pages folder of your project, you\u2019ll find the Privacy.cshtml file, shown in the following listing.<\/p>\n<p>Razor Pages \u5b58\u50a8\u5728\u9879\u76ee\u7684 Pages \u6587\u4ef6\u5939\u4e2d\u7684 .cshtml \u6587\u4ef6\uff08.cs \u548c .xhtml \u7684\u7ec4\u5408\uff09\u4e2d\u3002\u901a\u5e38\uff0c\u8def\u7531\u4e2d\u95f4\u4ef6\u901a\u8fc7\u5728\u9879\u76ee\u7684 Pages \u6587\u4ef6\u5939\u4e2d\u67e5\u627e\u5177\u6709\u76f8\u540c\u8def\u5f84\u7684 Razor \u9875\u9762\uff0c\u5c06\u8bf7\u6c42 URL \u8def\u5f84\u6620\u5c04\u5230\u5355\u4e2a Razor \u9875\u9762\u3002\u4f8b\u5982\uff0c\u5982\u679c\u4f60\u56de\u5934\u770b\u4e00\u4e0b\u56fe 13.3\uff0c\u4f60\u4f1a\u770b\u5230\u4f60\u7684\u5e94\u7528\u7a0b\u5e8f\u7684 Privacy \u9875\u9762\u5bf9\u5e94\u4e8e\u6d4f\u89c8\u5668\u5730\u5740\u680f\u4e2d\u7684\u8def\u5f84 \/Privacy\u3002\u5982\u679c\u67e5\u770b\u9879\u76ee\u7684 Pages \u6587\u4ef6\u5939\uff0c\u60a8\u5c06\u627e\u5230 Privacy.cshtml \u6587\u4ef6\uff0c\u5982\u4ee5\u4e0b\u6e05\u5355\u6240\u793a\u3002<\/p>\n<p>Listing 13.3 The Privacy.cshtml Razor Page<br \/>\n\u5217\u8868 13.3 Privacy.cshtml Razor \u9875\u9762<\/p>\n<pre><code>@page       \u2776\n@model PrivacyModel         \u2777\n@{\n    ViewData[&quot;Title&quot;] = &quot;Privacy Policy&quot;;       \u2778\n}\n&lt;h1&gt;@ViewData[&quot;Title&quot;]&lt;\/h1&gt;     \u2779\n\n&lt;p&gt;Use this page to detail your site&#039;s privacy policy.&lt;\/p&gt;    \u277a<\/code><\/pre>\n<p>\u2776 Indicates that this is a Razor Page<br \/>\n\u8868\u793a\u8fd9\u662f\u4e00\u4e2a Razor \u9875\u9762<br \/>\n\u2777 Links the Razor Page to a specific PageModel<br \/>\n\u5c06 Razor \u9875\u9762\u94fe\u63a5\u5230\u7279\u5b9a\u7684 PageModel<br \/>\n\u2778 C# code that doesn\u2019t write to the response<br \/>\n\u4e0d\u5199\u5165\u54cd\u5e94\u7684 C# \u4ee3\u7801<br \/>\n\u2779 HTML with dynamic C# values written to the response<br \/>\n\u5c06\u52a8\u6001 C# \u503c\u5199\u5165\u54cd\u5e94\u7684 HTML<br \/>\n\u277a Standalone, static HTML<br \/>\n\u72ec\u7acb\u7684\u9759\u6001 HTML<\/p>\n<p>Razor Pages use a templating syntax called Razor that combines static HTML with dynamic C# code and HTML generation. The @page directive on the first line of the Razor Page is the most important. This directive must always be placed on the first line of the file, as it tells ASP.NET Core that the .cshtml file is a Razor Page. Without it, you won\u2019t be able to view your page correctly.<\/p>\n<p>Razor Pages \u4f7f\u7528\u4e00\u79cd\u79f0\u4e3a Razor \u7684\u6a21\u677f\u8bed\u6cd5\uff0c\u8be5\u8bed\u6cd5\u5c06\u9759\u6001 HTML \u4e0e\u52a8\u6001 C# \u4ee3\u7801\u548c HTML \u751f\u6210\u76f8\u7ed3\u5408\u3002Razor \u9875\u9762\u7b2c\u4e00\u884c\u4e0a\u7684 @page \u6307\u4ee4\u662f\u6700\u91cd\u8981\u7684\u3002\u6b64\u6307\u4ee4\u5fc5\u987b\u59cb\u7ec8\u653e\u5728\u6587\u4ef6\u7684\u7b2c\u4e00\u884c\uff0c\u56e0\u4e3a\u5b83\u4f1a\u544a\u77e5 ASP.NET Core .cshtml \u6587\u4ef6\u662f Razor \u9875\u9762\u3002\u6ca1\u6709\u5b83\uff0c\u60a8\u5c06\u65e0\u6cd5\u6b63\u786e\u67e5\u770b\u60a8\u7684\u9875\u9762\u3002<\/p>\n<p>The next line of the Razor Page defines which PageModel in your project the Razor Page is associated with:<\/p>\n<p>Razor Page \u7684\u4e0b\u4e00\u884c\u5b9a\u4e49 Razor Page \u4e0e\u9879\u76ee\u4e2d\u7684\u54ea\u4e2a PageModel \u76f8\u5173\u8054\uff1a<\/p>\n<pre><code>@model PrivacyModel<\/code><\/pre>\n<p>In this case the PageModel is called PrivacyModel, and it follows the standard convention for naming Razor Page models. You can find this class in the Privacy.cshtml.cs file in the Pages folder of your project, as shown in figure 13.5. Visual Studio nests these files underneath the Razor Page .cshtml files in Solution Explorer. We\u2019ll look at the page model in section 13.1.4.<\/p>\n<p>\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0cPageModel \u79f0\u4e3a PrivacyModel\uff0c\u5b83\u9075\u5faa\u547d\u540d Razor Page \u6a21\u578b\u7684\u6807\u51c6\u7ea6\u5b9a\u3002\u60a8\u53ef\u4ee5\u5728\u9879\u76ee\u7684 Pages \u6587\u4ef6\u5939\u4e2d\u7684 Privacy.cshtml.cs \u6587\u4ef6\u4e2d\u627e\u5230\u6b64\u7c7b\uff0c\u5982\u56fe 13.5 \u6240\u793a\u3002Visual Studio \u5c06\u8fd9\u4e9b\u6587\u4ef6\u5d4c\u5957\u5728 Razor \u9875\u9762\u4e0b.cshtml \u6587\u4ef6\u3002\u6211\u4eec\u5c06\u5728 13.1.4 \u8282\u4e2d\u67e5\u770b\u9875\u9762\u6a21\u578b\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1305.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 13.5 By convention, page models for Razor Pages are placed in a file with the same name as the Razor Page, with a .cs suffix appended. Visual Studio nests these files below the Razor Page in Solution Explorer.<br \/>\n\u56fe 13.5 \u6309\u7167\u60ef\u4f8b\uff0cRazor \u9875\u9762\u7684\u9875\u9762\u6a21\u578b\u653e\u7f6e\u5728\u4e0e Razor \u9875\u9762\u540c\u540d\u7684\u6587\u4ef6\u4e2d\uff0c\u5e76\u9644\u52a0\u4e86 .cs \u540e\u7f00\u3002Visual Studio \u5c06\u8fd9\u4e9b\u6587\u4ef6\u5d4c\u5957\u5728\u201c\u89e3\u51b3\u65b9\u6848\u8d44\u6e90\u7ba1\u7406\u5668\u201d\u4e2d\u7684 Razor \u9875\u9762\u4e0b\u65b9\u3002<\/p>\n<p>In addition to the @page and @model directives, static HTML is always valid in a Razor Page and will be rendered as is in the response:<\/p>\n<p>\u9664\u4e86 @page \u548c @model \u6307\u4ee4\u4e4b\u5916\uff0c\u9759\u6001 HTML \u5728 Razor \u9875\u9762\u4e2d\u59cb\u7ec8\u6709\u6548\uff0c\u5e76\u5c06\u6309\u539f\u6837\u5728\u54cd\u5e94\u4e2d\u5448\u73b0\uff1a<\/p>\n<pre><code>&lt;p&gt;Use this page to detail your site\u2019s privacy policy.&lt;\/p&gt;<\/code><\/pre>\n<p>You can also write ordinary C# code in Razor templates by using this construct:<br \/>\n\u60a8\u8fd8\u53ef\u4ee5\u4f7f\u7528\u4ee5\u4e0b\u6784\u9020\u5728 Razor \u6a21\u677f\u4e2d\u7f16\u5199\u666e\u901a\u7684 C# \u4ee3\u7801\uff1a<\/p>\n<pre><code>@{ \/* C# code here *\/ }<\/code><\/pre>\n<p>Any code between the curly braces will be executed but won\u2019t be written to the response. In the listing, you\u2019re setting the title of the page by writing a key to the ViewData dictionary, but you aren\u2019t writing anything to the response at this point:<\/p>\n<p>\u5927\u62ec\u53f7\u4e4b\u95f4\u7684\u4efb\u4f55\u4ee3\u7801\u90fd\u5c06\u88ab\u6267\u884c\uff0c\u4f46\u4e0d\u4f1a\u5199\u5165\u54cd\u5e94\u3002\u5728\u6e05\u5355\u4e2d\uff0c\u60a8\u901a\u8fc7\u5411 ViewData \u5b57\u5178\u5199\u5165\u4e00\u4e2a\u952e\u6765\u8bbe\u7f6e\u9875\u9762\u7684\u6807\u9898 \uff0c\u4f46\u6b64\u65f6\u60a8\u6ca1\u6709\u5411\u54cd\u5e94\u5199\u5165\u4efb\u4f55\u5185\u5bb9\uff1a<\/p>\n<pre><code>@{\n    ViewData[&quot;Title&quot;] = &quot;Privacy Policy&quot;;\n}<\/code><\/pre>\n<p>Another feature shown in this template is that you can dynamically write C# variables and expressions to the HTML stream using the @ symbol. This ability to combine dynamic and static markup is what gives Razor Pages their power. In the example, you\u2019re fetching the &quot;Title&quot; value from the ViewData dictionary and writing the values to the response inside an <code> &lt;h1&gt; <\/code> tag:<\/p>\n<p>\u6b64\u6a21\u677f\u4e2d\u663e\u793a\u7684\u53e6\u4e00\u4e2a\u529f\u80fd\u662f\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528 @ \u7b26\u53f7\u5c06 C# \u53d8\u91cf\u548c\u8868\u8fbe\u5f0f\u52a8\u6001\u5199\u5165 HTML \u6d41 \u3002\u8fd9\u79cd\u7ed3\u5408\u52a8\u6001\u548c\u9759\u6001\u6807\u8bb0\u7684\u80fd\u529b\u8d4b\u4e88\u4e86 Razor Pages \u5f3a\u5927\u7684\u529f\u80fd\u3002\u5728\u6b64\u793a\u4f8b\u4e2d\uff0c\u60a8\u5c06\u4ece ViewData \u5b57\u5178\u4e2d\u63d0\u53d6 \u201cTitle\u201d \u503c\uff0c\u5e76\u5c06\u8be5\u503c\u5199\u5165 <code>&lt;h1&gt;<\/code> \u6807\u7b7e\u5185\u7684\u54cd\u5e94\uff1a<\/p>\n<pre><code>&lt;h1&gt;@ViewData[&quot;Title&quot;]&lt;\/h1&gt;<\/code><\/pre>\n<p>At this point, you might be a little confused by the template in listing 13.3 when it\u2019s compared with the output shown in figure 13.3. The title and the static HTML content appear in both the listing and figure, but some parts of the final web page don\u2019t appear in the template. How can that be?<\/p>\n<p>\u6b64\u65f6\uff0c\u5f53\u4e0e\u56fe 13.3 \u4e2d\u6240\u793a\u7684\u8f93\u51fa\u8fdb\u884c\u6bd4\u8f83\u65f6\uff0c\u60a8\u53ef\u80fd\u4f1a\u5bf9\u6e05\u5355 13.3 \u4e2d\u7684\u6a21\u677f\u611f\u5230\u56f0\u60d1\u3002\u6807\u9898\u548c\u9759\u6001 HTML \u5185\u5bb9\u540c\u65f6\u663e\u793a\u5728\u5217\u8868\u548c\u56fe\u4e2d\uff0c\u4f46\u6700\u7ec8\u7f51\u9875\u7684\u67d0\u4e9b\u90e8\u5206\u4e0d\u4f1a\u663e\u793a\u5728\u6a21\u677f\u4e2d\u3002\u8fd9\u600e\u4e48\u53ef\u80fd\u5462\uff1f<\/p>\n<p>Razor Pages have the concept of layouts, which are base templates that define the common elements of your application, such as headers and footers. The HTML of the layout combines with the Razor Page template to produce the final HTML that\u2019s sent to the browser. Layouts prevent you from having to duplicate code for the header and footer in every page, and mean that if you need to tweak something, you\u2019ll need to do it in only one place.<\/p>\n<p>Razor Pages \u5177\u6709\u5e03\u5c40\u7684\u6982\u5ff5\uff0c\u5e03\u5c40\u662f\u5b9a\u4e49\u5e94\u7528\u7a0b\u5e8f\u7684\u5e38\u89c1\u5143\u7d20\uff08\u5982\u9875\u7709\u548c\u9875\u811a\uff09\u7684\u57fa\u672c\u6a21\u677f\u3002\u5e03\u5c40\u7684 HTML \u4e0e Razor Page \u6a21\u677f\u76f8\u7ed3\u5408\uff0c\u4ee5\u751f\u6210\u53d1\u9001\u5230\u6d4f\u89c8\u5668\u7684\u6700\u7ec8 HTML\u3002\u5e03\u5c40\u53ef\u4ee5\u9632\u6b62\u4f60\u4e3a\u6bcf\u4e2a\u9875\u9762\u7684\u9875\u7709\u548c\u9875\u811a\u91cd\u590d\u4ee3\u7801\uff0c\u8fd9\u610f\u5473\u7740\u5982\u679c\u4f60\u9700\u8981\u8c03\u6574\u67d0\u4e9b\u5185\u5bb9\uff0c\u53ea\u9700\u5728\u4e00\u4e2a\u5730\u65b9\u8fdb\u884c\u3002<\/p>\n<p><strong>Note<\/strong> I cover Razor templates, including layouts, in detail in chapter 17. You can find layouts in the Pages\/Shared folder of your project.<br \/>\n<strong>\u6ce8\u610f<\/strong> \u6211\u5728\u7b2c 17 \u7ae0\u4e2d\u8be6\u7ec6\u4ecb\u7ecd\u4e86 Razor \u6a21\u677f\uff0c\u5305\u62ec\u5e03\u5c40\u3002\u60a8\u53ef\u4ee5\u5728\u9879\u76ee\u7684 Pages\/Shared \u6587\u4ef6\u5939\u4e2d\u627e\u5230\u5e03\u5c40\u3002<\/p>\n<p>As you\u2019ve already seen, you can include C# code in your Razor Pages by using curly braces @{ }, but generally speaking, you\u2019ll want to limit the code in your .cshtml file to presentational concerns only. Complex logic, code to access services such as a database, and data manipulation should be handled in the PageModel instead.<\/p>\n<p>\u5982\u4f60\u6240\u89c1\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528\u5927\u62ec\u53f7 @{ } \u5728 Razor Pages \u4e2d\u5305\u542b C# \u4ee3\u7801\uff0c\u4f46\u4e00\u822c\u6765\u8bf4\uff0c\u4f60\u9700\u8981\u5c06 .cshtml \u6587\u4ef6\u4e2d\u7684\u4ee3\u7801\u9650\u5236\u4e3a\u4ec5\u8868\u793a\u6027\u95ee\u9898\u3002\u590d\u6742\u7684\u903b\u8f91\u3001\u8bbf\u95ee\u670d\u52a1\uff08\u5982\u6570\u636e\u5e93\uff09\u7684\u4ee3\u7801\u4ee5\u53ca\u6570\u636e\u4f5c\u5e94\u8be5\u5728 PageModel \u4e2d\u5904\u7406\u3002<\/p>\n<h3>13.1.4 Handling request logic with page models and handlers<\/h3>\n<h3>13.1.4 \u4f7f\u7528\u9875\u9762\u6a21\u578b\u548c\u5904\u7406\u7a0b\u5e8f\u5904\u7406\u8bf7\u6c42\u903b\u8f91<\/h3>\n<p>As you\u2019ve already seen, the @page directive in a .cshtml file marks the page as a Razor Page, but most Razor Pages also have an associated page model. By convention, this page model is placed in a file commonly known as a code-behind file that has a .cs extension, as you saw in figure 13.5. Page models should derive from the PageModel base class, and they typically contain one or more methods called page handlers that define how to handle requests to the Razor Page.<\/p>\n<p>\u5982\u4f60\u6240\u89c1\uff0c.cshtml \u6587\u4ef6\u4e2d\u7684 @page \u6307\u4ee4\u5c06\u9875\u9762\u6807\u8bb0\u4e3a Razor \u9875\u9762\uff0c\u4f46\u5927\u591a\u6570 Razor \u9875\u9762\u4e5f\u6709\u5173\u8054\u7684\u9875\u9762\u6a21\u578b\u3002\u6309\u7167\u60ef\u4f8b\uff0c\u6b64\u9875\u9762\u6a21\u578b\u88ab\u653e\u7f6e\u5728\u4e00\u4e2a\u901a\u5e38\u79f0\u4e3a\u4ee3\u7801\u9690\u85cf\u6587\u4ef6\u7684\u6587\u4ef6\u4e2d\uff0c\u8be5\u6587\u4ef6\u5177\u6709 .cs \u6269\u5c55\u540d\uff0c\u5982\u56fe 13.5 \u6240\u793a\u3002\u9875\u9762\u6a21\u578b\u5e94\u6d3e\u751f\u81ea PageModel \u57fa\u7c7b\uff0c\u5e76\u4e14\u5b83\u4eec\u901a\u5e38\u5305\u542b\u4e00\u4e2a\u6216\u591a\u4e2a\u79f0\u4e3a page \u7684\u65b9\u6cd5\u5b9a\u4e49\u5982\u4f55\u5904\u7406\u5bf9 Razor Page \u7684\u8bf7\u6c42\u7684\u5904\u7406\u7a0b\u5e8f\u3002<\/p>\n<p><strong>Definition<\/strong> A page handler is the Razor Pages equivalent of a minimal API endpoint handler; it\u2019s a method that runs in response to a request. Razor Page models must be derived from the PageModel class. They can contain multiple page handlers, though typically they contain only one or two.<br \/>\n<strong>\u5b9a\u4e49<\/strong> \u9875\u9762\u5904\u7406\u7a0b\u5e8f\u76f8\u5f53\u4e8e\u6700\u5c0f API \u7aef\u70b9\u5904\u7406\u7a0b\u5e8f\u7684 Razor Pages;\u5b83\u662f\u4e3a\u54cd\u5e94\u8bf7\u6c42\u800c\u8fd0\u884c\u7684\u65b9\u6cd5\u3002Razor Page \u6a21\u578b\u5fc5\u987b\u6d3e\u751f\u81ea PageModel \u7c7b\u3002\u5b83\u4eec\u53ef\u4ee5\u5305\u542b\u591a\u4e2a\u9875\u9762\u5904\u7406\u7a0b\u5e8f\uff0c\u4f46\u901a\u5e38\u53ea\u5305\u542b\u4e00\u4e2a\u6216\u4e24\u4e2a\u3002<\/p>\n<p>The following listing shows the page model for the Privacy.cshtml Razor Page, located in the file Privacy.cshtml.cs.<\/p>\n<p>\u4ee5\u4e0b\u5217\u8868\u663e\u793a\u4e86\u4f4d\u4e8e\u6587\u4ef6 Privacy.cshtml.cs \u4e2d\u7684 Privacy.cshtml Razor \u9875\u9762\u7684\u9875\u9762\u6a21\u578b\u3002<\/p>\n<p>Listing 13.4 The PrivacyModel in Privacy.cshtml.cs: A Razor Page page model<br \/>\n\u6e05\u5355 13.4 Privacy.cshtml.cs\u4e2d\u7684 PrivacyModel\uff1a\u4e00\u4e2aRazor \u9875\u9762\u6a21\u578b<\/p>\n<pre><code>public class PrivacyModel: PageModel        \u2776\n{\n    private readonly ILogger&lt;PrivacyModel&gt; _logger;      \u2777 \n    public PrivacyModel(ILogger&lt;PrivacyModel&gt; logger)    \u2777 \n    {                                                    \u2777 \n        _logger = logger;                                \u2777 \n    }                                                    \u2777 \n\n  public void OnGet()      \u2778 \n    {\n    }\n}<\/code><\/pre>\n<p>\u2776 Razor Pages must inherit from PageModel.<br \/>\nRazor Pages \u5fc5\u987b\u7ee7\u627f\u81ea PageModel\u3002<br \/>\n\u2777 You can use dependency injection to provide services in the constructor.<br \/>\n\u60a8\u53ef\u4ee5\u4f7f\u7528\u4f9d\u8d56\u6ce8\u5165\u5728\u6784\u9020\u51fd\u6570\u4e2d\u63d0\u4f9b\u670d\u52a1\u3002<br \/>\n\u2778 The default page handler is OnGet. Returning void indicates HTML should be generated.<br \/>\n\u9ed8\u8ba4\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u4e3a OnGet\u3002\u8fd4\u56de void \u8868\u793a\u5e94\u751f\u6210 HTML\u3002<\/p>\n<p>This page model is extremely simple, but it demonstrates a couple of important points:<br \/>\n\u6b64\u9875\u9762\u6a21\u578b\u975e\u5e38\u7b80\u5355\uff0c\u4f46\u5b83\u6f14\u793a\u4e86\u51e0\u4e2a\u8981\u70b9\uff1a<\/p>\n<ul>\n<li>\n<p>Page handlers are driven by convention.<br \/>\n\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u7531\u7ea6\u5b9a\u9a71\u52a8\u3002<\/p>\n<\/li>\n<li>\n<p>Page models can use dependency injection (DI) to interact with other services.<br \/>\n\u9875\u9762\u6a21\u578b\u53ef\u4ee5\u4f7f\u7528\u4f9d\u8d56\u5173\u7cfb\u6ce8\u5165 \uff08DI\uff09 \u4e0e\u5176\u4ed6\u670d\u52a1\u8fdb\u884c\u4ea4\u4e92\u3002<\/p>\n<\/li>\n<\/ul>\n<p>Page handlers are typically named by convention, based on the HTTP verb they respond to. They return either void, indicating that the Razor<br \/>\nPage\u2019s template should be rendered, or an IActionResult that contains other instructions for generating the response, such as redirecting the user to a different page.<\/p>\n<p>\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u901a\u5e38\u6839\u636e\u5b83\u4eec\u54cd\u5e94\u7684 HTTP \u52a8\u8bcd\u6309\u7ea6\u5b9a\u547d\u540d\u3002\u5b83\u4eec\u8fd4\u56de void\uff08\u6307\u793a\u5e94\u5448\u73b0 Razor \u9875\u9762\u7684\u6a21\u677f\uff09\u6216 IActionResult\uff08\u5305\u542b\u7528\u4e8e\u751f\u6210\u54cd\u5e94\u7684\u5176\u4ed6\u8bf4\u660e\uff0c\u4f8b\u5982\u5c06\u7528\u6237\u91cd\u5b9a\u5411\u5230\u5176\u4ed6\u9875\u9762\uff09\u3002<\/p>\n<p>The PrivacyModel contains a single handler, OnGet, which indicates that it should run in response to GET requests for the page. As the method returns void, executing the handler executes the associated Razor template for the page to generate the HTML.<\/p>\n<p>PrivacyModel \u5305\u542b\u4e00\u4e2a\u5904\u7406\u7a0b\u5e8f OnGet\uff0c\u5b83\u6307\u793a\u5b83\u5e94\u8be5\u8fd0\u884c\u4ee5\u54cd\u5e94\u9875\u9762\u7684 GET \u8bf7\u6c42\u3002\u5f53\u8be5\u65b9\u6cd5\u8fd4\u56de void \u65f6\uff0c\u6267\u884c\u5904\u7406\u7a0b\u5e8f\u5c06\u6267\u884c\u9875\u9762\u7684\u5173\u8054 Razor \u6a21\u677f\u4ee5\u751f\u6210 HTML\u3002<\/p>\n<p><strong>Note<\/strong> Razor Pages are focused on building page-based apps, so you typically want to return HTML rather than JSON or XML. You can also use an IActionResult to return any sort of data, to redirect users to a new page, or to send an error. You\u2019ll learn more about IActionResults in chapter 15.<br \/>\n<strong>\u6ce8\u610f<\/strong> Razor Pages \u4e13\u6ce8\u4e8e\u6784\u5efa\u57fa\u4e8e\u9875\u9762\u7684\u5e94\u7528\uff0c\u56e0\u6b64\u4f60\u901a\u5e38\u9700\u8981\u8fd4\u56de HTML\uff0c\u800c\u4e0d\u662f JSON \u6216 XML\u3002\u60a8\u8fd8\u53ef\u4ee5\u4f7f\u7528 IActionResult \u8fd4\u56de\u4efb\u4f55\u7c7b\u578b\u7684\u6570\u636e\u3001\u5c06\u7528\u6237\u91cd\u5b9a\u5411\u5230\u65b0\u9875\u9762\u6216\u53d1\u9001\u9519\u8bef\u3002\u60a8\u5c06\u5728\u7b2c 15 \u7ae0\u4e2d\u4e86\u89e3\u6709\u5173 IActionResult\u7684\u66f4\u591a\u4fe1\u606f\u3002<\/p>\n<p>DI is used to inject an <code>ILogger&lt;PrivacyModel&gt;<\/code> instance into the constructor of the page model the same way you would inject a service into a minimal API endpoint handler. The service is unused in this example, but you\u2019ll learn all about ILogger in chapter 26.<\/p>\n<p>DI \u7528\u4e8e\u5c06 <code>ILogger&lt;PrivacyModel&gt;<\/code> \u5b9e\u4f8b\u6ce8\u5165\u9875\u9762\u6a21\u578b\u7684\u6784\u9020\u51fd\u6570\u4e2d\uff0c\u5c31\u50cf\u5c06\u670d\u52a1\u6ce8\u5165\u6700\u5c0f API \u7ec8\u7aef\u8282\u70b9\u5904\u7406\u7a0b\u5e8f\u4e2d\u4e00\u6837\u3002\u5728\u6b64\u793a\u4f8b\u4e2d\uff0c\u8be5\u670d\u52a1\u672a\u4f7f\u7528\uff0c\u4f46\u60a8\u5c06\u5728\u7b2c 26 \u7ae0\u4e2d\u4e86\u89e3\u6709\u5173 ILogger \u7684\u6240\u6709\u4fe1\u606f\u3002<\/p>\n<p>Clearly, the PrivacyModel page model doesn\u2019t do much in this case, and you may be wondering why it\u2019s worth having. If all page models do is tell the Razor Page to generate HTML, why do we need them at all?<\/p>\n<p>\u663e\u7136\uff0c\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0cPrivacyModel \u9875\u9762\u6a21\u578b\u7684\u4f5c\u7528\u4e0d\u5927\uff0c\u60a8\u53ef\u80fd\u60f3\u77e5\u9053\u4e3a\u4ec0\u4e48\u503c\u5f97\u62e5\u6709\u5b83\u3002\u5982\u679c\u6240\u6709\u9875\u9762\u6a21\u578b\u90fd\u53ea\u662f\u544a\u8bc9 Razor \u9875\u9762\u751f\u6210 HTML\uff0c\u90a3\u4e48\u6211\u4eec\u4e3a\u4ec0\u4e48\u8fd8\u9700\u8981\u5b83\u4eec\u5462\uff1f<\/p>\n<p>The key thing to remember here is that now you have a framework for performing arbitrarily complex functions in response to a request. You could easily update the handler method to load data from the database, send an email, add a product to a basket, or create an invoice\u2014all in response to a simple HTTP request. This extensibility is where a lot of the power in Razor Pages (and the MVC pattern in general) lies.<\/p>\n<p>\u8fd9\u91cc\u8981\u8bb0\u4f4f\u7684\u5173\u952e\u662f\uff0c\u73b0\u5728\u4f60\u6709\u4e00\u4e2a\u6846\u67b6\u6765\u6267\u884c\u4efb\u610f\u590d\u6742\u7684\u529f\u80fd\u4ee5\u54cd\u5e94\u8bf7\u6c42\u3002\u60a8\u53ef\u4ee5\u8f7b\u677e\u66f4\u65b0\u5904\u7406\u7a0b\u5e8f\u65b9\u6cd5\uff0c\u4ee5\u4ece\u6570\u636e\u5e93\u52a0\u8f7d\u6570\u636e\u3001\u53d1\u9001\u7535\u5b50\u90ae\u4ef6\u3001\u5c06\u4ea7\u54c1\u6dfb\u52a0\u5230\u8d2d\u7269\u7bee\u6216\u521b\u5efa\u53d1\u7968 - \u6240\u6709\u8fd9\u4e9b\u90fd\u662f\u4e3a\u4e86\u54cd\u5e94\u7b80\u5355\u7684 HTTP \u8bf7\u6c42\u3002\u8fd9\u79cd\u53ef\u6269\u5c55\u6027\u662f Razor Pages\uff08\u4ee5\u53ca\u4e00\u822c\u7684 MVC \u6a21\u5f0f\uff09\u4e2d\u8bb8\u591a\u529f\u80fd\u6240\u5728\u3002<\/p>\n<p>The other important point is that you\u2019ve separated the execution of these methods from the generation of the HTML. If the logic changes, and you need to add behavior to a page handler, you don\u2019t need to touch the HTML generation code, so you\u2019re less likely to introduce bugs. Conversely, if you need to change the UI slightly (change the color of the title, for example), your handler method logic is safe.<\/p>\n<p>\u53e6\u4e00\u4e2a\u91cd\u8981\u7684\u4e00\u70b9\u662f\uff0c\u60a8\u5df2\u7ecf\u5c06\u8fd9\u4e9b\u65b9\u6cd5\u7684\u6267\u884c\u4e0e HTML \u7684\u751f\u6210\u5206\u5f00\u3002\u5982\u679c\u903b\u8f91\u53d1\u751f\u53d8\u5316\uff0c\u5e76\u4e14\u60a8\u9700\u8981\u5411\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u6dfb\u52a0\u884c\u4e3a\uff0c\u5219\u65e0\u9700\u63a5\u89e6 HTML \u751f\u6210\u4ee3\u7801\uff0c\u56e0\u6b64\u4e0d\u592a\u53ef\u80fd\u5f15\u5165\u9519\u8bef\u3002\u76f8\u53cd\uff0c\u5982\u679c\u60a8\u9700\u8981\u7a0d\u5fae\u66f4\u6539 UI\uff08\u4f8b\u5982\uff0c\u66f4\u6539\u6807\u9898\u7684\u989c\u8272\uff09\uff0c\u5219\u5904\u7406\u7a0b\u5e8f\u65b9\u6cd5\u903b\u8f91\u662f\u5b89\u5168\u7684\u3002<\/p>\n<p>And there you have it\u2014a complete ASP.NET Core Razor Pages application! Before we move on, let\u2019s take one last look at how your application handles a request. Figure 13.6 shows a request to the \/Privacy path being handled by the sample application. You\u2019ve seen everything here already, so the process of handling a request should be familiar. The figure shows how the request passes through the middleware pipeline before being handled by the endpoint middleware. The Privacy.cshtml Razor Page executes the OnGet handler and generates the HTML response, which passes back through the middleware to the ASP.NET Core web server before being sent to the user\u2019s browser.<\/p>\n<p>\u8fd9\u5c31\u662f\u4e00\u4e2a\u5b8c\u6574\u7684 ASP.NET Core Razor Pages \u5e94\u7528\u7a0b\u5e8f\uff01\u5728\u7ee7\u7eed\u4e4b\u524d\uff0c\u8ba9\u6211\u4eec\u6700\u540e\u770b\u770b\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u5982\u4f55\u5904\u7406\u8bf7\u6c42\u3002\u56fe 13.6 \u663e\u793a\u4e86\u5bf9\u793a\u4f8b\u5e94\u7528\u7a0b\u5e8f\u6b63\u5728\u5904\u7406\u7684 \/Privacy \u8def\u5f84\u7684\u8bf7\u6c42\u3002\u60a8\u5df2\u7ecf\u5728\u8fd9\u91cc\u770b\u5230\u4e86\u6240\u6709\u5185\u5bb9\uff0c\u56e0\u6b64\u5904\u7406\u8bf7\u6c42\u7684\u8fc7\u7a0b\u5e94\u8be5\u5f88\u719f\u6089\u3002\u8be5\u56fe\u663e\u793a\u4e86\u8bf7\u6c42\u5728\u7531\u7ec8\u7aef\u8282\u70b9\u4e2d\u95f4\u4ef6\u5904\u7406\u4e4b\u524d\u5982\u4f55\u901a\u8fc7\u4e2d\u95f4\u4ef6\u7ba1\u9053\u3002Privacy.cshtml Razor \u9875\u9762\u6267\u884c OnGet \u5904\u7406\u7a0b\u5e8f\u5e76\u751f\u6210 HTML \u54cd\u5e94\uff0c\u8be5\u54cd\u5e94\u4f20\u56de\u901a\u8fc7\u4e2d\u95f4\u4ef6\u53d1\u9001\u5230 ASP.NET Core Web \u670d\u52a1\u5668\uff0c\u7136\u540e\u518d\u53d1\u9001\u5230\u7528\u6237\u7684\u6d4f\u89c8\u5668\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1306.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 13.6 An overview of a request to the \/Privacy URL for the sample ASP.NET Razor Pages application. The routing middleware routes the request to the OnGet handler of the Privacy.cshtml.cs Razor Page. The Razor Page generates an HTML response by executing the Razor template in Privacy.cshtml and passes the response back through the middleware pipeline to the browser.<br \/>\n\u56fe 13.6 \u5bf9\u793a\u4f8b ASP.NET Razor Pages \u5e94\u7528\u7a0b\u5e8f\u7684 \/Privacy URL \u7684\u8bf7\u6c42\u6982\u8ff0\u3002\u8def\u7531\u4e2d\u95f4\u4ef6\u5c06\u8bf7\u6c42\u8def\u7531\u5230 Privacy.cshtml.cs Razor Page \u7684 OnGet \u5904\u7406\u7a0b\u5e8f\u3002Razor \u9875\u9762\u901a\u8fc7\u5728 Privacy.cshtml \u4e2d\u6267\u884c Razor \u6a21\u677f\u6765\u751f\u6210 HTML \u54cd\u5e94\uff0c\u5e76\u901a\u8fc7\u4e2d\u95f4\u4ef6\u7ba1\u9053\u5c06\u54cd\u5e94\u4f20\u56de\u6d4f\u89c8\u5668\u3002<\/p>\n<p>We\u2019ve reached the end of this section working through the template, so you have a good overview of how an entire Razor Pages application is configured and how it handles a request using Razor Pages. In section 13.2 we take the basic Razor Pages in the default template a bit further, looking at a more complex example.<\/p>\n<p>\u6211\u4eec\u5df2\u5b8c\u6210\u672c\u90e8\u5206\u7684\u672b\u5c3e\uff0c\u9010\u6b65\u4e86\u89e3\u4e86\u6a21\u677f\u7684\u914d\u7f6e\u65b9\u5f0f\uff0c\u4ee5\u53ca\u5b83\u5982\u4f55\u4f7f\u7528 Razor Pages \u5904\u7406\u8bf7\u6c42\u3002\u5728\u7b2c 13.2 \u8282\u4e2d\uff0c\u6211\u4eec\u5c06\u9ed8\u8ba4\u6a21\u677f\u4e2d\u7684\u57fa\u672c Razor Pages \u8fdb\u4e00\u6b65\u4ecb\u7ecd\uff0c\u5e76\u67e5\u770b\u66f4\u590d\u6742\u7684\u793a\u4f8b\u3002<\/p>\n<h2>13.2 Exploring a typical Razor Page<\/h2>\n<h2>13.2 \u63a2\u7d22\u5178\u578b\u7684 Razor \u9875\u9762<\/h2>\n<p>The Razor Pages programming model was introduced in ASP.NET Core 2.0 as a way to build server-side rendered page-based websites. It builds on top of the ASP.NET Core infrastructure to provide a streamlined experience, using conventions where possible to reduce the amount of boilerplate code and configuration required. In this section we\u2019ll look at a more complex page model to better understand the overall design of Razor Pages.<\/p>\n<p>Razor Pages \u7f16\u7a0b\u6a21\u578b\u662f\u5728 ASP.NET Core 2.0 \u4e2d\u5f15\u5165\u7684\uff0c\u4f5c\u4e3a\u6784\u5efa\u670d\u52a1\u5668\u7aef\u5448\u73b0\u7684\u57fa\u4e8e\u9875\u9762\u7684\u7f51\u7ad9\u7684\u4e00\u79cd\u65b9\u5f0f\u3002\u5b83\u5efa\u7acb\u5728 ASP.NET Core \u57fa\u7840\u8bbe\u65bd\u4e4b\u4e0a\uff0c\u4ee5\u63d0\u4f9b\u7b80\u5316\u7684\u4f53\u9a8c\uff0c\u5e76\u5c3d\u53ef\u80fd\u4f7f\u7528\u7ea6\u5b9a\u6765\u51cf\u5c11\u6240\u9700\u7684\u6837\u677f\u4ee3\u7801\u548c\u914d\u7f6e\u7684\u6570\u91cf\u3002\u672c\u8282\u5185\u5bb9\u6211\u4eec\u5c06\u67e5\u770b\u66f4\u590d\u6742\u7684\u9875\u9762\u6a21\u578b\uff0c\u4ee5\u66f4\u597d\u5730\u4e86\u89e3 Razor Pages \u7684\u6574\u4f53\u8bbe\u8ba1\u3002<\/p>\n<p>In listing 13.4 you saw a simple Razor Page that didn\u2019t contain any logic; instead, it only rendered the associated Razor view. This pattern may be common if you\u2019re building a content-heavy marketing website, for example, but more commonly your Razor Pages will contain some logic, load data from a database, or use forms to allow users to submit information.<\/p>\n<p>\u5728\u6e05\u5355 13.4 \u4e2d\uff0c\u4f60\u770b\u5230\u4e86\u4e00\u4e2a\u7b80\u5355\u7684 Razor \u9875\u9762\uff0c\u5b83\u4e0d\u5305\u542b\u4efb\u4f55\u903b\u8f91;\u76f8\u53cd\uff0c\u5b83\u53ea\u5448\u73b0\u5173\u8054\u7684 Razor \u89c6\u56fe\u3002\u4f8b\u5982\uff0c\u5982\u679c\u60a8\u6b63\u5728\u6784\u5efa\u5185\u5bb9\u7e41\u91cd\u7684\u8425\u9500\u7f51\u7ad9\uff0c\u5219\u6b64\u6a21\u5f0f\u53ef\u80fd\u5f88\u5e38\u89c1\uff0c\u4f46\u66f4\u5e38\u89c1\u7684\u662f\uff0c\u60a8\u7684 Razor \u9875\u9762\u5c06\u5305\u542b\u4e00\u4e9b\u903b\u8f91\u3001\u4ece\u6570\u636e\u5e93\u52a0\u8f7d\u6570\u636e\u6216\u4f7f\u7528\u8868\u5355\u6765\u5141\u8bb8\u7528\u6237\u63d0\u4ea4\u4fe1\u606f\u3002<\/p>\n<p>To give you more of a flavor of how typical Razor Pages work, in this section we look briefly at a slightly more complex Razor Page. This page is taken from a to-do list application and is used to display all the to-do items for a given category. We\u2019re not focusing on the HTML generation at this point, so the following listing shows only the PageModel code-behind file for the Razor Page.<\/p>\n<p>\u4e3a\u4e86\u8ba9\u60a8\u66f4\u6df1\u5165\u5730\u4e86\u89e3\u5178\u578b\u7684 Razor \u9875\u9762\u7684\u5de5\u4f5c\u539f\u7406\uff0c\u5728\u672c\u8282\u4e2d\uff0c\u6211\u4eec\u5c06\u7b80\u8981\u4ecb\u7ecd\u4e00\u4e2a\u7a0d\u5fae\u590d\u6742\u4e00\u4e9b\u7684 Razor \u9875\u9762\u3002\u6b64\u9875\u9762\u53d6\u81ea\u5f85\u529e\u4e8b\u9879\u5217\u8868\u5e94\u7528\u7a0b\u5e8f\uff0c\u7528\u4e8e\u663e\u793a\u7ed9\u5b9a\u7c7b\u522b\u7684\u6240\u6709\u5f85\u529e\u4e8b\u9879\u3002\u76ee\u524d\uff0c\u6211\u4eec\u4e0d\u5173\u6ce8 HTML \u751f\u6210\uff0c\u56e0\u6b64\u4e0b\u9762\u7684\u6e05\u5355\u4ec5\u663e\u793a Razor Page \u7684 PageModel \u4ee3\u7801\u9690\u85cf\u6587\u4ef6\u3002<\/p>\n<p>Listing 13.5 A Razor Page for viewing all to-do items in a given category<br \/>\n\u6e05\u5355 13.5 \u7528\u4e8e\u67e5\u770b\u6240\u6709\u5f85\u529e\u4e8b\u9879\u7684 Razor \u9875\u9762\u5728\u7ed9\u5b9a\u7c7b\u522b\u4e2d<\/p>\n<pre><code>public class CategoryModel : PageModel\n{\n    private readonly ToDoService _service;       \u2776\n    public CategoryModel(ToDoService service)    \u2776\n    {\n        _service = service;\n    }\n\n    public ActionResult OnGet(string category)    \u2777\n    {\n        Items = _service.GetItemsForCategory(category);     \u2778\n        return Page();     \u2779\n    }\n\n    public List&lt;ToDoListModel&gt; Items { get; set; }    \u277a\n}<\/code><\/pre>\n<p>\u2776 The ToDoService is provided in the model constructor using DI.<br \/>\nToDoService \u662f\u4f7f\u7528 DI \u5728\u6a21\u578b\u6784\u9020\u51fd\u6570\u4e2d\u63d0\u4f9b\u7684\u3002<br \/>\n\u2777 The OnGet handler takes a parameter, category.<br \/>\nOnGet \u5904\u7406\u7a0b\u5e8f\u91c7\u7528\u53c2\u6570 category\u3002<br \/>\n\u2778 The handler calls out to the ToDoService to retrieve data and sets the Items property.<br \/>\n\u5904\u7406\u7a0b\u5e8f\u8c03\u7528 ToDoService \u4ee5\u68c0\u7d22\u6570\u636e\u5e76\u8bbe\u7f6e Items \u5c5e\u6027\u3002<br \/>\n\u2779 Returns a PageResult indicating the Razor view should be rendered<br \/>\n\u8fd4\u56de\u4e00\u4e2a PageResult\uff0c\u6307\u793a\u5e94\u5448\u73b0 Razor \u89c6\u56fe<br \/>\n\u277a The Razor View can access the Items property when it\u2019s rendered.<br \/>\nRazor \u89c6\u56fe\u5728\u5448\u73b0\u65f6\u53ef\u4ee5\u8bbf\u95ee Items \u5c5e\u6027\u3002<\/p>\n<p>This example is still relatively simple, but it demonstrates a variety of features compared with the basic example from listing 13.4:<br \/>\n\u8fd9\u4e2a\u4f8b\u5b50\u4ecd\u7136\u76f8\u5bf9\u7b80\u5355\uff0c\u4f46\u4e0e \u6e05\u5355 13.4 \u4e2d\u7684\u57fa\u672c\u4f8b\u5b50\u76f8\u6bd4\uff0c\u5b83\u6f14\u793a\u4e86\u5404\u79cd\u7279\u6027\uff1a<\/p>\n<ul>\n<li>\n<p>The page handler, OnGet, accepts a method parameter, category. This parameter is automatically populated using values from the incoming request via model binding, similar to the way binding works with minimal APIs. I discuss Razor Pages model binding in detail in chapter 16.<br \/>\n\u9875\u9762\u5904\u7406\u7a0b\u5e8f OnGet \u63a5\u53d7\u65b9\u6cd5\u53c2\u6570 category\u3002\u6b64\u53c2\u6570\u901a\u8fc7\u6a21\u578b\u7ed1\u5b9a\u4f7f\u7528\u4f20\u5165\u8bf7\u6c42\u4e2d\u7684\u503c\u81ea\u52a8\u586b\u5145\uff0c\u7c7b\u4f3c\u4e8e\u7ed1\u5b9a\u4f7f\u7528\u6700\u5c0f API \u7684\u65b9\u5f0f\u3002\u6211\u5728\u7b2c 16 \u7ae0\u4e2d\u8be6\u7ec6\u8ba8\u8bba\u4e86 Razor Pages \u6a21\u578b\u7ed1\u5b9a\u3002<\/p>\n<\/li>\n<li>\n<p>The handler doesn\u2019t interact with the database directly. Instead, it uses the category value provided to interact with the ToDoService, which is injected as a constructor argument using DI.<br \/>\n\u5904\u7406\u7a0b\u5e8f\u4e0d\u76f4\u63a5\u4e0e\u6570\u636e\u5e93\u4ea4\u4e92\u3002\u76f8\u53cd\uff0c\u5b83\u4f7f\u7528\u63d0\u4f9b\u7684 category \u503c\u4e0e ToDoService \u4ea4\u4e92\uff0c\u540e\u8005\u4f7f\u7528 DI \u4f5c\u4e3a\u6784\u9020\u51fd\u6570\u53c2\u6570\u6ce8\u5165\u3002<\/p>\n<\/li>\n<li>\n<p>The handler returns Page() at the end of the method to indicate that the associated Razor view should be rendered. The return statement is optional in this case; by convention, if the page handler is a void method, the Razor view will still be rendered, behaving as though you called return Page() at the end of the method.<br \/>\n\u5904\u7406\u7a0b\u5e8f\u5728\u65b9\u6cd5\u672b\u5c3e\u8fd4\u56de Page\uff08\uff09\uff0c\u4ee5\u6307\u793a\u5e94\u5448\u73b0\u5173\u8054\u7684 Razor \u89c6\u56fe\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0creturn \u8bed\u53e5\u662f\u53ef\u9009\u7684;\u6309\u7167\u7ea6\u5b9a\uff0c\u5982\u679c\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u662f void \u65b9\u6cd5\uff0c\u5219\u4ecd\u5c06\u5448\u73b0 Razor \u89c6\u56fe\uff0c\u5176\u884c\u4e3a\u5c31\u50cf\u5728\u65b9\u6cd5\u672b\u5c3e\u8c03\u7528 return Page\uff08\uff09 \u4e00\u6837\u3002<\/p>\n<\/li>\n<li>\n<p>The Razor View has access to the CategoryModel instance, so it can access the Items property that\u2019s set by the handler. It uses these items to build the HTML that is ultimately sent to the user.<br \/>\nRazor \u89c6\u56fe\u6709\u6743\u8bbf\u95ee CategoryModel \u5b9e\u4f8b\uff0c\u56e0\u6b64\u5b83\u53ef\u4ee5\u8bbf\u95ee\u5904\u7406\u7a0b\u5e8f\u8bbe\u7f6e\u7684 Items \u5c5e\u6027\u3002\u5b83\u4f7f\u7528\u8fd9\u4e9b\u9879\u6765\u6784\u5efa\u6700\u7ec8\u53d1\u9001\u7ed9\u7528\u6237\u7684 HTML\u3002\u200c<\/p>\n<\/li>\n<\/ul>\n<p>The pattern of interactions in the Razor Page of listing 13.5 shows a common pattern. The page handler is the central controller for the Razor Page. It receives an input from the user (the category method parameter); calls out to the \u201cbrains\u201d of the application (the ToDoService); and passes data (by exposing the Items property) to the Razor view, which generates the HTML response. If you squint, this pattern looks like the MVC design pattern.<\/p>\n<p>\u6e05\u5355 13.5 \u7684 Razor Page \u4e2d\u7684\u4ea4\u4e92\u6a21\u5f0f\u663e\u793a\u4e86\u4e00\u79cd\u5e38\u89c1\u6a21\u5f0f\u3002\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u662f Razor Page \u7684\u4e2d\u592e\u63a7\u5236\u5668\u3002\u5b83\u63a5\u6536\u6765\u81ea\u7528\u6237\u7684\u8f93\u5165\uff08category \u65b9\u6cd5\u53c2\u6570\uff09;\u8c03\u7528\u5e94\u7528\u7a0b\u5e8f\u7684\u201c\u5927\u8111\u201d\uff08ToDoService\uff09;\u5e76\u5c06\u6570\u636e\uff08\u901a\u8fc7\u516c\u5f00 Items \u5c5e\u6027\uff09\u4f20\u9012\u5230 Razor \u89c6\u56fe\uff0c\u540e\u8005\u4f1a\u751f\u6210 HTML \u54cd\u5e94\u3002\u5982\u679c\u60a8\u772f\u7740\u773c\u775b\u770b\uff0c\u6b64\u6a21\u5f0f\u770b\u8d77\u6765\u7c7b\u4f3c\u4e8e MVC \u8bbe\u8ba1\u6a21\u5f0f\u3002<\/p>\n<p>Depending on your background in software development, you may have come across the MVC pattern in some form. In web development, MVC is a common paradigm, used in frameworks such as Django, Rails, and Spring MVC. But as it\u2019s such a broad concept, you can find MVC in everything from mobile apps to rich-client desktop applications. I hope that indicates the benefits of the pattern when it\u2019s used correctly! In section 13.3 we\u2019ll look at the MVC pattern in general and how ASP.NET Core uses it.<\/p>\n<p>\u6839\u636e\u4f60\u7684\u8f6f\u4ef6\u5f00\u53d1\u80cc\u666f\uff0c\u4f60\u53ef\u80fd\u9047\u5230\u8fc7\u67d0\u79cd\u5f62\u5f0f\u7684 MVC \u6a21\u5f0f\u3002\u5728 Web \u5f00\u53d1\u4e2d\uff0cMVC \u662f\u4e00\u79cd\u5e38\u89c1\u7684\u8303\u5f0f\uff0c\u7528\u4e8e Django\u3001Rails \u548c Spring MVC \u7b49\u6846\u67b6\u3002\u4f46\u662f\uff0c\u7531\u4e8e MVC \u662f\u4e00\u4e2a\u5982\u6b64\u5e7f\u6cdb\u7684\u6982\u5ff5\uff0c\u56e0\u6b64\u60a8\u53ef\u4ee5\u5728\u4ece\u79fb\u52a8\u5e94\u7528\u7a0b\u5e8f\u5230\u5bcc\u5ba2\u6237\u7aef\u684c\u9762\u5e94\u7528\u7a0b\u5e8f\u7684\u6240\u6709\u5e94\u7528\u7a0b\u5e8f\u4e2d\u627e\u5230 MVC\u3002\u6211\u5e0c\u671b\u8fd9\u8868\u660e\u6b63\u786e\u4f7f\u7528\u8be5\u6a21\u5f0f\u7684\u597d\u5904\uff01\u5728 Section 13.3 \u4e2d\uff0c\u6211\u4eec\u5c06\u5927\u81f4\u4e86\u89e3 MVC \u6a21\u5f0f\u4ee5\u53ca ASP.NET Core \u5982\u4f55\u4f7f\u7528\u5b83\u3002<\/p>\n<h2>13.3 Understanding the MVC design pattern<\/h2>\n<h2>13.3 \u4e86\u89e3 MVC \u8bbe\u8ba1\u6a21\u5f0f<\/h2>\n<p>The MVC design pattern is a common pattern for designing apps that have UIs. The MVC pattern has many interpretations, each of which focuses on a slightly different aspect of the pattern. The original MVC design pattern was specified with rich-client graphical user interface (GUI) apps in mind, rather than web applications, so it uses terminology and paradigms associated with a GUI environment. Fundamentally, though, the pattern aims to separate the management and manipulation of data from its visual representation.<\/p>\n<p>MVC \u8bbe\u8ba1\u6a21\u5f0f\u662f\u8bbe\u8ba1\u5177\u6709 UI \u7684\u5e94\u7528\u7a0b\u5e8f\u7684\u5e38\u89c1\u6a21\u5f0f\u3002MVC \u6a21\u5f0f\u6709\u591a\u79cd\u89e3\u91ca\uff0c\u6bcf\u79cd\u89e3\u91ca\u90fd\u4fa7\u91cd\u4e8e\u6a21\u5f0f\u7684\u4e00\u4e2a\u7565\u6709\u4e0d\u540c\u7684\u65b9\u9762\u3002\u6700\u521d\u7684 MVC \u8bbe\u8ba1\u6a21\u5f0f\u5728\u6307\u5b9a\u65f6\u8003\u8651\u4e86\u5bcc\u5ba2\u6237\u7aef\u56fe\u5f62\u7528\u6237\u754c\u9762 \uff08GUI\uff09 \u5e94\u7528\u7a0b\u5e8f\uff0c\u800c\u4e0d\u662f Web \u5e94\u7528\u7a0b\u5e8f\uff0c\u56e0\u6b64\u5b83\u4f7f\u7528\u4e86\u4e0e GUI \u73af\u5883\u76f8\u5173\u7684\u672f\u8bed\u548c\u8303\u4f8b\u3002\u4e0d\u8fc7\uff0c\u4ece\u6839\u672c\u4e0a\u8bf4\uff0c\u8be5\u6a21\u5f0f\u65e8\u5728\u5c06\u6570\u636e\u7684\u7ba1\u7406\u548c\u4f5c\u4e0e\u5176\u89c6\u89c9\u8868\u793a\u5206\u5f00\u3002<\/p>\n<p>Before I dive too far into the design pattern itself, let\u2019s consider a typical Razor Pages request. Imagine that a user requests the Razor Page from listing 13.5 that displays a to-do list category. Figure 13.7 shows how a Razor Page handles different aspects of a request, all of which combine to generate the final response.<\/p>\n<p>\u5728\u6df1\u5165\u7814\u7a76\u8bbe\u8ba1\u6a21\u5f0f\u672c\u8eab\u4e4b\u524d\uff0c\u8ba9\u6211\u4eec\u8003\u8651\u4e00\u4e2a\u5178\u578b\u7684 Razor Pages \u8bf7\u6c42\u3002\u5047\u8bbe\u7528\u6237\u4ece\u663e\u793a\u5f85\u529e\u4e8b\u9879\u5217\u8868\u7c7b\u522b\u7684\u6e05\u5355 13.5 \u4e2d\u8bf7\u6c42 Razor \u9875\u9762\u3002\u56fe 13.7 \u663e\u793a\u4e86 Razor Page \u5982\u4f55\u5904\u7406\u8bf7\u6c42\u7684\u4e0d\u540c\u65b9\u9762\uff0c\u6240\u6709\u8fd9\u4e9b\u65b9\u9762\u7ed3\u5408\u8d77\u6765\u751f\u6210\u6700\u7ec8\u54cd\u5e94\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1307.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 13.7 Requesting a to-do list page for a Razor Pages application. A different component handles each aspect of the request.<br \/>\n\u56fe 13.7 \u8bf7\u6c42 Razor Pages \u5e94\u7528\u7a0b\u5e8f\u7684\u5f85\u529e\u4e8b\u9879\u5217\u8868\u9875\u9762\u3002\u4e0d\u540c\u7684\u7ec4\u4ef6\u5904\u7406\u8bf7\u6c42\u7684\u6bcf\u4e2a\u65b9\u9762\u3002<\/p>\n<p>In general, three components make up the MVC design pattern:<\/p>\n<p>\u901a\u5e38\uff0cMVC \u8bbe\u8ba1\u6a21\u5f0f\u7531\u4e09\u4e2a\u7ec4\u4ef6\u7ec4\u6210\uff1a<\/p>\n<ul>\n<li>\n<p>Model\u2014The data that needs to be displayed\u2014the global state of the application. It\u2019s accessed via the ToDoService in listing 13.5.<br \/>\nModel \uff08\u6a21\u578b\uff09 - \u9700\u8981\u663e\u793a\u7684\u6570\u636e - \u5e94\u7528\u7a0b\u5e8f\u7684\u5168\u5c40\u72b6\u6001\u3002\u5b83\u53ef\u4ee5\u901a\u8fc7\u6e05\u5355 13.5 \u4e2d\u7684 ToDoService \u8bbf\u95ee\u3002<\/p>\n<\/li>\n<li>\n<p>View\u2014The template that displays the data provided by the model.<br \/>\nView \uff08\u89c6\u56fe\uff09 - \u663e\u793a\u6a21\u578b\u63d0\u4f9b\u7684\u6570\u636e\u7684\u6a21\u677f\u3002<\/p>\n<\/li>\n<li>\n<p>Controller\u2014Updates the model and provides the data for display to the view. This role is taken by the page handler in Razor Pages\u2014the OnGet method in listing 13.5.<br \/>\nController \uff08\u63a7\u5236\u5668\uff09 - \u66f4\u65b0\u6a21\u578b\u5e76\u63d0\u4f9b\u6570\u636e\u4ee5\u663e\u793a\u5728\u89c6\u56fe\u4e2d\u3002\u6b64\u89d2\u8272\u7531 Razor Pages \u4e2d\u7684\u9875\u9762\u5904\u7406\u7a0b\u5e8f\uff08\u5217\u8868 13.5 \u4e2d\u7684 OnGet \u65b9\u6cd5\uff09\u62c5\u4efb\u3002<\/p>\n<\/li>\n<\/ul>\n<p>Each component of the MVC design pattern is responsible for a single aspect of the overall system, which, when combined, generates a UI. The to-do list example considers MVC in terms of a web application using Razor Pages, but a generalized request could be equivalent to the click of a button in a desktop GUI application.<\/p>\n<p>MVC \u8bbe\u8ba1\u6a21\u5f0f\u7684\u6bcf\u4e2a\u7ec4\u4ef6\u90fd\u8d1f\u8d23\u6574\u4e2a\u7cfb\u7edf\u7684\u4e00\u4e2a\u65b9\u9762\uff0c\u5f53\u8fd9\u4e9b\u65b9\u9762\u7ec4\u5408\u5728\u4e00\u8d77\u65f6\uff0c\u5c06\u751f\u6210\u4e00\u4e2a UI\u3002\u5f85\u529e\u4e8b\u9879\u5217\u8868\u793a\u4f8b\u4ece\u4f7f\u7528 Razor Pages \u7684 Web \u5e94\u7528\u7a0b\u5e8f\u7684\u89d2\u5ea6\u8003\u8651 MVC\uff0c\u4f46\u901a\u7528\u8bf7\u6c42\u53ef\u80fd\u7b49\u6548\u4e8e\u5355\u51fb\u684c\u9762 GUI \u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u6309\u94ae\u3002<\/p>\n<p>In general, the order of events when an application responds to a user interaction or request is as follows:<\/p>\n<p>\u901a\u5e38\uff0c\u5e94\u7528\u7a0b\u5e8f\u54cd\u5e94\u7528\u6237\u4ea4\u4e92\u6216\u8bf7\u6c42\u65f6\u7684\u4e8b\u4ef6\u987a\u5e8f\u5982\u4e0b\uff1a<\/p>\n<ol>\n<li>\n<p>The controller (the Razor Page handler) receives the request.<br \/>\n\u63a7\u5236\u5668 \uff08Razor Page \u5904\u7406\u7a0b\u5e8f\uff09 \u63a5\u6536\u8bf7\u6c42\u3002<\/p>\n<\/li>\n<li>\n<p>Depending on the request, the controller either fetches the requested data from the application model using injected services or updates the data that makes up the model.<br \/>\n\u6839\u636e\u8bf7\u6c42\uff0c\u63a7\u5236\u5668\u8981\u4e48\u4f7f\u7528\u6ce8\u5165\u7684\u670d\u52a1\u4ece\u5e94\u7528\u7a0b\u5e8f\u6a21\u578b\u4e2d\u83b7\u53d6\u8bf7\u6c42\u7684\u6570\u636e\uff0c\u8981\u4e48\u66f4\u65b0\u6784\u6210\u6a21\u578b\u7684\u6570\u636e\u3002<\/p>\n<\/li>\n<li>\n<p>The controller selects a view to display and passes a representation of the model (the view model) to it.<br \/>\n\u63a7\u5236\u5668\u9009\u62e9\u8981\u663e\u793a\u7684\u89c6\u56fe\uff0c\u5e76\u5c06\u6a21\u578b\u7684\u8868\u793a \uff08\u89c6\u56fe\u6a21\u578b\uff09 \u4f20\u9012\u7ed9\u8be5\u89c6\u56fe\u3002<\/p>\n<\/li>\n<li>\n<p>The view uses the data contained in the model to generate the UI.<br \/>\n\u8be5\u89c6\u56fe\u4f7f\u7528\u6a21\u578b\u4e2d\u5305\u542b\u7684\u6570\u636e\u6765\u751f\u6210 UI\u3002<\/p>\n<\/li>\n<\/ol>\n<p>When we describe MVC in this format, the controller (the Razor Page handler) serves as the entry point for the interaction. The user communicates with the controller to instigate an interaction. In web applications, this interaction takes the form of an HTTP request, so when a request to a URL is received, the controller handles it.<\/p>\n<p>\u5f53\u6211\u4eec\u4ee5\u8fd9\u79cd\u683c\u5f0f\u63cf\u8ff0 MVC \u65f6\uff0c\u63a7\u5236\u5668\uff08Razor Page \u5904\u7406\u7a0b\u5e8f\uff09\u5c06\u7528\u4f5c\u4ea4\u4e92\u7684\u5165\u53e3\u70b9\u3002\u7528\u6237\u4e0e\u63a7\u5236\u5668\u901a\u4fe1\u4ee5\u5f15\u53d1\u4ea4\u4e92\u3002\u5728 Web \u5e94\u7528\u7a0b\u5e8f\u4e2d\uff0c\u6b64\u4ea4\u4e92\u91c7\u7528 HTTP \u8bf7\u6c42\u7684\u5f62\u5f0f\uff0c\u56e0\u6b64\u5f53\u6536\u5230\u5bf9 URL \u7684\u8bf7\u6c42\u65f6\uff0c\u63a7\u5236\u5668\u4f1a\u5bf9\u5176\u8fdb\u884c\u5904\u7406\u3002<\/p>\n<p>Depending on the nature of the request, the controller may take a variety of actions, but the key point is that the actions are undertaken using the application model. The model here contains all the business logic for the application, so it\u2019s able to provide requested data or perform actions.<\/p>\n<p>\u6839\u636e\u8bf7\u6c42\u7684\u6027\u8d28\uff0c\u63a7\u5236\u5668\u53ef\u80fd\u4f1a\u91c7\u53d6\u5404\u79cd\u4f5c\uff0c\u4f46\u5173\u952e\u662f\u8fd9\u4e9b\u4f5c\u662f\u4f7f\u7528\u5e94\u7528\u7a0b\u5e8f\u6a21\u578b\u6267\u884c\u7684\u3002\u6b64\u5904\u7684\u6a21\u578b\u5305\u542b\u5e94\u7528\u7a0b\u5e8f\u7684\u6240\u6709\u4e1a\u52a1\u903b\u8f91\uff0c\u56e0\u6b64\u5b83\u80fd\u591f\u63d0\u4f9b\u8bf7\u6c42\u7684\u6570\u636e\u6216\u6267\u884c\u4f5c\u3002<\/p>\n<p><strong>Note<\/strong> In this description of MVC, the model is considered to be a complex beast, containing all the logic for how to perform an action, as well as any internal state. The Razor Page PageModel class is not the model we\u2019re talking about! Unfortunately, as in all software development, naming things is hard.<br \/>\n<strong>\u6ce8\u610f<\/strong> \u5728 MVC \u7684\u8fd9\u4e2a\u63cf\u8ff0\u4e2d\uff0c\u6a21\u578b\u88ab\u8ba4\u4e3a\u662f\u4e00\u4e2a\u590d\u6742\u7684\u91ce\u517d\uff0c\u5305\u542b\u5982\u4f55\u6267\u884c\u4f5c\u7684\u6240\u6709\u903b\u8f91\uff0c\u4ee5\u53ca\u4efb\u4f55\u5185\u90e8\u72b6\u6001\u3002Razor Page PageModel \u7c7b\u4e0d\u662f\u6211\u4eec\u6b63\u5728\u8c08\u8bba\u7684\u6a21\u578b\uff01\u4e0d\u5e78\u7684\u662f\uff0c\u5c31\u50cf\u5728\u6240\u6709\u8f6f\u4ef6\u5f00\u53d1\u4e2d\u4e00\u6837\uff0c\u547d\u540d\u4e8b\u7269\u662f\u56f0\u96be\u7684\u3002<\/p>\n<p>Consider a request to view a product page for an e-commerce application. The controller would receive the request and know how to contact some product service that\u2019s part of the application model. This service might fetch the details of the requested product from a database and return them to the controller.<\/p>\n<p>\u8003\u8651\u67e5\u770b\u7535\u5b50\u5546\u52a1\u5e94\u7528\u7a0b\u5e8f\u7684\u4ea7\u54c1\u9875\u9762\u7684\u8bf7\u6c42\u3002\u63a7\u5236\u5668\u5c06\u6536\u5230\u8bf7\u6c42\u5e76\u77e5\u9053\u5982\u4f55\u8054\u7cfb\u5c5e\u4e8e\u5e94\u7528\u7a0b\u5e8f\u6a21\u578b\u7684\u67d0\u4e9b\u4ea7\u54c1\u670d\u52a1\u3002\u6b64\u670d\u52a1\u53ef\u80fd\u4f1a\u4ece\u6570\u636e\u5e93\u4e2d\u83b7\u53d6\u6240\u8bf7\u6c42\u4ea7\u54c1\u7684\u8be6\u7ec6\u4fe1\u606f\uff0c\u5e76\u5c06\u5176\u8fd4\u56de\u7ed9\u63a7\u5236\u5668\u3002<\/p>\n<p>Alternatively, imagine that a controller receives a request to add a product to the user\u2019s shopping cart. The controller would receive the request and most likely would invoke a method on the model to request that the product be added. Then the model would update its internal representation of the user\u2019s cart, by adding (for example) a new row to a database table holding the user\u2019s data.<\/p>\n<p>\u6216\u8005\uff0c\u5047\u8bbe\u63a7\u5236\u5668\u6536\u5230\u5c06\u4ea7\u54c1\u6dfb\u52a0\u5230\u7528\u6237\u8d2d\u7269\u8f66\u7684\u8bf7\u6c42\u3002\u63a7\u5236\u5668\u5c06\u6536\u5230\u8bf7\u6c42\uff0c\u5e76\u4e14\u5f88\u53ef\u80fd\u4f1a\u8c03\u7528\u6a21\u578b\u4e0a\u7684\u65b9\u6cd5\u4ee5\u8bf7\u6c42\u6dfb\u52a0\u4ea7\u54c1\u3002\u7136\u540e\uff0c\u8be5\u6a21\u578b\u5c06\u66f4\u65b0\u5176\u7528\u6237\u8d2d\u7269\u8f66\u7684\u5185\u90e8\u8868\u793a\uff0c\u65b9\u6cd5\u662f\u5411\u5305\u542b\u7528\u6237\u6570\u636e\u7684\u6570\u636e\u5e93\u8868\u6dfb\u52a0\u65b0\u884c\uff08\u4f8b\u5982\uff09\u3002<\/p>\n<p><strong>Tip<\/strong> You can think of each Razor Page handler as being a mini controller focused on a single page. Every web request is another independent call to a controller that orchestrates the response. Although there are many controllers, all the handlers interact with the same application model.<br \/>\n<strong>\u63d0\u793a<\/strong> \u60a8\u53ef\u4ee5\u5c06\u6bcf\u4e2a Razor Page \u5904\u7406\u7a0b\u5e8f\u89c6\u4e3a\u4e00\u4e2a\u4e13\u6ce8\u4e8e\u5355\u4e2a\u9875\u9762\u7684\u8ff7\u4f60\u63a7\u5236\u5668\u3002\u6bcf\u4e2a Web \u8bf7\u6c42\u90fd\u662f\u5bf9\u7f16\u6392\u54cd\u5e94\u7684\u63a7\u5236\u5668\u7684\u53e6\u4e00\u4e2a\u72ec\u7acb\u8c03\u7528\u3002\u5c3d\u7ba1\u6709\u8bb8\u591a\u63a7\u5236\u5668\uff0c\u4f46\u6240\u6709\u5904\u7406\u7a0b\u5e8f\u90fd\u4e0e\u76f8\u540c\u7684\u5e94\u7528\u7a0b\u5e8f\u6a21\u578b\u4ea4\u4e92\u3002<\/p>\n<p>After the model has been updated, the controller needs to decide what response to generate. One of the advantages of using the MVC design pattern is that the model representing the application\u2019s data is decoupled from the final representation of that data, called the view. The controller is responsible for deciding whether the response should generate an HTML view, whether it should send the user to a new page, or whether it should return an error page.<\/p>\n<p>\u66f4\u65b0\u6a21\u578b\u540e\uff0c\u63a7\u5236\u5668\u9700\u8981\u51b3\u5b9a\u8981\u751f\u6210\u4ec0\u4e48\u54cd\u5e94\u3002\u4f7f\u7528 MVC \u8bbe\u8ba1\u6a21\u5f0f\u7684\u4e00\u4e2a\u4f18\u70b9\u662f\uff0c\u8868\u793a\u5e94\u7528\u7a0b\u5e8f\u6570\u636e\u7684\u6a21\u578b\u4e0e\u8be5\u6570\u636e\u7684\u6700\u7ec8\u8868\u793a\u5f62\u5f0f\uff08\u79f0\u4e3a\u89c6\u56fe\uff09\u5206\u79bb\u3002\u63a7\u5236\u5668\u8d1f\u8d23\u51b3\u5b9a\u54cd\u5e94\u662f\u5426\u5e94\u751f\u6210 HTML \u89c6\u56fe\uff0c\u662f\u5426\u5e94\u5c06\u7528\u6237\u53d1\u9001\u5230\u65b0\u9875\u9762\uff0c\u6216\u8005\u662f\u5426\u5e94\u8fd4\u56de\u9519\u8bef\u9875\u9762\u3002<\/p>\n<p>One of the advantages of the model\u2019s being independent of the view is that it improves testability. UI code is classically hard to test, as it\u2019s dependent on the environment; anyone who has written UI tests simulating a user clicking buttons and typing in forms knows that it\u2019s typically fragile. By keeping the model independent of the view, you can ensure that the model stays easily testable, without any dependencies on UI constructs. As the model often contains your application\u2019s business logic, this is clearly a good thing!<\/p>\n<p>\u6a21\u578b\u72ec\u7acb\u4e8e\u89c6\u56fe\u7684\u4f18\u70b9\u4e4b\u4e00\u662f\u5b83\u63d0\u9ad8\u4e86\u53ef\u6d4b\u8bd5\u6027\u3002UI \u4ee3\u7801\u901a\u5e38\u5f88\u96be\u6d4b\u8bd5\uff0c\u56e0\u4e3a\u5b83\u4f9d\u8d56\u4e8e\u73af\u5883;\u4efb\u4f55\u7f16\u5199\u8fc7\u6a21\u62df\u7528\u6237\u5355\u51fb\u6309\u94ae\u548c\u5728\u8868\u5355\u4e2d\u952e\u5165\u7684 UI \u6d4b\u8bd5\u7684\u4eba\u90fd\u77e5\u9053\uff0c\u5b83\u901a\u5e38\u662f\u8106\u5f31\u7684\u3002\u901a\u8fc7\u4f7f\u6a21\u578b\u72ec\u7acb\u4e8e\u89c6\u56fe\uff0c\u60a8\u53ef\u4ee5\u786e\u4fdd\u6a21\u578b\u6613\u4e8e\u6d4b\u8bd5\uff0c\u800c\u4e0d\u4f9d\u8d56\u4e8e UI \u6784\u9020\u3002\u7531\u4e8e\u8be5\u6a21\u578b\u901a\u5e38\u5305\u542b\u5e94\u7528\u7a0b\u5e8f\u7684\u4e1a\u52a1\u903b\u8f91\uff0c\u8fd9\u663e\u7136\u662f\u4e00\u4ef6\u597d\u4e8b\uff01<\/p>\n<p>The view can use the data passed to it by the controller to generate the appropriate HTML response. The view is responsible only for generating the final representation of the data; it\u2019s not involved in any of the business logic.<\/p>\n<p>\u89c6\u56fe\u53ef\u4ee5\u4f7f\u7528\u63a7\u5236\u5668\u4f20\u9012\u7ed9\u5b83\u7684\u6570\u636e\u6765\u751f\u6210\u9002\u5f53\u7684 HTML \u54cd\u5e94\u3002\u89c6\u56fe\u4ec5\u8d1f\u8d23\u751f\u6210\u6570\u636e\u7684\u6700\u7ec8\u8868\u793a\u5f62\u5f0f;\u5b83\u4e0d\u6d89\u53ca\u4efb\u4f55\u4e1a\u52a1\u903b\u8f91\u3002<\/p>\n<p>This is all there is to the MVC design pattern in relation to web applications. Much of the confusion related to MVC seems to stem from slightly different uses of the term for slightly different frameworks and types of applications. In section 13.4 I\u2019ll show how the ASP.NET Core framework uses the MVC pattern with Razor Pages, along with more examples of the pattern in action.<\/p>\n<p>\u8fd9\u5c31\u662f MVC \u8bbe\u8ba1\u6a21\u5f0f\u4e0e Web \u5e94\u7528\u7a0b\u5e8f\u76f8\u5173\u7684\u5168\u90e8\u5185\u5bb9\u3002\u8bb8\u591a\u4e0e MVC \u76f8\u5173\u7684\u6df7\u6dc6\u4f3c\u4e4e\u6e90\u4e8e\u8be5\u672f\u8bed\u5bf9\u6846\u67b6\u548c\u5e94\u7528\u7a0b\u5e8f\u7c7b\u578b\u7684\u7528\u6cd5\u7565\u6709\u4e0d\u540c\u3002\u5728\u7b2c 13.4 \u8282\u4e2d\uff0c\u6211\u5c06\u5c55\u793a ASP.NET Core \u6846\u67b6\u5982\u4f55\u5c06 MVC \u6a21\u5f0f\u4e0e Razor Pages \u7ed3\u5408\u4f7f\u7528\uff0c\u4ee5\u53ca\u8be5\u6a21\u5f0f\u7684\u66f4\u591a\u5b9e\u9645\u793a\u4f8b\u3002<\/p>\n<h2>13.4 Applying the MVC design pattern to Razor Pages<\/h2>\n<h2>13.4 \u5c06 MVC \u8bbe\u8ba1\u6a21\u5f0f\u5e94\u7528\u4e8e Razor Pages<\/h2>\n<p>In section 13.3 I discussed the MVC pattern as it\u2019s typically used in web applications; Razor Pages use this pattern. But ASP.NET Core also includes a framework called ASP.NET Core MVC. This framework (unsurprisingly) closely mirrors the MVC design pattern, using controllers containing action methods in place of Razor Pages and page handlers. Razor Pages builds directly on top of the underlying ASP.NET Core MVC framework, using the MVC framework under the hood for their behavior.<\/p>\n<p>\u5728 Section 13.3 \u4e2d\uff0c\u6211\u8ba8\u8bba\u4e86 MVC \u6a21\u5f0f\uff0c\u56e0\u4e3a\u5b83\u901a\u5e38\u7528\u4e8e Web \u5e94\u7528\u7a0b\u5e8f;Razor Pages \u4f7f\u7528\u6b64\u6a21\u5f0f\u3002\u4f46 ASP.NET Core \u8fd8\u5305\u62ec\u4e00\u4e2a\u540d\u4e3a ASP.NET Core MVC \u7684\u6846\u67b6\u3002\u6b64\u6846\u67b6\uff08\u4e0d\u51fa\u6240\u6599\uff09\u4e0e MVC \u8bbe\u8ba1\u6a21\u5f0f\u7d27\u5bc6\u955c\u50cf\uff0c\u4f7f\u7528\u5305\u542b\u4f5c\u65b9\u6cd5\u7684\u63a7\u5236\u5668\u6765\u4ee3\u66ff Razor Pages \u548c\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u3002Razor Pages \u76f4\u63a5\u6784\u5efa\u5728\u57fa\u7840 ASP.NET Core MVC \u6846\u67b6\u4e4b\u4e0a\uff0c\u5e76\u5728\u540e\u53f0\u4f7f\u7528 MVC \u6846\u67b6\u6765\u5b9e\u73b0\u5176\u884c\u4e3a\u3002<\/p>\n<p>If you prefer, you can avoid Razor Pages and work with the MVC framework directly in ASP.NET Core. This option was the only one in early versions of ASP.NET Core and the previous version of ASP.NET.<\/p>\n<p>\u5982\u679c\u613f\u610f\uff0c\u53ef\u4ee5\u907f\u514d\u4f7f\u7528 Razor Pages\uff0c\u76f4\u63a5\u5728 ASP.NET Core \u4e2d\u4f7f\u7528 MVC \u6846\u67b6\u3002\u6b64\u9009\u9879\u662f ASP.NET Core \u65e9\u671f\u7248\u672c\u548c ASP.NET \u65e9\u671f\u7248\u672c\u4e2d\u7684\u552f\u4e00\u9009\u9879\u3002<\/p>\n<p><strong>Tip<\/strong> I look in greater depth at choosing between Razor Pages and the MVC framework in chapter 19.<br \/>\n<strong>\u63d0\u793a<\/strong> \u5728\u7b2c 19 \u7ae0\u4e2d\uff0c\u6211\u5c06\u66f4\u6df1\u5165\u5730\u4e86\u89e3\u5982\u4f55\u5728 Razor Pages \u548c MVC \u6846\u67b6\u4e4b\u95f4\u8fdb\u884c\u9009\u62e9\u3002<\/p>\n<p>In this section we look in greater depth at how the MVC design pattern applies to Razor Pages in ASP.NET Core. This section will also help clarify the role of various features of Razor Pages.<\/p>\n<p>\u5728\u672c\u90e8\u5206\u4e2d\uff0c\u6211\u4eec\u5c06\u66f4\u6df1\u5165\u5730\u4e86\u89e3 MVC \u8bbe\u8ba1\u6a21\u5f0f\u5982\u4f55\u5e94\u7528\u4e8e ASP.NET Core \u4e2d\u7684 Razor \u9875\u9762\u3002\u8fd9\u90e8\u5206\u8fd8\u5c06\u6709\u52a9\u4e8e\u9610\u660e Razor Pages \u7684\u5404\u79cd\u529f\u80fd\u7684\u4f5c\u7528\u3002<\/p>\n<blockquote>\n<p>Do Razor Pages use MVC or MVVM?<br \/>\nRazor Pages \u4f7f\u7528 MVC \u8fd8\u662f MVVM\uff1f<br \/>\nOccasionally, I\u2019ve seen people describe Razor Pages as using the Model-View-View Model (MVVM) design pattern rather than the MVC design pattern. don\u2019t agree, but it\u2019s worth being aware of the differences.<br \/>\n\u6709\u65f6\uff0c\u6211\u770b\u5230\u4eba\u4eec\u5c06 Razor Pages \u63cf\u8ff0\u4e3a\u4f7f\u7528\u6a21\u578b-\u89c6\u56fe-\u89c6\u56fe\u6a21\u578b \uff08MVVM\uff09 \u8bbe\u8ba1\u6a21\u5f0f\uff0c\u800c\u4e0d\u662f MVC \u8bbe\u8ba1\u6a21\u5f0f\u3002\u6211\u4e0d\u540c\u610f\uff0c\u4f46\u503c\u5f97\u610f\u8bc6\u5230\u5dee\u5f02\u3002<br \/>\nMVVM is a UI pattern that is often used in mobile apps, desktop apps, and some client-side frameworks. It differs from MVC in that there is a bidirectional interaction between the view and the view model. The view model tells the view what to display, but the view can also trigger changes directly on the view model. It\u2019s often used with two-way data binding where a view model is bound to a view.<br \/>\nMVVM \u662f\u4e00\u79cd UI \u6a21\u5f0f\uff0c\u901a\u5e38\u7528\u4e8e\u79fb\u52a8\u5e94\u7528\u7a0b\u5e8f\u3001\u684c\u9762\u5e94\u7528\u7a0b\u5e8f\u548c\u4e00\u4e9b\u5ba2\u6237\u7aef\u6846\u67b6\u3002\u5b83\u4e0e MVC \u7684\u4e0d\u540c\u4e4b\u5904\u5728\u4e8e\uff0c\u89c6\u56fe\u548c\u89c6\u56fe\u6a21\u578b\u4e4b\u95f4\u5b58\u5728\u53cc\u5411\u4ea4\u4e92\u3002\u89c6\u56fe\u6a21\u578b\u544a\u8bc9\u89c6\u56fe\u8981\u663e\u793a\u4ec0\u4e48\uff0c\u4f46\u89c6\u56fe\u4e5f\u53ef\u4ee5\u76f4\u63a5\u5728\u89c6\u56fe\u6a21\u578b\u4e0a\u89e6\u53d1\u66f4\u6539\u3002\u5b83\u901a\u5e38\u4e0e\u53cc\u5411\u6570\u636e\u7ed1\u5b9a\u4e00\u8d77\u4f7f\u7528\uff0c\u5176\u4e2d\u89c6\u56fe\u6a21\u578b\u7ed1\u5b9a\u5230\u89c6\u56fe\u3002<br \/>\nSome people consider the Razor Pages PageModel to be filling this role, but I\u2019m not convinced. Razor Pages definitely seems based on the MVC pattern to me (it\u2019s based on the ASP.NET Core MVC framework after all!), and it doesn\u2019t have the same two-way binding that I would expect with MVVM.<br \/>\n\u6709\u4e9b\u4eba\u8ba4\u4e3a Razor Pages PageModel \u6b63\u5728\u626e\u6f14\u8fd9\u4e2a\u89d2\u8272\uff0c\u4f46\u6211\u4e0d\u76f8\u4fe1\u3002\u5728\u6211\u770b\u6765\uff0cRazor Pages \u7edd\u5bf9\u662f\u57fa\u4e8e MVC \u6a21\u5f0f\u7684\uff08\u6bd5\u7adf\u5b83\u57fa\u4e8e ASP.NET Core MVC \u6846\u67b6\uff01\uff09\uff0c\u5e76\u4e14\u5b83\u6ca1\u6709\u6211\u6240\u671f\u671b\u7684 MVVM \u7684\u53cc\u5411\u7ed1\u5b9a\u3002<\/p>\n<\/blockquote>\n<p>As you\u2019ve seen in previous chapters, ASP.NET Core implements Razor Page endpoints using a combination of RoutingMiddleware and EndpointMiddleware, as shown in figure 13.8. When a request has been processed by earlier middleware (and assuming that none has handled the request and short-circuited the pipeline), the routing middleware selects which Razor Page handler should be executed, and the endpoint middleware executes the page handler.<br \/>\n\u5982\u524d\u51e0\u7ae0\u6240\u793a\uff0cASP.NET Core \u4f7f\u7528 RoutingMiddleware \u548c EndpointMiddleware \u7684\u7ec4\u5408\u5b9e\u73b0 Razor Page \u7ec8\u7ed3\u70b9\uff0c\u5982\u56fe 13.8 \u6240\u793a\u3002\u5f53\u8bf7\u6c42\u7531\u65e9\u671f\u4e2d\u95f4\u4ef6\u5904\u7406\u65f6\uff08\u5e76\u5047\u8bbe\u6ca1\u6709\u4e2d\u95f4\u4ef6\u5904\u7406\u8bf7\u6c42\u5e76\u4f7f\u7ba1\u9053\u77ed\u8def\uff09\uff0c\u8def\u7531\u4e2d\u95f4\u4ef6\u5c06\u9009\u62e9\u5e94\u6267\u884c\u54ea\u4e2a Razor Page \u5904\u7406\u7a0b\u5e8f\uff0c\u800c\u7ec8\u7ed3\u70b9\u4e2d\u95f4\u4ef6\u5c06\u6267\u884c\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1308.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 13.8 The middleware pipeline for a typical ASP.NET Core application. The request is processed by middleware in sequence. If the request reaches the routing middleware, the middleware selects an endpoint, such as a Razor Page, to execute. The endpoint middleware executes the selected endpoint.<br \/>\n\u56fe 13.8 \u5178\u578b ASP.NET Core \u5e94\u7528\u7a0b\u5e8f\u7684\u4e2d\u95f4\u4ef6\u7ba1\u9053\u3002\u4e2d\u95f4\u4ef6\u4f1a\u6309\u987a\u5e8f\u5904\u7406\u8be5\u8bf7\u6c42\u3002\u5982\u679c\u8bf7\u6c42\u5230\u8fbe\u8def\u7531\u4e2d\u95f4\u4ef6\uff0c\u4e2d\u95f4\u4ef6\u4f1a\u9009\u62e9\u4e00\u4e2a\u7aef\u70b9\uff08\u4f8b\u5982 Razor Page\uff09\u6765\u6267\u884c\u3002\u7aef\u70b9\u4e2d\u95f4\u4ef6\u6267\u884c\u9009\u5b9a\u7684\u7aef\u70b9\u3002<\/p>\n<p>As you\u2019ve seen in earlier chapters, middleware often handles cross-cutting concerns or narrowly defined requests, such as requests for files. For requirements that fall outside these functions or that have many external dependencies, a more robust framework is required. Razor Pages (and\/or ASP.NET Core MVC) can provide this framework, allowing interaction with your application\u2019s core business logic and the generation of a UI. It handles everything from mapping the request to an appropriate page handler (or controller action method) to generating the HTML response.<\/p>\n<p>\u6b63\u5982\u4f60\u5728\u524d\u9762\u7684\u7ae0\u8282\u4e2d\u6240\u770b\u5230\u7684\uff0c\u4e2d\u95f4\u4ef6\u901a\u5e38\u5904\u7406\u6a2a\u5207\u5173\u6ce8\u70b9\u6216\u72ed\u4e49\u5b9a\u4e49\u7684\u8bf7\u6c42\uff0c\u6bd4\u5982\u6587\u4ef6\u8bf7\u6c42\u3002\u5bf9\u4e8e\u8d85\u51fa\u8fd9\u4e9b\u529f\u80fd\u6216\u5177\u6709\u8bb8\u591a\u5916\u90e8\u4f9d\u8d56\u9879\u7684\u9700\u6c42\uff0c\u9700\u8981\u66f4\u5065\u58ee\u7684\u6846\u67b6\u3002Razor Pages\uff08\u548c\/\u6216 ASP.NET Core MVC\uff09\u53ef\u4ee5\u63d0\u4f9b\u6b64\u6846\u67b6\uff0c\u5141\u8bb8\u4e0e\u5e94\u7528\u7a0b\u5e8f\u7684\u6838\u5fc3\u4e1a\u52a1\u903b\u8f91\u4ea4\u4e92\u5e76\u751f\u6210 UI\u3002\u5b83\u5904\u7406\u4ece\u5c06\u8bf7\u6c42\u6620\u5c04\u5230\u9002\u5f53\u7684\u9875\u9762\u5904\u7406\u7a0b\u5e8f\uff08\u6216\u63a7\u5236\u5668\u4f5c\u65b9\u6cd5\uff09\u5230\u751f\u6210 HTML \u54cd\u5e94\u7684\u6240\u6709\u4f5c\u3002<\/p>\n<p>In the traditional description of the MVC design pattern, there\u2019s only a single type of model, which holds all the non-UI data and behavior. The controller updates this model as appropriate and then passes it to the view, which uses it to generate a UI.<\/p>\n<p>\u5728 MVC \u8bbe\u8ba1\u6a21\u5f0f\u7684\u4f20\u7edf\u63cf\u8ff0\u4e2d\uff0c\u53ea\u6709\u4e00\u79cd\u7c7b\u578b\u7684\u6a21\u578b\uff0c\u5b83\u5305\u542b\u6240\u6709\u975e UI \u6570\u636e\u548c\u884c\u4e3a\u3002\u63a7\u5236\u5668\u4f1a\u6839\u636e\u9700\u8981\u66f4\u65b0\u6b64\u6a21\u578b\uff0c\u7136\u540e\u5c06\u5176\u4f20\u9012\u7ed9\u89c6\u56fe\uff0c\u89c6\u56fe\u4f1a\u4f7f\u7528\u5b83\u6765\u751f\u6210 UI\u3002<\/p>\n<p>One of the problems when discussing MVC is the vague and ambiguous terms that it uses, such as controller and model. Model in particular is such an overloaded term that it\u2019s often difficult to be sure exactly what it refers to; is it an object, a collection of objects, or an abstract concept? Even ASP.NET Core uses the word model to describe several related but different components, as you\u2019ll see later in this chapter.<\/p>\n<p>\u8ba8\u8bba MVC \u65f6\u7684\u95ee\u9898\u4e4b\u4e00\u662f\u5b83\u4f7f\u7528\u7684\u672f\u8bed\u6a21\u7cca\u4e0d\u6e05\uff0c\u4f8b\u5982 controller \u548c model\u3002\u7279\u522b\u662f Model \u662f\u4e00\u4e2a\u8d85\u8f7d\u7684\u672f\u8bed\uff0c\u4ee5\u81f3\u4e8e\u901a\u5e38\u5f88\u96be\u786e\u5b9a\u5b83\u5230\u5e95\u6307\u7684\u662f\u4ec0\u4e48;\u5b83\u662f\u4e00\u4e2a\u5bf9\u8c61\u3001\u5bf9\u8c61\u7684\u96c6\u5408\u8fd8\u662f\u4e00\u4e2a\u62bd\u8c61\u6982\u5ff5\uff1fEven ASP.NET Core \u4e5f\u4f7f\u7528\u5355\u8bcd model \u6765\u63cf\u8ff0\u51e0\u4e2a\u76f8\u5173\u4f46\u4e0d\u540c\u7684\u7ec4\u4ef6\uff0c\u60a8\u5c06\u5728\u672c\u7ae0\u540e\u9762\u770b\u5230\u3002<\/p>\n<h3>13.4.1 Directing a request to a Razor Page and building a binding model<\/h3>\n<h3>13.4.1 \u5c06\u8bf7\u6c42\u5b9a\u5411\u5230 Razor \u9875\u9762\u5e76\u6784\u5efa\u7ed1\u5b9a\u6a21\u578b<\/h3>\n<p>The first step when your app receives a request is routing the request to an appropriate Razor Page handler in the routing middleware. Let\u2019s think again about the category to-do list page in listing 13.5. On that page, you\u2019re displaying a list of items that have a given category label. If you\u2019re looking at the list of items with a category of Simple, you\u2019d make a request to the \/category\/Simple path.<\/p>\n<p>\u5e94\u7528\u6536\u5230\u8bf7\u6c42\u65f6\u7684\u7b2c\u4e00\u6b65\u662f\u5c06\u8bf7\u6c42\u8def\u7531\u5230\u8def\u7531\u4e2d\u95f4\u4ef6\u4e2d\u7684\u76f8\u5e94 Razor Page \u5904\u7406\u7a0b\u5e8f\u3002\u8ba9\u6211\u4eec\u518d\u8003\u8651\u4e00\u4e0b\u6e05\u5355 13.5 \u4e2d\u7684\u7c7b\u522b to- do \u5217\u8868\u9875\u9762\u3002\u5728\u8be5\u9875\u9762\u4e0a\uff0c\u5c06\u663e\u793a\u5177\u6709\u7ed9\u5b9a\u7c7b\u522b\u6807\u7b7e\u7684\u9879\u76ee\u5217\u8868\u3002\u5982\u679c\u60a8\u6b63\u5728\u67e5\u770b\u7c7b\u522b\u4e3a Simple \u7684\u9879\u76ee\u5217\u8868\uff0c\u5219\u9700\u8981\u5411 \/category\/Simple \u8def\u5f84\u53d1\u51fa\u8bf7\u6c42\u3002<\/p>\n<p>Routing maps a request URL, \/category\/Simple, against the route patterns registered with your application. You\u2019ve seen how this process works for minimal APIs, and it\u2019s the same for Razor Pages; each route template corresponds to a Razor Page endpoint. You\u2019ll learn more about routing with Razor Pages in chapter 14.<\/p>\n<p>\u8def\u7531\u5c06\u8bf7\u6c42 URL \/category\/Simple \u6620\u5c04\u5230\u5e94\u7528\u7a0b\u5e8f\u4e2d\u6ce8\u518c\u7684\u8def\u7531\u6a21\u5f0f\u3002\u60a8\u5df2\u7ecf\u4e86\u89e3\u4e86\u6b64\u8fc7\u7a0b\u5982\u4f55\u9002\u7528\u4e8e\u6700\u5c0f API\uff0c\u5bf9\u4e8e Razor Pages \u4e5f\u662f\u5982\u6b64;\u6bcf\u4e2a\u8def\u7531\u6a21\u677f\u5bf9\u5e94\u4e8e\u4e00\u4e2a Razor Page \u7ec8\u7ed3\u70b9\u3002\u60a8\u5c06\u5728\u7b2c 14 \u7ae0\u4e2d\u4e86\u89e3\u6709\u5173\u4f7f\u7528 Razor Pages \u8fdb\u884c\u8def\u7531\u7684\u66f4\u591a\u4fe1\u606f\u3002<\/p>\n<p><strong>Tip<\/strong> I\u2019m using the term Razor Page to refer to the combination of the Razor view and the PageModel that includes the page handler. Note that that PageModel class is not the model we\u2019re referring to when describing the MVC pattern. It fulfills other roles, as you\u2019ll see later in this section.<br \/>\n<strong>\u63d0\u793a<\/strong> \u6211\u4f7f\u7528\u672f\u8bed Razor Page \u6765\u6307\u4ee3 Razor \u89c6\u56fe\u548c\u5305\u542b\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u7684 PageModel \u7684\u7ec4\u5408\u3002\u8bf7\u6ce8\u610f\uff0cPageModel \u7c7b\u4e0d\u662f\u6211\u4eec\u5728\u63cf\u8ff0 MVC \u6a21\u5f0f\u65f6\u6240\u6307\u7684\u6a21\u578b\u3002\u5b83\u5c65\u884c\u5176\u4ed6\u89d2\u8272\uff0c\u5982\u672c\u8282\u540e\u9762\u6240\u8ff0\u3002<\/p>\n<p>When a page handler is selected in the routing middleware, the request continues down the middleware pipeline until it reaches the endpoint middleware, where the Razor Page executes.<\/p>\n<p>\u5728\u8def\u7531\u4e2d\u95f4\u4ef6\u4e2d\u9009\u62e9\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u540e\uff0c\u8bf7\u6c42\u5c06\u7ee7\u7eed\u6cbf\u4e2d\u95f4\u4ef6\u7ba1\u9053\u5411\u4e0b\uff0c\u76f4\u5230\u5230\u8fbe\u6267\u884c Razor Page \u7684\u7ec8\u7ed3\u70b9\u4e2d\u95f4\u4ef6\u3002<\/p>\n<p>First, the binding model (if applicable) is generated. This model is built from the incoming request, based on the properties of the PageModel marked for binding and the method parameters required by the page handler, as shown in figure 13.9. A binding model is normally one or more standard C# objects and works similarly to the way it works in minimal APIs, as you saw in chapter 6. We\u2019ll look at Razor Page binding models in detail in chapter 16.<\/p>\n<p>\u9996\u5148\uff0c\u751f\u6210\u7ed1\u5b9a\u6a21\u578b\uff08\u5982\u679c\u9002\u7528\uff09\u3002\u6b64\u6a21\u578b\u662f\u6839\u636e\u4f20\u5165\u8bf7\u6c42\u6784\u5efa\u7684\uff0c\u57fa\u4e8e\u6807\u8bb0\u4e3a\u7ed1\u5b9a\u7684 PageModel \u5c5e\u6027\u548c\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u6240\u9700\u7684\u65b9\u6cd5\u53c2\u6570\uff0c\u5982\u56fe 13.9 \u6240\u793a\u3002\u7ed1\u5b9a\u6a21\u578b\u901a\u5e38\u662f\u4e00\u4e2a\u6216\u591a\u4e2a\u6807\u51c6 C# \u5bf9\u8c61\uff0c\u5176\u5de5\u4f5c\u65b9\u5f0f\u7c7b\u4f3c\u4e8e\u5b83\u5728\u6700\u5c0f API \u4e2d\u7684\u5de5\u4f5c\u65b9\u5f0f\uff0c\u5982\u7b2c 6 \u7ae0\u6240\u793a\u3002\u6211\u4eec\u5c06\u5728\u7b2c 16 \u7ae0\u4e2d\u8be6\u7ec6\u4ecb\u7ecd Razor Page \u7ed1\u5b9a\u6a21\u578b\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1309.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 13.9 Routing a request to a Razor Page and building a binding model. A request to the \/category\/Simple URL results in the execution of the CategoryModel.OnGet page handler, passing in a populated binding model, category.<br \/>\n\u56fe 13.9 \u5c06\u8bf7\u6c42\u8def\u7531\u5230 Razor \u9875\u9762\u5e76\u6784\u5efa\u7ed1\u5b9a\u6a21\u578b\u3002\u5bf9\/category\/Simple URL \u4f1a\u5bfc\u81f4\u6267\u884c CategoryModel.OnGet \u9875\u9762\u5904\u7406\u7a0b\u5e8f\uff0c\u5e76\u4f20\u5165\u586b\u5145\u7684\u7ed1\u5b9a\u6a21\u578b category\u3002<\/p>\n<p><strong>Definition<\/strong> A binding model is one or more objects that act as a container for the data provided in a request\u2014data that\u2019s required by a page handler.<br \/>\n<strong>\u5b9a\u4e49<\/strong> \u7ed1\u5b9a\u6a21\u578b\u662f\u4e00\u4e2a\u6216\u591a\u4e2a\u5bf9\u8c61\uff0c\u5b83\u4eec\u5145\u5f53\u8bf7\u6c42\u4e2d\u63d0\u4f9b\u7684\u6570\u636e\u7684\u5bb9\u5668\uff0c\u8fd9\u4e9b\u6570\u636e\u662f\u7531\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u8981\u6c42\u3002<\/p>\n<p>In this case, the binding model is a simple string, category, that\u2019s bound to the &quot;Simple&quot; value. This value is provided in the request URL\u2019s path. A more complex binding model could have been used, with multiple properties populated with values from the route template, the query string, and the request body.<\/p>\n<p>\u5728\u672c\u4f8b\u4e2d\uff0c\u7ed1\u5b9a\u6a21\u578b\u662f\u7ed1\u5b9a\u5230 \u201cSimple\u201d \u503c\u7684\u7b80\u5355\u5b57\u7b26\u4e32 category\u3002\u6b64\u503c\u5728\u8bf7\u6c42 URL \u7684\u8def\u5f84\u4e2d\u63d0\u4f9b\u3002\u53ef\u4ee5\u4f7f\u7528\u66f4\u590d\u6742\u7684\u7ed1\u5b9a\u6a21\u578b\uff0c\u5176\u4e2d\u591a\u4e2a\u5c5e\u6027\u586b\u5145\u4e86\u8def\u7531\u6a21\u677f\u3001\u67e5\u8be2\u5b57\u7b26\u4e32\u548c\u8bf7\u6c42\u6b63\u6587\u4e2d\u7684\u503c\u3002<\/p>\n<p><strong>Note<\/strong> The binding model for Razor Pages is conceptually equivalent to all the parameters you pass in to a minimal API endpoint that are populated from the request.<br \/>\n<strong>\u6ce8\u610f<\/strong> Razor Pages \u7684\u7ed1\u5b9a\u6a21\u578b\u5728\u6982\u5ff5\u4e0a\u7b49\u6548\u4e8e\u60a8\u4f20\u9012\u7ed9\u4ece\u8bf7\u6c42\u586b\u5145\u7684\u6700\u5c0f API \u7aef\u70b9\u7684\u6240\u6709\u53c2\u6570\u3002<\/p>\n<p>The binding model in this case corresponds to the method parameter of the OnGet page handler. An instance of the Razor Page is created using its constructor, and the binding model is passed to the page handler when it executes, so it can be used to decide how to respond. For this example, the page handler uses it to decide which to-do items to display on the page.<\/p>\n<p>\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u7ed1\u5b9a\u6a21\u578b\u5bf9\u5e94\u4e8e OnGet \u9875\u9762\u5904\u7406\u7a0b\u5e8f\u7684 method \u53c2\u6570\u3002Razor Page \u7684\u5b9e\u4f8b\u662f\u4f7f\u7528\u5176\u6784\u9020\u51fd\u6570\u521b\u5efa\u7684\uff0c\u7ed1\u5b9a\u6a21\u578b\u5728\u6267\u884c\u65f6\u4f20\u9012\u7ed9\u9875\u9762\u5904\u7406\u7a0b\u5e8f\uff0c\u56e0\u6b64\u53ef\u7528\u4e8e\u51b3\u5b9a\u5982\u4f55\u54cd\u5e94\u3002\u5728\u6b64\u793a\u4f8b\u4e2d\uff0c\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u4f7f\u7528\u5b83\u6765\u51b3\u5b9a\u8981\u5728\u9875\u9762\u4e0a\u663e\u793a\u54ea\u4e9b\u5f85\u529e\u4e8b\u9879\u3002<\/p>\n<h3>13.4.2 Executing a handler using the application model<\/h3>\n<h3>13.4.2 \u4f7f\u7528\u5e94\u7528\u7a0b\u5e8f\u6a21\u578b\u6267\u884c\u5904\u7406\u7a0b\u5e8f<\/h3>\n<p>The role of the page handler as the controller in the MVC pattern is to coordinate the generation of a response to the request it\u2019s handling. That means it should perform only a limited number of actions. In particular, it should<\/p>\n<p>\u5728 MVC \u6a21\u5f0f\u4e2d\uff0c\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u4f5c\u4e3a\u63a7\u5236\u5668\u7684\u89d2\u8272\u662f\u534f\u8c03\u5bf9\u5b83\u6b63\u5728\u5904\u7406\u7684\u8bf7\u6c42\u7684\u54cd\u5e94\u7684\u751f\u6210\u3002\u8fd9\u610f\u5473\u7740\u5b83\u5e94\u8be5\u53ea\u6267\u884c\u6709\u9650\u6570\u91cf\u7684\u4f5c\u3002\u7279\u522b\u662f\uff0c\u5b83\u5e94\u8be5<\/p>\n<ul>\n<li>\n<p>Validate that the data contained in the binding model is valid for the request.<br \/>\n\u9a8c\u8bc1\u7ed1\u5b9a\u6a21\u578b\u4e2d\u5305\u542b\u7684\u6570\u636e\u662f\u5426\u5bf9\u8bf7\u6c42\u6709\u6548\u3002<\/p>\n<\/li>\n<li>\n<p>Invoke the appropriate actions on the application model using services.<br \/>\n\u4f7f\u7528 services \u5bf9\u5e94\u7528\u7a0b\u5e8f\u6a21\u578b\u8c03\u7528\u9002\u5f53\u7684\u4f5c\u3002<\/p>\n<\/li>\n<li>\n<p>Select an appropriate response to generate based on the response from the application model.<br \/>\n\u6839\u636e\u5e94\u7528\u7a0b\u5e8f\u6a21\u578b\u7684\u54cd\u5e94\u9009\u62e9\u8981\u751f\u6210\u7684\u9002\u5f53\u54cd\u5e94\u3002<\/p>\n<\/li>\n<\/ul>\n<p>Figure 13.10 shows the page handler invoking an appropriate method on the application model. Here, you can see that the application model is a somewhat-abstract concept that encapsulates the remaining non-UI parts of your application. It contains the domain model, several services, and the database interaction.<\/p>\n<p>\u56fe 13.10 \u663e\u793a\u4e86\u5728\u5e94\u7528\u7a0b\u5e8f\u6a21\u578b\u4e0a\u8c03\u7528\u9002\u5f53\u65b9\u6cd5\u7684\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u3002\u5728\u8fd9\u91cc\uff0c\u60a8\u53ef\u4ee5\u770b\u5230\u5e94\u7528\u7a0b\u5e8f\u6a21\u578b\u662f\u4e00\u4e2a\u6709\u70b9\u62bd\u8c61\u7684\u6982\u5ff5\uff0c\u5b83\u5c01\u88c5\u4e86\u5e94\u7528\u7a0b\u5e8f\u7684\u5176\u4f59\u975e UI \u90e8\u5206\u3002\u5b83\u5305\u542b\u57df\u6a21\u578b\u3001\u591a\u4e2a\u670d\u52a1\u548c\u6570\u636e\u5e93\u4ea4\u4e92\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1310.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 13.10 When executed, an action invokes the appropriate methods in the application model.<br \/>\n\u56fe 13.10 \u6267\u884c\u65f6\uff0c\u4f5c\u4f1a\u8c03\u7528\u5e94\u7528\u7a0b\u5e8f\u6a21\u578b\u4e2d\u7684\u76f8\u5e94\u65b9\u6cd5\u3002<\/p>\n<p><strong>Definition<\/strong> The domain model encapsulates complex business logic in a series of classes that don\u2019t depend on any infrastructure and are easy to test.<br \/>\n<strong>\u5b9a\u4e49<\/strong> \u57df\u6a21\u578b\u5c06\u590d\u6742\u7684\u4e1a\u52a1\u903b\u8f91\u5c01\u88c5\u5728\u4e00\u7cfb\u5217\u4e0d\u4f9d\u8d56\u4e8e\u4efb\u4f55\u57fa\u7840\u8bbe\u65bd\u4e14\u6613\u4e8e\u6d4b\u8bd5\u7684\u7c7b\u4e2d\u3002<\/p>\n<p>The page handler typically calls into a single point in the application model. In our example of viewing a to-do list category, the application model might use a variety of services to check whether the current user is allowed to view certain items, to search for items in the given category, to load the details from the database, or to load a picture associated with an item from a file. Assuming that the request is valid, the application model returns the required details to the page handler. Then it\u2019s up to the page handler to choose a response to generate.<\/p>\n<p>\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u901a\u5e38\u8c03\u7528\u5e94\u7528\u7a0b\u5e8f\u6a21\u578b\u4e2d\u7684\u5355\u4e2a\u70b9\u3002\u5728\u67e5\u770b\u5f85\u529e\u4e8b\u9879\u5217\u8868\u7c7b\u522b\u7684\u793a\u4f8b\u4e2d\uff0c\u5e94\u7528\u7a0b\u5e8f\u6a21\u578b\u53ef\u80fd\u4f7f\u7528\u5404\u79cd\u670d\u52a1\u6765\u68c0\u67e5\u662f\u5426\u5141\u8bb8\u5f53\u524d\u7528\u6237\u67e5\u770b\u67d0\u4e9b\u9879\u76ee\u3001\u641c\u7d22\u7ed9\u5b9a\u7c7b\u522b\u4e2d\u7684\u9879\u76ee\u3001\u4ece\u6570\u636e\u5e93\u52a0\u8f7d\u8be6\u7ec6\u4fe1\u606f\u6216\u4ece\u6587\u4ef6\u4e2d\u52a0\u8f7d\u4e0e\u9879\u76ee\u5173\u8054\u7684\u56fe\u7247\u3002\u5047\u8bbe\u8bf7\u6c42\u6709\u6548\uff0c\u5e94\u7528\u7a0b\u5e8f\u6a21\u578b\u4f1a\u5c06\u6240\u9700\u7684\u8be6\u7ec6\u4fe1\u606f\u8fd4\u56de\u7ed9\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u3002\u7136\u540e\uff0c\u7531\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u9009\u62e9\u8981\u751f\u6210\u7684\u54cd\u5e94\u3002<\/p>\n<h3>13.4.3 Building HTML using the view model<\/h3>\n<h3>13.4.3 \u4f7f\u7528\u89c6\u56fe\u6a21\u578b\u6784\u5efa HTML<\/h3>\n<p>When the page handler has called out to the application model that contains the application business logic, it\u2019s time to generate a response. A view model captures the details necessary for the view to generate a response.<\/p>\n<p>\u5f53\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u8c03\u7528\u4e86\u5305\u542b\u5e94\u7528\u7a0b\u5e8f\u4e1a\u52a1\u903b\u8f91\u7684\u5e94\u7528\u7a0b\u5e8f\u6a21\u578b\u65f6\uff0c\u5c31\u53ef\u4ee5\u751f\u6210\u54cd\u5e94\u4e86\u3002\u89c6\u56fe\u6a21\u578b\u6355\u83b7\u89c6\u56fe\u751f\u6210\u54cd\u5e94\u6240\u9700\u7684\u8be6\u7ec6\u4fe1\u606f\u3002<\/p>\n<p><strong>Definition<\/strong> A view model in the MVC pattern is all the data required by the view to render a UI. It\u2019s typically some transformation of the data contained in the application model, plus extra information required to render the page, such as the page\u2019s title.<br \/>\n<strong>\u5b9a\u4e49<\/strong> MVC \u6a21\u5f0f\u4e2d\u7684\u89c6\u56fe\u6a21\u578b\u662f\u89c6\u56fe\u5448\u73b0 UI \u6240\u9700\u7684\u6240\u6709\u6570\u636e\u3002\u5b83\u901a\u5e38\u662f\u5bf9\u5e94\u7528\u7a0b\u5e8f\u6a21\u578b\u4e2d\u5305\u542b\u7684\u6570\u636e\u8fdb\u884c\u4e00\u4e9b\u8f6c\u6362\uff0c\u4ee5\u53ca\u5448\u73b0\u9875\u9762\u6240\u9700\u7684\u989d\u5916\u4fe1\u606f\uff0c\u4f8b\u5982\u9875\u9762\u7684\u6807\u9898\u3002<\/p>\n<p>The term view model is used extensively in ASP.NET Core MVC, where it typically refers to a single object that is passed to the Razor view to render. With Razor Pages, however, the Razor view can access the Razor Page\u2019s page model class directly. Therefore, the Razor Page PageModel typically acts as the view model in Razor Pages, with the data required by the Razor view exposed via properties, as you saw in listing 13.5.<\/p>\n<p>\u672f\u8bed\u201c\u89c6\u56fe\u6a21\u578b\u201d\u5728 ASP.NET Core MVC \u4e2d\u5e7f\u6cdb\u4f7f\u7528\uff0c\u5b83\u901a\u5e38\u662f\u6307\u4f20\u9012\u7ed9 Razor \u89c6\u56fe\u8fdb\u884c\u6e32\u67d3\u7684\u5355\u4e2a\u5bf9\u8c61\u3002\u4f46\u662f\uff0c\u4f7f\u7528 Razor \u9875\u9762\u65f6\uff0cRazor \u89c6\u56fe\u53ef\u4ee5\u76f4\u63a5\u8bbf\u95ee Razor \u9875\u9762\u7684\u9875\u9762\u6a21\u578b\u7c7b\u3002\u56e0\u6b64\uff0cRazor Page PageModel \u901a\u5e38\u5145\u5f53 Razor Pages \u4e2d\u7684\u89c6\u56fe\u6a21\u578b\uff0c\u5176\u4e2d\u901a\u8fc7 properties \u516c\u5f00\u7684 Razor \u89c6\u56fe\u6240\u9700\u7684\u6570\u636e\uff0c\u5982\u6e05\u5355 13.5 \u6240\u793a\u3002<\/p>\n<p><strong>Note<\/strong> Razor Pages use the PageModel class itself as the view model for the Razor view by exposing the required data as properties.<br \/>\n<strong>\u6ce8\u610f<\/strong> Razor Pages \u901a\u8fc7\u5c06\u6240\u9700\u6570\u636e\u4f5c\u4e3a\u5c5e\u6027\u516c\u5f00\uff0c\u4f7f\u7528 PageModel \u7c7b\u672c\u8eab\u4f5c\u4e3a Razor \u89c6\u56fe\u7684\u89c6\u56fe\u6a21\u578b\u3002<\/p>\n<p>The Razor view uses the data exposed in the page model to generate the final HTML response. Finally, this data is sent back through the middleware pipeline and out to the user\u2019s browser, as shown in figure 13.11.<\/p>\n<p>Razor \u89c6\u56fe\u4f7f\u7528\u9875\u9762\u6a21\u578b\u4e2d\u516c\u5f00\u7684\u6570\u636e\u6765\u751f\u6210\u6700\u7ec8\u7684 HTML \u54cd\u5e94\u3002\u6700\u540e\uff0c\u8fd9\u4e9b\u6570\u636e\u901a\u8fc7\u4e2d\u95f4\u4ef6\u7ba1\u9053\u53d1\u9001\u56de\u7528\u6237\u7684\u6d4f\u89c8\u5668\uff0c\u5982\u56fe 13.11 \u6240\u793a\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1311.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 13.11 The page handler builds a view model by setting properties on the PageModel. It\u2019s the view that generates the response.<br \/>\n\u56fe 13.11 \u9875\u9762\u5904\u7406\u7a0b\u5e8f\u901a\u8fc7\u5728 PageModel \u4e0a\u8bbe\u7f6e\u5c5e\u6027\u6765\u6784\u5efa\u89c6\u56fe\u6a21\u578b\u3002\u8fd9\u662f\u751f\u6210\u54cd\u5e94\u3002<\/p>\n<p>It\u2019s important to note that although the page handler selects whether to execute the view and the data to use, it doesn\u2019t control what HTML is generated. The view itself decides what the content of the response will be.<\/p>\n<p>\u8bf7\u52a1\u5fc5\u6ce8\u610f\uff0c\u5c3d\u7ba1\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u9009\u62e9\u662f\u5426\u6267\u884c\u89c6\u56fe\u548c\u8981\u4f7f\u7528\u7684\u6570\u636e\uff0c\u4f46\u5b83\u5e76\u4e0d\u63a7\u5236\u751f\u6210\u7684 HTML\u3002\u89c6\u56fe\u672c\u8eab\u51b3\u5b9a\u54cd\u5e94\u7684\u5185\u5bb9\u3002<\/p>\n<h3>13.4.4 Putting it all together: A complete Razor Page request<\/h3>\n<h3>13.4.4 \u6c47\u603b\uff1a\u5b8c\u6574\u7684 Razor Page \u8bf7\u6c42<\/h3>\n<p>Now that you\u2019ve seen the steps that go into handling a request in ASP.NET Core using Razor Pages, let\u2019s put them together from request to response. Figure 13.12 shows how the steps combine to handle the request to display the list of to-do items for the Simple category. The traditional MVC pattern is still visible in Razor Pages, made up of the page handler (controller), the view, and the application model.<\/p>\n<p>\u73b0\u5728\uff0c\u4f60\u5df2\u7ecf\u4e86\u89e3\u4e86\u4f7f\u7528 Razor Pages \u5728 ASP.NET Core \u4e2d\u5904\u7406\u8bf7\u6c42\u7684\u6b65\u9aa4\uff0c\u8ba9\u6211\u4eec\u5c06\u5b83\u4eec\u4ece\u8bf7\u6c42\u5230\u54cd\u5e94\u653e\u5728\u4e00\u8d77\u3002\u56fe 13.12 \u663e\u793a\u4e86\u5982\u4f55\u7ec4\u5408\u8fd9\u4e9b\u6b65\u9aa4\u6765\u5904\u7406\u663e\u793a Simple \u7c7b\u522b\u7684\u5f85\u529e\u4e8b\u9879\u5217\u8868\u7684\u8bf7\u6c42\u3002\u4f20\u7edf\u7684 MVC \u6a21\u5f0f\u5728 Razor Pages \u4e2d\u4ecd\u7136\u53ef\u89c1\uff0c\u5b83\u7531\u9875\u9762\u5904\u7406\u7a0b\u5e8f\uff08\u63a7\u5236\u5668\uff09\u3001\u89c6\u56fe\u548c\u5e94\u7528\u7a0b\u5e8f\u6a21\u578b\u7ec4\u6210\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1312.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 13.12 A complete Razor Pages request for the list of to-dos in the Simple category<br \/>\n\u56fe 13.12 \u5bf9\u201c\u7b80\u5355\u201d\u7c7b\u522b\u4e2d\u5f85\u529e\u4e8b\u9879\u5217\u8868\u7684\u5b8c\u6574 Razor Pages \u8bf7\u6c42<\/p>\n<p>By now, you may be thinking this whole process seems rather convoluted. So many steps to display some HTML! Why not allow the application model to create the view directly, rather than have to go on a dance back and forth with the page handler method? The key benefit throughout this process is the separation of concerns:<\/p>\n<p>\u5230\u73b0\u5728\u4e3a\u6b62\uff0c\u60a8\u53ef\u80fd\u4f1a\u8ba4\u4e3a\u6574\u4e2a\u8fc7\u7a0b\u4f3c\u4e4e\u76f8\u5f53\u590d\u6742\u3002\u663e\u793a\u4e00\u4e9b HTML \u7684\u6b65\u9aa4\u592a\u591a\u4e86\uff01\u4e3a\u4ec0\u4e48\u4e0d\u5141\u8bb8\u5e94\u7528\u7a0b\u5e8f\u6a21\u578b\u76f4\u63a5\u521b\u5efa\u89c6\u56fe\uff0c\u800c\u4e0d\u5fc5\u4f7f\u7528\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u65b9\u6cd5\u6765\u56de\u8df3\u821e\u5462\uff1f\u6574\u4e2a\u8fc7\u7a0b\u4e2d\u7684\u4e3b\u8981\u597d\u5904\u662f\u5173\u6ce8\u70b9\u5206\u79bb\uff1a<\/p>\n<ul>\n<li>\n<p>The view is responsible only for taking some data and generating HTML.<br \/>\n\u8be5\u89c6\u56fe\u53ea\u8d1f\u8d23\u83b7\u53d6\u4e00\u4e9b\u6570\u636e\u5e76\u751f\u6210 HTML\u3002<\/p>\n<\/li>\n<li>\n<p>The application model is responsible only for executing the required business logic.<br \/>\n\u5e94\u7528\u7a0b\u5e8f\u6a21\u578b\u4ec5\u8d1f\u8d23\u6267\u884c\u6240\u9700\u7684\u4e1a\u52a1\u903b\u8f91\u3002<\/p>\n<\/li>\n<li>\n<p>The page handler (controller) is responsible only for validating the incoming request and selecting which response is required, based on the output of the application model.<br \/>\n\u9875\u9762\u5904\u7406\u7a0b\u5e8f\uff08\u63a7\u5236\u5668\uff09\u4ec5\u8d1f\u8d23\u9a8c\u8bc1\u4f20\u5165\u8bf7\u6c42\u5e76\u6839\u636e\u5e94\u7528\u7a0b\u5e8f\u6a21\u578b\u7684\u8f93\u51fa\u9009\u62e9\u6240\u9700\u7684\u54cd\u5e94\u3002<\/p>\n<\/li>\n<\/ul>\n<p>By having clearly defined boundaries, it\u2019s easier to update and test each of the components without depending on any of the others. If your UI logic changes, you won\u2019t necessarily have to modify any of your business logic classes, so you\u2019re less likely to introduce errors in unexpected places.<br \/>\n\u901a\u8fc7\u660e\u786e\u5b9a\u4e49\u7684\u8fb9\u754c\uff0c\u53ef\u4ee5\u66f4\u8f7b\u677e\u5730\u66f4\u65b0\u548c\u6d4b\u8bd5\u6bcf\u4e2a\u7ec4\u4ef6\uff0c\u800c\u65e0\u9700\u4f9d\u8d56\u4efb\u4f55\u5176\u4ed6\u7ec4\u4ef6\u3002\u5982\u679c\u60a8\u7684 UI \u903b\u8f91\u53d1\u751f\u53d8\u5316\uff0c\u60a8\u4e0d\u4e00\u5b9a\u5fc5\u987b\u4fee\u6539\u4efb\u4f55\u4e1a\u52a1\u903b\u8f91\u7c7b\uff0c\u56e0\u6b64\u60a8\u4e0d\u592a\u53ef\u80fd\u5728\u610f\u60f3\u4e0d\u5230\u7684\u5730\u65b9\u5f15\u5165\u9519\u8bef\u3002<\/p>\n<blockquote>\n<p>The dangers of tight coupling<br \/>\n\u7d27\u5bc6\u8026\u5408\u7684\u5371\u9669<br \/>\nIt\u2019s generally a good idea to reduce coupling between logically separate parts of your application as much as possible. This makes it easier to update your application without causing adverse effects or requiring modifications in seemingly unrelated areas. Applying the MVC pattern is one way to help with this goal.<br \/>\n\u901a\u5e38\uff0c\u6700\u597d\u5c3d\u53ef\u80fd\u51cf\u5c11\u5e94\u7528\u7a0b\u5e8f\u903b\u8f91\u4e0a\u72ec\u7acb\u7684\u90e8\u5206\u4e4b\u95f4\u7684\u8026\u5408\u3002\u8fd9\u6837\u53ef\u4ee5\u66f4\u8f7b\u677e\u5730\u66f4\u65b0\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\uff0c\u800c\u4e0d\u4f1a\u9020\u6210\u4e0d\u5229\u5f71\u54cd\u6216\u9700\u8981\u5728\u770b\u4f3c\u4e0d\u76f8\u5173\u7684\u533a\u57df\u4e2d\u8fdb\u884c\u4fee\u6539\u3002\u5e94\u7528 MVC \u6a21\u5f0f\u662f\u5e2e\u52a9\u5b9e\u73b0\u6b64\u76ee\u6807\u7684\u4e00\u79cd\u65b9\u6cd5\u3002<\/p>\n<\/blockquote>\n<p>As an example of when coupling rears its head, I remember a case a few years ago when I was working on a small web app. In our haste, we hadn\u2019t decoupled our business logic from our HTML generation code properly, but initially there were no obvious problems. The code worked, so we shipped it!<\/p>\n<p>\u4e3e\u4e2a\u4f8b\u5b50\uff0c\u6211\u8bb0\u5f97\u51e0\u5e74\u524d\u6211\u6b63\u5728\u5f00\u53d1\u4e00\u4e2a\u5c0f\u578b Web \u5e94\u7528\u7a0b\u5e8f\u3002\u7531\u4e8e\u5306\u5fd9\uff0c\u6211\u4eec\u6ca1\u6709\u5c06\u4e1a\u52a1\u903b\u8f91\u4e0e HTML \u751f\u6210\u4ee3\u7801\u6b63\u786e\u89e3\u8026\uff0c\u4f46\u6700\u521d\u5e76\u6ca1\u6709\u660e\u663e\u7684\u95ee\u9898\u3002\u4ee3\u7801\u6709\u6548\uff0c\u6240\u4ee5\u6211\u4eec\u53d1\u5e03\u4e86\u5b83\uff01<\/p>\n<p>A few months later, someone new started working on the app and immediately \u201chelped\u201d by renaming an innocuous spelling error in a class in the business layer. Unfortunately, the names of those classes had been used to generate our HTML code, so renaming the class caused the whole website to break in users\u2019 browsers! Suffice it to say that we made a concerted effort to apply the MVC pattern thereafter and ensure that we had a proper separation of concerns.<\/p>\n<p>\u51e0\u4e2a\u6708\u540e\uff0c\u6709\u4eba\u5f00\u59cb\u5f00\u53d1\u8be5\u5e94\u7528\u7a0b\u5e8f\uff0c\u5e76\u7acb\u5373\u201c\u5e2e\u52a9\u201d\u91cd\u547d\u540d\u4e86\u4e1a\u52a1\u5c42\u4e2d\u4e00\u4e2a\u65e0\u5bb3\u7684\u7c7b\u4e2d\u7684\u4e00\u4e2a\u65e0\u5bb3\u7684\u62fc\u5199\u9519\u8bef\u3002\u4e0d\u5e78\u7684\u662f\uff0c\u8fd9\u4e9b\u7c7b\u7684\u540d\u79f0\u5df2\u88ab\u7528\u4e8e\u751f\u6210\u6211\u4eec\u7684 HTML \u4ee3\u7801\uff0c\u56e0\u6b64\u91cd\u547d\u540d\u8be5\u7c7b\u4f1a\u5bfc\u81f4\u6574\u4e2a\u7f51\u7ad9\u5728\u7528\u6237\u7684\u6d4f\u89c8\u5668\u4e2d\u4e2d\u65ad\uff01\u53ef\u4ee5\u8bf4\uff0c\u6211\u4eec\u5728\u6b64\u540e\u9f50\u5fc3\u534f\u529b\u5730\u5e94\u7528 MVC \u6a21\u5f0f\uff0c\u5e76\u786e\u4fdd\u6211\u4eec\u9002\u5f53\u5730\u5206\u79bb\u4e86\u5173\u6ce8\u70b9\u3002<\/p>\n<p>The examples shown in this chapter demonstrate the bulk of the Razor Pages functionality. It has additional features, such as the filter pipeline, which I cover in chapters 21 and 22, and I discuss binding models in greater depth in chapter 16, but the overall behavior of the system is the same.<\/p>\n<p>\u672c\u7ae0\u4e2d\u663e\u793a\u7684\u793a\u4f8b\u6f14\u793a\u4e86 Razor Pages \u7684\u5927\u90e8\u5206\u529f\u80fd\u3002\u5b83\u8fd8\u6709\u5176\u4ed6\u529f\u80fd\uff0c\u4f8b\u5982\u8fc7\u6ee4\u5668\u7ba1\u9053\uff0c\u6211\u5728\u7b2c 21 \u7ae0\u548c\u7b2c 22 \u7ae0\u4e2d\u4ecb\u7ecd\u4e86\u8fd9\u4e00\u70b9\uff0c\u6211\u5728\u7b2c 16 \u7ae0\u4e2d\u66f4\u6df1\u5165\u5730\u8ba8\u8bba\u4e86\u7ed1\u5b9a\u6a21\u578b\uff0c\u4f46\u7cfb\u7edf\u7684\u6574\u4f53\u884c\u4e3a\u662f\u76f8\u540c\u7684\u3002<\/p>\n<p>Similarly, in chapter 19 I look at MVC controllers and explain why I don\u2019t recommend them over Razor Pages for server-rendered applications. By contrast, in chapter 20 I discuss how you can use the MVC design pattern when you\u2019re generating machine-readable responses using Web API controllers. The process is for all intents and purposes identical to the MVC pattern you\u2019ve already seen.<\/p>\n<p>\u540c\u6837\uff0c\u5728\u7b2c 19 \u7ae0\u4e2d\uff0c\u6211\u5c06\u4ecb\u7ecd MVC \u63a7\u5236\u5668\uff0c\u5e76\u89e3\u91ca\u4e3a\u4ec0\u4e48\u5bf9\u4e8e\u670d\u52a1\u5668\u5448\u73b0\u7684\u5e94\u7528\u7a0b\u5e8f\uff0c\u6211\u4e0d\u5efa\u8bae\u4f7f\u7528 MVC \u63a7\u5236\u5668\u800c\u4e0d\u662f Razor Pages\u3002\u76f8\u6bd4\u4e4b\u4e0b\uff0c\u5728\u7b2c 20 \u7ae0\u4e2d\uff0c\u6211\u5c06\u8ba8\u8bba\u5728\u4f7f\u7528 Web API \u63a7\u5236\u5668\u751f\u6210\u673a\u5668\u53ef\u8bfb\u54cd\u5e94\u65f6\u5982\u4f55\u4f7f\u7528 MVC \u8bbe\u8ba1\u6a21\u5f0f\u3002\u8be5\u8fc7\u7a0b\u7684\u6240\u6709\u610f\u56fe\u548c\u76ee\u7684\u90fd\u4e0e\u60a8\u5df2\u7ecf\u770b\u5230\u7684 MVC \u6a21\u5f0f\u76f8\u540c\u3002<\/p>\n<p>I hope that by this point, you\u2019re sold on Razor Pages and their overall design using the MVC pattern. The page handler methods on a Razor Page are invoked in response to a request and select the type of response to generate by returning an IActionResult.<\/p>\n<p>\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\u8c03\u7528 Razor \u9875\u9762\u4e0a\u7684\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u65b9\u6cd5\u4ee5\u54cd\u5e94\u8bf7\u6c42\uff0c\u5e76\u901a\u8fc7\u8fd4\u56de IActionResult \u9009\u62e9\u8981\u751f\u6210\u7684\u54cd\u5e94\u7c7b\u578b\u3002<\/p>\n<p>An aspect I\u2019ve touched on only vaguely is how the RoutingMiddleware decides which Razor Page and handler to invoke for a given request. You don\u2019t want to have a Razor Page for every URL in an app. It would be difficult to have, for example, a different page per product in an e-shop; every product would need its own Razor Page! In chapter 14 you\u2019ll see how to define routes for your Razor Pages, how to add constraints to your routes, and how they deconstruct URLs to match a single handler.<\/p>\n<p>\u6211\u53ea\u662f\u6a21\u7cca\u5730\u8c08\u5230\u4e86\u4e00\u4e2a\u65b9\u9762\uff0c\u5373 RoutingMiddleware \u5982\u4f55\u51b3\u5b9a\u4e3a\u7ed9\u5b9a\u8bf7\u6c42\u8c03\u7528\u54ea\u4e2a Razor Page \u548c\u5904\u7406\u7a0b\u5e8f\u3002\u60a8\u4e0d\u5e0c\u671b\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u6bcf\u4e2a URL \u90fd\u6709\u4e00\u4e2a Razor \u9875\u9762\u3002\u4f8b\u5982\uff0c\u5728\u7535\u5b50\u5546\u5e97\u4e2d\u4e3a\u6bcf\u4e2a\u4ea7\u54c1\u8bbe\u7f6e\u4e0d\u540c\u7684\u9875\u9762\u662f\u5f88\u56f0\u96be\u7684;\u6bcf\u4e2a\u4ea7\u54c1\u90fd\u9700\u8981\u81ea\u5df1\u7684 Razor Page\uff01\u5728\u7b2c 14 \u7ae0\u4e2d\uff0c\u4f60\u5c06\u4e86\u89e3\u5982\u4f55\u4e3a Razor \u9875\u9762\u5b9a\u4e49\u8def\u7531\uff0c\u5982\u4f55\u5411\u8def\u7531\u6dfb\u52a0\u7ea6\u675f\uff0c\u4ee5\u53ca\u5b83\u4eec\u5982\u4f55\u89e3\u6784 URL \u4ee5\u5339\u914d\u5355\u4e2a\u5904\u7406\u7a0b\u5e8f\u3002<\/p>\n<h2>13.5 Summary<\/h2>\n<h2>13.5 \u603b\u7ed3<\/h2>\n<p>Razor Pages are located in the Pages folder of a project and by default are named according to the URL path they handle. Privacy.cshtml, for example, handles the path \/Privacy. This convention makes it easy to quickly add new pages.<br \/>\nRazor Pages \u4f4d\u4e8e\u9879\u76ee\u7684 Pages \u6587\u4ef6\u5939\u4e2d\uff0c\u9ed8\u8ba4\u60c5\u51b5\u4e0b\u6839\u636e\u5b83\u4eec\u5904\u7406\u7684 URL \u8def\u5f84\u8fdb\u884c\u547d\u540d\u3002\u4f8b\u5982\uff0cPrivacy.cshtml \u5904\u7406\u8def\u5f84 \/Privacy\u3002\u6b64\u7ea6\u5b9a\u4f7f\u5feb\u901f\u6dfb\u52a0\u65b0\u9875\u9762\u53d8\u5f97\u5bb9\u6613\u3002<\/p>\n<p>Razor Pages must contain the @page directive as the first line of the .cshtml file. Without this directive, ASP.NET Core won\u2019t recognize it as a Razor Page, and it won\u2019t appear as an endpoint in your app.<br \/>\nRazor Pages \u5fc5\u987b\u5305\u542b @page \u6307\u4ee4\u4f5c\u4e3a .cshtml \u6587\u4ef6\u7684\u7b2c\u4e00\u884c\u3002\u5982\u679c\u6ca1\u6709\u6b64\u6307\u4ee4\uff0cASP.NET Core \u5c06\u65e0\u6cd5\u5c06\u5176\u8bc6\u522b\u4e3a Razor \u9875\u9762\uff0c\u5e76\u4e14\u4e0d\u4f1a\u5728\u5e94\u7528\u4e2d\u663e\u793a\u4e3a\u7ec8\u7ed3\u70b9\u3002<\/p>\n<p>Page models derive from the PageModel base class and contain page handlers. Page handlers are methods named using conventions that indicate the HTTP verb they handle. OnGet, for example, handles the GET verb. Page handlers are equivalent to minimal API endpoint handlers; they run in response to a given request.<br \/>\n\u9875\u9762\u6a21\u578b\u6d3e\u751f\u81ea PageModel \u57fa\u7c7b\uff0c\u5e76\u5305\u542b\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u3002\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u662f\u4f7f\u7528\u7ea6\u5b9a\u547d\u540d\u7684\u65b9\u6cd5\uff0c\u8fd9\u4e9b\u7ea6\u5b9a\u6307\u793a\u5b83\u4eec\u5904\u7406\u7684 HTTP \u52a8\u8bcd\u3002\u4f8b\u5982\uff0cOnGet \u5904\u7406 GET \u52a8\u8bcd\u3002\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u7b49\u540c\u4e8e\u6700\u5c0f API \u7aef\u70b9\u5904\u7406\u7a0b\u5e8f;\u5b83\u4eec\u8fd0\u884c\u4ee5\u54cd\u5e94\u7ed9\u5b9a\u7684\u8bf7\u6c42\u3002<\/p>\n<p>Razor templates can contain standalone C#, standalone HTML, and dynamic HTML generated from C# values. By combining all three, you can build highly dynamic applications.<br \/>\nRazor \u6a21\u677f\u53ef\u4ee5\u5305\u542b\u72ec\u7acb C#\u3001\u72ec\u7acb HTML \u548c\u4ece C# \u503c\u751f\u6210\u7684\u52a8\u6001 HTML\u3002\u901a\u8fc7\u5c06\u8fd9\u4e09\u8005\u7ed3\u5408\u8d77\u6765\uff0c\u60a8\u53ef\u4ee5\u6784\u5efa\u9ad8\u5ea6\u52a8\u6001\u7684\u5e94\u7528\u7a0b\u5e8f\u3002<\/p>\n<p>The MVC design pattern allows for a separation of concerns between the business logic of your application, the data that\u2019s passed around, and the display of data in a response. This reduces coupling between the different layers of your application.<br \/>\nMVC \u8bbe\u8ba1\u6a21\u5f0f\u5141\u8bb8\u5728\u5e94\u7528\u7a0b\u5e8f\u7684\u4e1a\u52a1\u903b\u8f91\u3001\u4f20\u9012\u7684\u6570\u636e\u548c\u54cd\u5e94\u4e2d\u7684\u6570\u636e\u663e\u793a\u4e4b\u95f4\u5206\u79bb\u5173\u6ce8\u70b9\u3002\u8fd9\u51cf\u5c11\u4e86\u5e94\u7528\u7a0b\u5e8f\u4e0d\u540c\u5c42\u4e4b\u95f4\u7684\u8026\u5408\u3002<\/p>\n<p>Razor Pages should inherit from the PageModel base class and contain page handlers. The routing middleware selects a page handler based on the incoming request\u2019s URL, the HTTP verb, and the request\u2019s query string.<br \/>\nRazor Pages \u5e94\u7ee7\u627f\u81ea PageModel \u57fa\u7c7b\u5e76\u5305\u542b\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u3002\u8def\u7531\u4e2d\u95f4\u4ef6\u6839\u636e\u4f20\u5165\u8bf7\u6c42\u7684 URL\u3001HTTP \u52a8\u8bcd\u548c\u8bf7\u6c42\u7684\u67e5\u8be2\u5b57\u7b26\u4e32\u9009\u62e9\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u3002<\/p>\n<p>Page handlers generally should delegate to services to handle the business logic required by a request instead of performing the changes themselves. This ensures a clean separation of concerns that aids testing and improves application structure.<br \/>\n\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u901a\u5e38\u5e94\u59d4\u6258\u7ed9\u670d\u52a1\u6765\u5904\u7406\u8bf7\u6c42\u6240\u9700\u7684\u4e1a\u52a1\u903b\u8f91\uff0c\u800c\u4e0d\u662f\u81ea\u884c\u6267\u884c\u66f4\u6539\u3002\u8fd9\u786e\u4fdd\u4e86\u5173\u6ce8\u70b9\u7684\u6e05\u6670\u5206\u79bb\uff0c\u4ece\u800c\u6709\u52a9\u4e8e\u6d4b\u8bd5\u5e76\u6539\u8fdb\u5e94\u7528\u7a0b\u5e8f\u7ed3\u6784\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Part 3 Generating HTML with Razor Pages and MVC \u7b2c 3 \u90e8\u5206\uff1a\u4f7f\u7528 Razor Pages \u548c MVC \u751f\u6210 HTML In parts 1 and 2 we looked in detail at how to create JSON API applications using minimal APIs. You learned how to configure your app from multiple sources, how to use dependency injection to reduce coupling [&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":[19],"class_list":["post-597","post","type-post","status-publish","format-standard","hentry","category-csharp","tag-asp-net-core-in-action"],"_links":{"self":[{"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts\/597","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=597"}],"version-history":[{"count":0,"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts\/597\/revisions"}],"wp:attachment":[{"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=597"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=597"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=597"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}