{"id":601,"date":"2025-04-05T11:39:07","date_gmt":"2025-04-05T03:39:07","guid":{"rendered":"https:\/\/www.hyy.net\/?p=601"},"modified":"2025-04-05T11:39:07","modified_gmt":"2025-04-05T03:39:07","slug":"asp-net-core-in-action-15-generating-responses-with-page-handlers-in-razor-pages","status":"publish","type":"post","link":"https:\/\/diji.net\/?p=601","title":{"rendered":"ASP.NET Core in Action 15 Generating responses with page handlers in Razor Pages"},"content":{"rendered":"<p>15 Generating responses with page handlers in Razor Pages<br \/>\n15 \u5728 Razor Pages \u4e2d\u4f7f\u7528\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u751f\u6210\u54cd\u5e94<\/p>\n<p>This chapter covers<br \/>\n\u672c\u7ae0\u6db5\u76d6<\/p>\n<p>\u2022  Selecting which page handler in a Razor Page to invoke for a request<br \/>\n\u9009\u62e9\u8981\u4e3a\u8bf7\u6c42\u8c03\u7528\u7684 Razor \u9875\u9762\u4e2d\u7684\u9875\u9762\u5904\u7406\u7a0b\u5e8f<br \/>\n\u2022  Returning an IActionResult from a page handler<br \/>\n\u4ece\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u8fd4\u56de IActionResult<br \/>\n\u2022  Handling status code errors with StatusCodePagesMiddleware<br \/>\n\u4f7f\u7528 StatusCodePagesMiddleware \u5904\u7406\u72b6\u6001\u4ee3\u7801\u9519\u8bef<\/p>\n<p>In chapter 14 you learned how the routing system selects a Razor Page to execute based on its associated route template and the request URL, but each Razor Page can have multiple page handlers. In this chapter you\u2019ll learn all about page handlers, their responsibilities, and how a single Razor Page selects which handler to execute for a request.<br \/>\n\u5728\u7b2c 14 \u7ae0\u4e2d\uff0c\u4f60\u4e86\u89e3\u4e86\u8def\u7531\u7cfb\u7edf\u5982\u4f55\u6839\u636e\u5176\u5173\u8054\u7684\u8def\u7531\u6a21\u677f\u548c\u8bf7\u6c42 URL \u9009\u62e9\u8981\u6267\u884c\u7684 Razor \u9875\u9762\uff0c\u4f46\u6bcf\u4e2a Razor \u9875\u9762\u53ef\u4ee5\u6709\u591a\u4e2a\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u3002\u5728\u672c\u7ae0\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3\u6709\u5173\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u3001\u5176\u804c\u8d23\u4ee5\u53ca\u5355\u4e2a Razor \u9875\u9762\u5982\u4f55\u4e3a\u8bf7\u6c42\u9009\u62e9\u8981\u6267\u884c\u7684\u5904\u7406\u7a0b\u5e8f\u7684\u6240\u6709\u4fe1\u606f\u3002<\/p>\n<p>In section 15.3 we look at some of the ways of retrieving values from an HTTP request in a page handler. Much like minimal APIs, page handlers can accept method arguments that are bound to values in the HTTP request, but Razor Pages can also bind the request to properties on the PageModel.<br \/>\n\u5728 Section 15.3 \u4e2d\uff0c\u6211\u4eec\u4e86\u89e3\u4e86\u5728\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u4e2d\u4ece HTTP \u8bf7\u6c42\u4e2d\u68c0\u7d22\u503c\u7684\u4e00\u4e9b\u65b9\u6cd5\u3002\u4e0e\u6700\u5c0f API \u975e\u5e38\u76f8\u4f3c\uff0c\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u53ef\u4ee5\u63a5\u53d7\u7ed1\u5b9a\u5230 HTTP \u8bf7\u6c42\u4e2d\u503c\u7684\u65b9\u6cd5\u53c2\u6570\uff0c\u4f46 Razor Pages \u4e5f\u53ef\u4ee5\u5c06\u8bf7\u6c42\u7ed1\u5b9a\u5230 PageModel \u4e0a\u7684\u5c5e\u6027\u3002<\/p>\n<p>In section 15.4 you\u2019ll learn how to return IActionResult objects from page handlers. Then you look at some of the common IActionResult types that you\u2019ll return from page handlers for generating HTML and redirect responses.<br \/>\n\u5728\u7b2c 15.4 \u8282\u4e2d\uff0c\u60a8\u5c06\u5b66\u4e60\u5982\u4f55\u4ece\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u8fd4\u56de IActionResult \u5bf9\u8c61\u3002\u7136\u540e\uff0c\u60a8\u67e5\u770b\u5c06\u4ece\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u8fd4\u56de\u7684\u4e00\u4e9b\u5e38\u89c1 IActionResult \u7c7b\u578b\uff0c\u8fd9\u4e9b\u7c7b\u578b\u7528\u4e8e\u751f\u6210 HTML \u548c\u91cd\u5b9a\u5411\u54cd\u5e94\u3002<\/p>\n<p>Finally, in section 15.5 you\u2019ll learn how to use the StatusCodePagesMiddleware to improve the error status code responses in your middleware pipeline. This middleware intercepts error responses such as basic 404 responses and reexecutes the middleware pipeline to generate a pretty HTML response for the error. This gives users a much nicer experience when they encounter an error browsing your Razor Pages app.<br \/>\n\u6700\u540e\uff0c\u5728 15.5 \u8282\u4e2d\uff0c\u60a8\u5c06\u5b66\u4e60\u5982\u4f55\u4f7f\u7528 StatusCodePagesMiddleware \u6765\u6539\u8fdb\u4e2d\u95f4\u4ef6\u7ba1\u9053\u4e2d\u7684\u9519\u8bef\u72b6\u6001\u4ee3\u7801\u54cd\u5e94\u3002\u6b64\u4e2d\u95f4\u4ef6\u4f1a\u62e6\u622a\u9519\u8bef\u54cd\u5e94\uff08\u4f8b\u5982\u57fa\u672c\u7684 404 \u54cd\u5e94\uff09\uff0c\u5e76\u91cd\u65b0\u6267\u884c\u4e2d\u95f4\u4ef6\u7ba1\u9053\u4ee5\u751f\u6210\u9519\u8bef\u7684\u6f02\u4eae HTML \u54cd\u5e94\u3002\u5f53\u7528\u6237\u5728\u6d4f\u89c8 Razor Pages \u5e94\u7528\u7a0b\u5e8f\u65f6\u9047\u5230\u9519\u8bef\u65f6\uff0c\u8fd9\u4e3a\u4ed6\u4eec\u63d0\u4f9b\u4e86\u66f4\u597d\u7684\u4f53\u9a8c\u3002<\/p>\n<p>We\u2019ll start by taking a quick look at the responsibilities of a page handler before we move on to see how the Razor Page infrastructure selects which page handler to execute.<br \/>\n\u9996\u5148\uff0c\u6211\u4eec\u5c06\u5feb\u901f\u4e86\u89e3\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u7684\u804c\u8d23\uff0c\u7136\u540e\u518d\u7ee7\u7eed\u4e86\u89e3 Razor Page \u57fa\u7840\u7ed3\u6784\u5982\u4f55\u9009\u62e9\u8981\u6267\u884c\u7684\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u3002<\/p>\n<h2>15.1 Razor Pages and page handlers<\/h2>\n<p>15.1 Razor \u9875\u9762\u548c\u9875\u9762\u5904\u7406\u7a0b\u5e8f<\/p>\n<p>In chapter 13 I described the Model-View-Controller (MVC) design pattern and showed how it relates to ASP.NET Core. In this design pattern, the \u201ccontroller\u201d receives a request and is the entry point for UI generation. For Razor Pages, the entry point is the page handler that resides in a Razor Page\u2019s PageModel. A page handler is a method that runs in response to a request.<br \/>\n\u5728\u7b2c 13 \u7ae0\u4e2d\uff0c\u6211\u4ecb\u7ecd\u4e86\u6a21\u578b-\u89c6\u56fe-\u63a7\u5236\u5668 \uff08MVC\uff09 \u8bbe\u8ba1\u6a21\u5f0f\uff0c\u5e76\u5c55\u793a\u4e86\u5b83\u4e0e ASP.NET Core \u7684\u5173\u7cfb\u3002\u5728\u6b64\u8bbe\u8ba1\u6a21\u5f0f\u4e2d\uff0c\u201c\u63a7\u5236\u5668\u201d \u63a5\u6536\u8bf7\u6c42\uff0c\u5e76\u4e14\u662f\u751f\u6210 UI \u7684\u5165\u53e3\u70b9\u3002\u5bf9\u4e8e Razor \u9875\u9762\uff0c\u5165\u53e3\u70b9\u662f\u9a7b\u7559\u5728 Razor \u9875\u9762\u7684 PageModel \u4e2d\u7684\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u3002\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u662f\u4e3a\u54cd\u5e94\u8bf7\u6c42\u800c\u8fd0\u884c\u7684\u65b9\u6cd5\u3002<\/p>\n<p>The responsibility of a page handler is generally threefold:<br \/>\n\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u7684\u8d23\u4efb\u901a\u5e38\u6709\u4e09\u4e2a\u65b9\u9762\uff1a<\/p>\n<p>\u2022  Confirm that the incoming request is valid.<br \/>\n\u786e\u8ba4\u4f20\u5165\u8bf7\u6c42\u6709\u6548\u3002<br \/>\n\u2022  Invoke the appropriate business logic corresponding to the incoming request.<br \/>\n\u8c03\u7528\u4e0e\u4f20\u5165\u8bf7\u6c42\u5bf9\u5e94\u7684\u9002\u5f53\u4e1a\u52a1\u903b\u8f91\u3002<br \/>\n\u2022  Choose the appropriate kind of response to return.<br \/>\n\u9009\u62e9\u8981\u8fd4\u56de\u7684\u9002\u5f53\u54cd\u5e94\u7c7b\u578b\u3002<\/p>\n<p>A page handler doesn\u2019t need to perform all these actions, but at the very least it must choose the kind of response to return. Page handlers typically return one of three things:<br \/>\n\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u4e0d\u9700\u8981\u6267\u884c\u6240\u6709\u8fd9\u4e9b\u4f5c\uff0c\u4f46\u81f3\u5c11\u5b83\u5fc5\u987b\u9009\u62e9\u8981\u8fd4\u56de\u7684\u54cd\u5e94\u7c7b\u578b\u3002\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u901a\u5e38\u8fd4\u56de\u4ee5\u4e0b\u4e09\u9879\u5185\u5bb9\u4e4b\u4e00\uff1a<\/p>\n<p>\u2022  A PageResult object\u2014This causes the associated Razor view to generate an HTML response.<br \/>\nPageResult \u5bf9\u8c61 - \u8fd9\u4f1a\u5bfc\u81f4\u5173\u8054\u7684 Razor \u89c6\u56fe\u751f\u6210 HTML \u54cd\u5e94\u3002<br \/>\n\u2022  Nothing (the handler returns void or Task)\u2014This is the same as the previous case, causing the Razor view to generate an HTML response.<br \/>\nNothing \uff08\u5904\u7406\u7a0b\u5e8f\u8fd4\u56de void \u6216 Task\uff09 - \u8fd9\u4e0e\u524d\u4e00\u79cd\u60c5\u51b5\u76f8\u540c\uff0c\u4f1a\u5bfc\u81f4 Razor \u89c6\u56fe\u751f\u6210 HTML \u54cd\u5e94\u3002<br \/>\n\u2022  A RedirectToPageResult\u2014This indicates that the user should be redirected to a different page in your application.<br \/>\nRedirectToPageResult - \u8fd9\u8868\u793a\u5e94\u5c06\u7528\u6237\u91cd\u5b9a\u5411\u5230\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u5176\u4ed6\u9875\u9762\u3002<\/p>\n<p>These are the most common results for Razor Pages, but I describe some additional options in section 15.4.<br \/>\n\u8fd9\u4e9b\u662f Razor Pages \u6700\u5e38\u89c1\u7684\u7ed3\u679c\uff0c\u4f46\u6211\u4f1a\u5728\u7b2c 15.4 \u8282\u4e2d\u4ecb\u7ecd\u4e00\u4e9b\u5176\u4ed6\u9009\u9879\u3002<\/p>\n<p>It\u2019s important to realize that a page handler doesn\u2019t generate a response directly; it selects the type of response and prepares the data for it. For example, returning a PageResult doesn\u2019t generate any HTML at that point; it merely indicates that a view should be rendered. This is in keeping with the MVC design pattern in which it\u2019s the view that generates the response, not the controller.<br \/>\n\u8bf7\u52a1\u5fc5\u8ba4\u8bc6\u5230\uff0c\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u4e0d\u4f1a\u76f4\u63a5\u751f\u6210\u54cd\u5e94;\u5b83\u9009\u62e9\u54cd\u5e94\u7684\u7c7b\u578b\u5e76\u4e3a\u5176\u51c6\u5907\u6570\u636e\u3002\u4f8b\u5982\uff0c\u8fd4\u56de PageResult \u6b64\u65f6\u4e0d\u4f1a\u751f\u6210\u4efb\u4f55 HTML;\u5b83\u4ec5\u6307\u793a\u5e94\u5448\u73b0\u89c6\u56fe\u3002\u8fd9\u4e0e MVC \u8bbe\u8ba1\u6a21\u5f0f\u4e00\u81f4\uff0c\u5728\u8fd9\u79cd\u6a21\u5f0f\u4e2d\uff0c\u751f\u6210\u54cd\u5e94\u7684\u662f\u89c6\u56fe\uff0c\u800c\u4e0d\u662f\u63a7\u5236\u5668\u3002<\/p>\n<p><b>Tip<\/b> The page handler is responsible for choosing what sort of response to send; the view engine in the MVC framework uses the result to generate the response.<br \/>\n\u63d0\u793a:\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u8d1f\u8d23\u9009\u62e9\u8981\u53d1\u9001\u7684\u54cd\u5e94\u7c7b\u578b;MVC \u6846\u67b6\u4e2d\u7684\u89c6\u56fe\u5f15\u64ce\u4f7f\u7528\u7ed3\u679c\u751f\u6210\u54cd\u5e94\u3002<\/p>\n<p>It\u2019s also worth bearing in mind that page handlers generally shouldn\u2019t be performing business logic directly. Instead, they should call appropriate services in the application model to handle requests. If a page handler receives a request to add a product to a user\u2019s cart, it shouldn\u2019t manipulate the database or recalculate cart totals directly, for example. Instead, it should make a call to another class to handle the details. This approach of separating concerns ensures that your code stays testable and maintainable as it grows.<br \/>\n\u8fd8\u503c\u5f97\u8bb0\u4f4f\u7684\u662f\uff0c\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u901a\u5e38\u4e0d\u5e94\u76f4\u63a5\u6267\u884c\u4e1a\u52a1\u903b\u8f91\u3002\u76f8\u53cd\uff0c\u5b83\u4eec\u5e94\u8be5\u8c03\u7528\u5e94\u7528\u7a0b\u5e8f\u6a21\u578b\u4e2d\u7684\u76f8\u5e94\u670d\u52a1\u6765\u5904\u7406\u8bf7\u6c42\u3002\u4f8b\u5982\uff0c\u5982\u679c\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u6536\u5230\u5c06\u4ea7\u54c1\u6dfb\u52a0\u5230\u7528\u6237\u8d2d\u7269\u8f66\u7684\u8bf7\u6c42\uff0c\u5219\u5b83\u4e0d\u5e94\u76f4\u63a5\u4f5c\u6570\u636e\u5e93\u6216\u91cd\u65b0\u8ba1\u7b97\u8d2d\u7269\u8f66\u603b\u6570\u3002\u76f8\u53cd\uff0c\u5b83\u5e94\u8be5\u8c03\u7528\u53e6\u4e00\u4e2a\u7c7b\u6765\u5904\u7406\u7ec6\u8282\u3002\u8fd9\u79cd\u5206\u79bb\u5173\u6ce8\u70b9\u7684\u65b9\u6cd5\u53ef\u786e\u4fdd\u60a8\u7684\u4ee3\u7801\u5728\u589e\u957f\u8fc7\u7a0b\u4e2d\u4fdd\u6301\u53ef\u6d4b\u8bd5\u6027\u548c\u53ef\u7ef4\u62a4\u6027\u3002<\/p>\n<h2>15.2 Selecting a page handler to invoke<\/h2>\n<p>15.2 \u9009\u62e9\u8981\u8c03\u7528\u7684\u9875\u9762\u5904\u7406\u7a0b\u5e8f<\/p>\n<p>In chapter 14 I said routing is about mapping URLs to an endpoint, which for Razor Pages means a page handler. But I\u2019ve mentioned several times that Razor Pages can contain multiple page handlers. In this section you\u2019ll learn how the EndpointMiddleware selects which page handler to invoke when it executes a Razor Page.<br \/>\n\u5728\u7b2c 14 \u7ae0\u4e2d\uff0c\u6211\u8bf4\u8def\u7531\u662f\u5c06 URL \u6620\u5c04\u5230\u7aef\u70b9\uff0c\u5bf9\u4e8e Razor Pages \u6765\u8bf4\uff0c\u7aef\u70b9\u662f\u6307\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u3002\u4f46\u6211\u5df2\u591a\u6b21\u63d0\u5230 Razor Pages \u53ef\u4ee5\u5305\u542b\u591a\u4e2a\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u3002\u5728\u672c\u90e8\u5206\u4e2d\uff0c\u4f60\u5c06\u4e86\u89e3 EndpointMiddleware \u5982\u4f55\u5728\u6267\u884c Razor \u9875\u9762\u65f6\u9009\u62e9\u8981\u8c03\u7528\u7684\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u3002<\/p>\n<p>As you saw in chapter 14, the path of a Razor Page on disk controls the default route template for a Razor Page. For example, the Razor Page at the path Pages\/Products\/Search.cshtml has a default route template of Products\/Search. When a request is received with the URL \/products\/search, the RoutingMiddleware selects this Razor Page, and the request passes through the middleware pipeline to the EndpointMiddleware. At this point, the EndpointMiddleware must choose which page handler to execute, as shown in figure 15.1.<br \/>\n\u5982\u7b2c 14 \u7ae0\u6240\u793a\uff0c\u78c1\u76d8\u4e0a Razor \u9875\u9762\u7684\u8def\u5f84\u63a7\u5236 Razor \u9875\u9762\u7684\u9ed8\u8ba4\u8def\u7531\u6a21\u677f\u3002\u4f8b\u5982\uff0c\u8def\u5f84 Pages\/Products\/Search.cshtml \u5904\u7684 Razor \u9875\u9762\u5177\u6709 Products\/Search \u7684\u9ed8\u8ba4\u8def\u7531\u6a21\u677f\u3002\u5f53\u6536\u5230 URL \u4e3a \/products\/search \u7684\u8bf7\u6c42\u65f6\uff0cRoutingMiddleware \u4f1a\u9009\u62e9\u6b64 Razor \u9875\u9762\uff0c\u5e76\u4e14\u8bf7\u6c42\u901a\u8fc7\u4e2d\u95f4\u4ef6\u7ba1\u9053\u4f20\u9012\u5230 EndpointMiddleware\u3002\u6b64\u65f6\uff0cEndpointMiddleware \u5fc5\u987b\u9009\u62e9\u8981\u6267\u884c\u7684\u9875\u9762\u5904\u7406\u7a0b\u5e8f\uff0c\u5982\u56fe 15.1 \u6240\u793a\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1501.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 15.1 The routing middleware selects the Razor Page to execute based on the incoming request URL. Then the endpoint middleware selects the endpoint to execute based on the HTTP verb of the request and the presence (or lack) of a handler route value.<br \/>\n\u56fe 15.1 \u8def\u7531\u4e2d\u95f4\u4ef6\u6839\u636e\u4f20\u5165\u8bf7\u6c42 URL \u9009\u62e9\u8981\u6267\u884c\u7684 Razor \u9875\u9762\u3002\u7136\u540e\uff0c\u7aef\u70b9\u4e2d\u95f4\u4ef6\u6839\u636e\u8bf7\u6c42\u7684 HTTP \u52a8\u8bcd\u548c\u5904\u7406\u7a0b\u5e8f\u8def\u7531\u503c\u7684\u5b58\u5728\uff08\u6216\u7f3a\u5931\uff09\u9009\u62e9\u8981\u6267\u884c\u7684\u7aef\u70b9\u3002<\/p>\n<p>Consider the Razor Page SearchModel shown in listing 15.1. This Razor Page has three handlers: OnGet, OnPostAsync, and OnPostCustomSearch. The bodies of the handler methods aren\u2019t shown, as we\u2019re interested only in how the EndpointMiddleware chooses which handler to invoke.<br \/>\n\u8bf7\u8003\u8651\u6e05\u5355 15.1 \u4e2d\u6240\u793a\u7684 Razor Page SearchModel\u3002\u6b64 Razor \u9875\u9762\u6709\u4e09\u4e2a\u5904\u7406\u7a0b\u5e8f\uff1aOnGet\u3001OnPostAsync \u548c OnPostCustomSearch\u3002\u5904\u7406\u7a0b\u5e8f\u65b9\u6cd5\u7684\u4e3b\u4f53\u6ca1\u6709\u663e\u793a\uff0c\u56e0\u4e3a\u6211\u4eec\u53ea\u5bf9 EndpointMiddleware \u5982\u4f55\u9009\u62e9\u8981\u8c03\u7528\u7684\u5904\u7406\u7a0b\u5e8f\u611f\u5174\u8da3\u3002<\/p>\n<p>Listing 15.1 Razor Page with multiple page handlers<br \/>\n\u5217\u8868 15.1 \u5177\u6709\u591a\u4e2a\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u7684 Razor Page<\/p>\n<pre><code>public class SearchModel : PageModel\n{\npublic void OnGet() \u2776\n{\n\/\/ Handler implementation\n}\npublic Task OnPostAsync() \u2777\n{\n\/\/ Handler implementation\n}\npublic void OnPostCustomSearch() \u2778\n{\n\/\/ Handler implementation\n}\n}<\/code><\/pre>\n<p>\u2776 Handles GET requests<br \/>\n\u5904\u7406 GET \u8bf7\u6c42<br \/>\n\u2777 Handles POST requests. The async suffix is optional and is ignored for routing purposes.<br \/>\n\u5904\u7406 POST \u8bf7\u6c42\u3002async \u540e\u7f00\u662f\u53ef\u9009\u7684\uff0c\u51fa\u4e8e\u8def\u7531\u76ee\u7684\u800c\u88ab\u5ffd\u7565\u3002<br \/>\n\u2778 Handles POST requests where the handler route value has the value CustomSearch<br \/>\n\u5904\u7406\u5904\u7406\u7a0b\u5e8f\u8def\u7531\u503c\u503c\u4e3a CustomSearch \u7684 POST \u8bf7\u6c42<\/p>\n<p>Razor Pages can contain any number of page handlers, but only one runs in response to a given request. When the EndpointMiddleware executes a selected Razor Page, it selects a page handler to invoke based on two variables:<br \/>\nRazor Pages \u53ef\u4ee5\u5305\u542b\u4efb\u610f\u6570\u91cf\u7684\u9875\u9762\u5904\u7406\u7a0b\u5e8f\uff0c\u4f46\u53ea\u6709\u4e00\u4e2a\u5904\u7406\u7a0b\u5e8f\u8fd0\u884c\u4ee5\u54cd\u5e94\u7ed9\u5b9a\u8bf7\u6c42\u3002\u5f53 EndpointMiddleware \u6267\u884c\u9009\u5b9a\u7684 Razor \u9875\u9762\u65f6\uff0c\u5b83\u4f1a\u6839\u636e\u4e24\u4e2a\u53d8\u91cf\u9009\u62e9\u8981\u8c03\u7528\u7684\u9875\u9762\u5904\u7406\u7a0b\u5e8f\uff1a<\/p>\n<p>\u2022  The HTTP verb used in the request (such as GET, POST, or DELETE)<br \/>\n\u8bf7\u6c42\u4e2d\u4f7f\u7528\u7684 HTTP \u52a8\u8bcd \uff08\u5982 GET\u3001POST \u6216 DELETE\uff09<br \/>\n\u2022  The value of the handler route value<br \/>\n\u5904\u7406\u7a0b\u5e8f\u8def\u7531\u503c\u7684\u503c<\/p>\n<p>The handler route value typically comes from a query string value in the request URL, such as \/Search?handler=CustomSearch. If you don\u2019t like the look of query strings (I don\u2019t!), you can include the {handler} route parameter in your Razor Page\u2019s route template. For the Search page model in listing 15.2, you could update the page\u2019s directive to<br \/>\n\u5904\u7406\u7a0b\u5e8f\u8def\u7531\u503c\u901a\u5e38\u6765\u81ea\u8bf7\u6c42 URL \u4e2d\u7684\u67e5\u8be2\u5b57\u7b26\u4e32\u503c\uff0c\u4f8b\u5982 \/Search\uff1fhandler=CustomSearch\u3002\u5982\u679c\u60a8\u4e0d\u559c\u6b22\u67e5\u8be2\u5b57\u7b26\u4e32\u7684\u5916\u89c2\uff08\u6211\u4e0d\u559c\u6b22\uff09\uff0c\u5219\u53ef\u4ee5\u5728 Razor Page \u7684\u8def\u7531\u6a21\u677f\u4e2d\u5305\u542b {handler} \u8def\u7531\u53c2\u6570\u3002\u5bf9\u4e8e\u6e05\u5355 15.2 \u4e2d\u7684 Search \u9875\u9762\u6a21\u578b\uff0c\u60a8\u53ef\u4ee5\u5c06\u9875\u9762\u7684\u6307\u4ee4\u66f4\u65b0\u4e3a<\/p>\n<pre><code>@page &quot;{handler?}&quot;<\/code><\/pre>\n<p>This would give a complete route template something like &quot;Search\/{handler?}&quot;, which would match URLs such as \/Search and \/Search\/CustomSearch.<br \/>\n\u8fd9\u5c06\u63d0\u4f9b\u4e00\u4e2a\u5b8c\u6574\u7684\u8def\u7531\u6a21\u677f\uff0c\u7c7b\u4f3c\u4e8e \u201cSearch\/{handler\uff1f}\u201d\uff0c\u5b83\u5c06\u5339\u914d \/Search \u548c \/Search\/CustomSearch \u7b49 URL\u3002<\/p>\n<p>The EndpointMiddleware uses the handler route value and the HTTP verb together with a standard naming convention to identify which page handler to execute, as shown in figure 15.2. The handler parameter is optional and is typically provided as part of the request\u2019s query string or as a route parameter, as described earlier. The async suffix is also optional and is often used when the handler uses asynchronous programming constructs such as Task or async\/await.<br \/>\nEndpointMiddleware \u4f7f\u7528\u5904\u7406\u7a0b\u5e8f\u8def\u7531\u503c\u548c HTTP \u52a8\u8bcd\u4ee5\u53ca\u6807\u51c6\u547d\u540d\u7ea6\u5b9a\u6765\u6807\u8bc6\u8981\u6267\u884c\u7684\u9875\u9762\u5904\u7406\u7a0b\u5e8f\uff0c\u5982\u56fe 15.2 \u6240\u793a\u3002handler \u53c2\u6570\u662f\u53ef\u9009\u7684\uff0c\u901a\u5e38\u4f5c\u4e3a\u8bf7\u6c42\u7684\u67e5\u8be2\u5b57\u7b26\u4e32\u7684\u4e00\u90e8\u5206\u6216\u4f5c\u4e3a\u8def\u7531\u53c2\u6570\u63d0\u4f9b\uff0c\u5982\u524d\u6240\u8ff0\u3002async \u540e\u7f00\u4e5f\u662f\u53ef\u9009\u7684\uff0c\u5f53\u5904\u7406\u7a0b\u5e8f\u4f7f\u7528\u5f02\u6b65\u7f16\u7a0b\u6784\u9020\uff08\u5982 Task \u6216 async\/await\uff09\u65f6\uff0c\u901a\u5e38\u4f1a\u4f7f\u7528\u8be5\u540e\u7f00\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1502.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 15.2 Razor Page handlers are matched to a request based on the HTTP verb and the optional handler parameter.<br \/>\n\u56fe 15.2 Razor Page \u5904\u7406\u7a0b\u5e8f\u6839\u636e HTTP \u8c13\u8bcd\u548c\u53ef\u9009\u7684 handler \u53c2\u6570\u4e0e\u8bf7\u6c42\u5339\u914d\u3002<\/p>\n<p><b>NOTE<\/b> The async suffix naming convention is suggested by Microsoft, though it is unpopular with some developers. NServiceBus provides a reasoned argument against it here (along with Microsoft\u2019s advice): <a href=\"http:\/\/mng.bz\/e59P\">http:\/\/mng.bz\/e59P<\/a>.<br \/>\n\u6ce8\u610f:async \u540e\u7f00\u547d\u540d\u7ea6\u5b9a\u7531 Microsoft \u5efa\u8bae\uff0c\u5c3d\u7ba1\u5b83\u5728\u67d0\u4e9b\u5f00\u53d1\u4eba\u5458\u4e2d\u5e76\u4e0d\u53d7\u6b22\u8fce\u3002NServiceBus \u5728\u8fd9\u91cc\u63d0\u4f9b\u4e86\u4e00\u4e2a\u5408\u7406\u7684\u53cd\u5bf9\u5b83\u7684\u7406\u7531\uff08\u4ee5\u53ca Microsoft \u7684\u5efa\u8bae\uff09\uff1a<a href=\"http:\/\/mng.bz\/e59P\">http:\/\/mng.bz\/e59P<\/a>\u3002<\/p>\n<p>Based on this convention, we can now identify what type of request each page handler in listing 15.1 corresponds to:<br \/>\n\u57fa\u4e8e\u8fd9\u4e2a\u7ea6\u5b9a\uff0c\u6211\u4eec\u73b0\u5728\u53ef\u4ee5\u786e\u5b9a\u6e05\u5355 15.1 \u4e2d\u7684\u6bcf\u4e2a\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u5bf9\u5e94\u4e8e\u4ec0\u4e48\u7c7b\u578b\u7684\u8bf7\u6c42\uff1a<\/p>\n<p>\u2022  OnGet\u2014Invoked for GET requests that don\u2019t specify a handler value<br \/>\nOnGet - \u9488\u5bf9\u672a\u6307\u5b9a\u5904\u7406\u7a0b\u5e8f\u503c\u7684GET \u8bf7\u6c42\u8c03\u7528<br \/>\n\u2022  OnPostAsync\u2014Invoked for POST requests that don\u2019t specify a handler value; returns a Task, so it uses the Async suffix, which is ignored for routing purposes<br \/>\nOnPostAsync - \u9488\u5bf9\u672a\u6307\u5b9a\u5904\u7406\u7a0b\u5e8f\u503c\u7684 POST \u8bf7\u6c42\u8c03\u7528;\u8fd4\u56de\u4e00\u4e2a Task\uff0c\u56e0\u6b64\u5b83\u4f7f\u7528 Async \u540e\u7f00\uff0c\u8be5\u540e\u7f00\u5728\u8def\u7531\u65f6\u88ab\u5ffd\u7565<br \/>\n\u2022  OnPostCustomSearch\u2014Invoked for POST requests that specify a handler value of &quot;CustomSearch&quot;<br \/>\nOnPostCustomSearch - \u4e3a\u6307\u5b9a\u5904\u7406\u7a0b\u5e8f\u503c\u201cCustomSearch\u201d\u7684 POST \u8bf7\u6c42\u8c03\u7528<\/p>\n<p>The Razor Page in listing 15.1 specifies three handlers, so it can handle only three verb-handler pairs. But what happens if you get a request that doesn\u2019t match these, such as a request using the DELETE verb, a GET request with a nonblank handler value, or a POST request with an unrecognized handler value?<br \/>\n\u6e05\u5355 15.1 \u4e2d\u7684 Razor Page \u6307\u5b9a\u4e86\u4e09\u4e2a\u5904\u7406\u7a0b\u5e8f\uff0c\u56e0\u6b64\u5b83\u53ea\u80fd\u5904\u7406\u4e09\u4e2a\u8c13\u8bcd\u5904\u7406\u7a0b\u5e8f\u5bf9\u3002\u4f46\u662f\uff0c\u5982\u679c\u60a8\u6536\u5230\u4e0e\u8fd9\u4e9b\u4e0d\u5339\u914d\u7684\u8bf7\u6c42\uff0c\u4f8b\u5982\u4f7f\u7528 DELETE \u52a8\u8bcd\u7684\u8bf7\u6c42\u3001\u5177\u6709\u975e\u7a7a\u5904\u7406\u7a0b\u5e8f\u503c\u7684 GET \u8bf7\u6c42\u6216\u5177\u6709\u65e0\u6cd5\u8bc6\u522b\u7684\u5904\u7406\u7a0b\u5e8f\u503c\u7684 POST \u8bf7\u6c42\uff0c\u4f1a\u53d1\u751f\u4ec0\u4e48\u60c5\u51b5\uff1f<\/p>\n<p>For all these cases, the EndpointMiddleware executes an implicit page handler instead. Implicit page handlers contain no logic; they simply render the Razor view. For example, if you sent a DELETE request to the Razor Page in listing 15.1, the EndpointMiddleware would execute an implicit handler. The implicit page handler is equivalent to the following handler code:<br \/>\n\u5bf9\u4e8e\u6240\u6709\u8fd9\u4e9b\u60c5\u51b5\uff0cEndpointMiddleware \u90fd\u4f1a\u6267\u884c\u9690\u5f0f\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u3002\u9690\u5f0f\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u4e0d\u5305\u542b\u4efb\u4f55\u903b\u8f91;\u5b83\u4eec\u53ea\u5448\u73b0 Razor \u89c6\u56fe\u3002\u4f8b\u5982\uff0c\u5982\u679c\u5411\u6e05\u5355 15.1 \u4e2d\u7684 Razor \u9875\u9762\u53d1\u9001\u4e86 DELETE \u8bf7\u6c42\uff0c\u5219 EndpointMiddleware \u5c06\u6267\u884c\u9690\u5f0f\u5904\u7406\u7a0b\u5e8f\u3002\u9690\u5f0f\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u7b49\u6548\u4e8e\u4ee5\u4e0b\u5904\u7406\u7a0b\u5e8f\u4ee3\u7801\uff1a<\/p>\n<pre><code>public void OnDelete() { }<\/code><\/pre>\n<p><b>DEFINITION<\/b> If a page handler does not match a request\u2019s HTTP verb and handler value, an implicit page handler is executed that renders the associated Razor view. Implicit page handlers take part in model binding and use page filters but execute no logic.<br \/>\n\u5b9a\u4e49:\u5982\u679c\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u4e0e\u8bf7\u6c42\u7684 HTTP \u8c13\u8bcd\u548c\u5904\u7406\u7a0b\u5e8f\u503c\u4e0d\u5339\u914d\uff0c\u5219\u4f1a\u6267\u884c\u4e00\u4e2a\u9690\u5f0f\u9875\u9762\u5904\u7406\u7a0b\u5e8f\uff0c\u4ee5\u5448\u73b0\u5173\u8054\u7684 Razor \u89c6\u56fe\u3002\u9690\u5f0f\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u53c2\u4e0e\u6a21\u578b\u7ed1\u5b9a\u5e76\u4f7f\u7528\u9875\u9762\u8fc7\u6ee4\u5668\uff0c\u4f46\u4e0d\u6267\u884c\u903b\u8f91\u3002<\/p>\n<p>There\u2019s one exception to the implicit page handler rule: if a request uses the HEAD verb, and there is no corresponding OnHead handler, the EndpointMiddleware executes the OnGet handler instead (if it exists).<br \/>\n\u9690\u5f0f\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u89c4\u5219\u6709\u4e00\u4e2a\u4f8b\u5916\uff1a\u5982\u679c\u8bf7\u6c42\u4f7f\u7528 HEAD \u52a8\u8bcd\uff0c\u5e76\u4e14\u6ca1\u6709\u76f8\u5e94\u7684 OnHead \u5904\u7406\u7a0b\u5e8f\uff0c\u5219 EndpointMiddleware \u5c06\u6539\u4e3a\u6267\u884c OnGet \u5904\u7406\u7a0b\u5e8f\uff08\u5982\u679c\u5b58\u5728\uff09\u3002<\/p>\n<p><b>NOTE<\/b> HEAD requests are typically sent automatically by the browser and don\u2019t return a response body. They\u2019re often used for security purposes, as you\u2019ll see in chapter 28.<br \/>\n\u6ce8\u610f:HEAD \u8bf7\u6c42\u901a\u5e38\u7531\u6d4f\u89c8\u5668\u81ea\u52a8\u53d1\u9001\uff0c\u4e0d\u4f1a\u8fd4\u56de\u54cd\u5e94\u6b63\u6587\u3002\u5b83\u4eec\u901a\u5e38\u7528\u4e8e\u5b89\u5168\u76ee\u7684\uff0c\u5982\u7b2c 28 \u7ae0\u6240\u793a\u3002<\/p>\n<p>Now that you know how a page handler is selected, you can think about how it\u2019s executed.<br \/>\n\u73b0\u5728\uff0c\u60a8\u77e5\u9053\u4e86\u5982\u4f55\u9009\u62e9\u9875\u9762\u5904\u7406\u7a0b\u5e8f\uff0c\u60a8\u53ef\u4ee5\u8003\u8651\u5982\u4f55\u6267\u884c\u5b83\u3002<\/p>\n<h2>15.3 Accepting parameters to page handlers<\/h2>\n<p>15.3 \u63a5\u53d7\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u7684\u53c2\u6570<\/p>\n<p>In chapter 7 you learned about the intricacies of model binding in minimal API endpoint handlers. Like minimal APIs, Razor Page page handlers can use model binding to easily extract values from the request. You\u2019ll learn the details of Razor Page model binding in chapter 16; in this section you\u2019ll learn about the basic mechanics of Razor Page model binding and the basic options available.<br \/>\n\u5728\u7b2c 7 \u7ae0\u4e2d\uff0c\u60a8\u4e86\u89e3\u4e86\u6700\u5c0f API \u7aef\u70b9\u5904\u7406\u7a0b\u5e8f\u4e2d\u6a21\u578b\u7ed1\u5b9a\u7684\u590d\u6742\u6027\u3002\u4e0e\u6700\u5c0f API \u4e00\u6837\uff0cRazor Page \u9875\u9762\u5904\u7406\u7a0b\u5e8f\u53ef\u4ee5\u4f7f\u7528\u6a21\u578b\u7ed1\u5b9a\u8f7b\u677e\u5730\u4ece\u8bf7\u6c42\u4e2d\u63d0\u53d6\u503c\u3002\u60a8\u5c06\u5728\u7b2c 16 \u7ae0\u4e2d\u4e86\u89e3 Razor Page \u6a21\u578b\u7ed1\u5b9a\u7684\u8be6\u7ec6\u4fe1\u606f;\u5728\u672c\u8282\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3 Razor Page \u6a21\u578b\u7ed1\u5b9a\u7684\u57fa\u672c\u673a\u5236\u548c\u53ef\u7528\u7684\u57fa\u672c\u9009\u9879\u3002<\/p>\n<p>When working with Razor Pages, you\u2019ll often want to extract values from an incoming request. If the request is for a search page, the request might contain the search term and the page number in the query string. If the request is POSTing a form to your application, such as a user logging in with their username and password, those values may be encoded in the request body. In other cases, there will be no values, such as when a user requests the home page for your application.<br \/>\n\u4f7f\u7528 Razor Pages \u65f6\uff0c\u901a\u5e38\u9700\u8981\u4ece\u4f20\u5165\u8bf7\u6c42\u4e2d\u63d0\u53d6\u503c\u3002\u5982\u679c\u8bf7\u6c42\u9488\u5bf9\u641c\u7d22\u9875\u9762\uff0c\u5219\u8bf7\u6c42\u53ef\u80fd\u5305\u542b\u67e5\u8be2\u5b57\u7b26\u4e32\u4e2d\u7684\u641c\u7d22\u8bcd\u548c\u9875\u7801\u3002\u5982\u679c\u8bf7\u6c42\u5c06\u8868\u5355 POST \u5230\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\uff0c\u4f8b\u5982\u7528\u6237\u4f7f\u7528\u5176\u7528\u6237\u540d\u548c\u5bc6\u7801\u767b\u5f55\uff0c\u5219\u8fd9\u4e9b\u503c\u53ef\u80fd\u4f1a\u5728\u8bf7\u6c42\u6b63\u6587\u4e2d\u7f16\u7801\u3002\u5728\u5176\u4ed6\u60c5\u51b5\u4e0b\uff0c\u5c06\u6ca1\u6709\u503c\uff0c\u4f8b\u5982\u5f53\u7528\u6237\u8bf7\u6c42\u5e94\u7528\u7a0b\u5e8f\u7684\u4e3b\u9875\u65f6\u3002<\/p>\n<p><b>DEFINITION<\/b> The process of extracting values from a request and converting them to .NET types is called model binding. I discuss model binding for Razor Pages in detail in chapter 16.<br \/>\n\u5b9a\u4e49:\u4ece\u8bf7\u6c42\u4e2d\u63d0\u53d6\u503c\u5e76\u5c06\u5176\u8f6c\u6362\u4e3a .NET \u7c7b\u578b\u7684\u8fc7\u7a0b\u79f0\u4e3a\u6a21\u578b\u7ed1\u5b9a\u3002\u6211\u5728\u7b2c 16 \u7ae0\u4e2d\u8be6\u7ec6\u8ba8\u8bba\u4e86 Razor Pages \u7684\u6a21\u578b\u7ed1\u5b9a\u3002<\/p>\n<p>ASP.NET Core can bind two different targets in Razor Pages:<br \/>\nASP.NET Core \u53ef\u4ee5\u5728 Razor Pages \u4e2d\u7ed1\u5b9a\u4e24\u4e2a\u4e0d\u540c\u7684\u76ee\u6807\uff1a<br \/>\n\u2022  Method arguments\u2014If a page handler has method parameters, the arguments are bound and created from values in the request.<br \/>\n\u65b9\u6cd5\u53c2\u6570 - \u5982\u679c\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u5177\u6709\u65b9\u6cd5\u53c2\u6570\uff0c\u5219\u6839\u636e\u8bf7\u6c42\u4e2d\u7684\u503c\u7ed1\u5b9a\u548c\u521b\u5efa\u53c2\u6570\u3002<br \/>\n\u2022  Properties marked with a [BindProperty] attribute\u2014Any properties on the PageModel marked with this attribute are bound to the request. By default, this attribute does nothing for GET requests.<br \/>\n\u6807\u6709 [BindProperty] \u5c5e\u6027\u7684\u5c5e\u6027 - PageModel \u4e0a\u6807\u6709\u6b64\u5c5e\u6027\u7684\u4efb\u4f55\u5c5e\u6027\u90fd\u5c06\u7ed1\u5b9a\u5230\u8bf7\u6c42\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u6b64\u5c5e\u6027\u5bf9 GET \u8bf7\u6c42\u4e0d\u6267\u884c\u4efb\u4f55\u4f5c\u3002<\/p>\n<p>Model-bound values can be simple types, such as strings and integers, or they can be complex types, as shown in the following listing. If any of the values provided in the request are not bound to a property or page handler argument, the additional values will go unused.<br \/>\n\u6a21\u578b\u7ed1\u5b9a\u503c\u53ef\u4ee5\u662f\u7b80\u5355\u7c7b\u578b\uff0c\u4f8b\u5982\u5b57\u7b26\u4e32\u548c\u6574\u6570\uff0c\u4e5f\u53ef\u4ee5\u662f\u590d\u6742\u7c7b\u578b\uff0c\u5982\u4e0b\u9762\u7684\u6e05\u5355\u6240\u793a\u3002\u5982\u679c\u8bf7\u6c42\u4e2d\u63d0\u4f9b\u7684\u4efb\u4f55\u503c\u672a\u7ed1\u5b9a\u5230 property \u6216 page handler \u53c2\u6570\uff0c\u5219\u5176\u4ed6\u503c\u5c06\u672a\u4f7f\u7528\u3002<\/p>\n<p>Listing 15.2 Example Razor Page handlers<br \/>\n\u5217\u8868 15.2 \u793a\u4f8b Razor Page \u5904\u7406\u7a0b\u5e8f<\/p>\n<pre><code>public class SearchModel : PageModel\n{\nprivate readonly SearchService _searchService; \u2776\npublic SearchModel(SearchService searchService) \u2776\n{ \u2776\n_searchService = searchService; \u2776\n} \u2776\n[BindProperty] \u2777\npublic BindingModel Input { get; set; } \u2777\npublic List&lt;Product&gt; Results { get; set; } \u2778\npublic void OnGet() \u2779\n{ \u2779\n} \u2779\npublic IActionResult OnPost(int max) \u277a\n{\n    if (ModelState.IsValid) \u277b\n{ \u277b\nResults = _searchService.Search(Input.SearchTerm, max); \u277b\nreturn Page(); \u277b\n} \u277b\nreturn RedirectToPage(&quot;.\/Index&quot;); \u277b\n}\n}<\/code><\/pre>\n<p>\u2776 The SearchService is injected from DI for use in page handlers.<br \/>\nSearchService \u4ece DI \u6ce8\u5165\uff0c\u7528\u4e8e\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u3002<br \/>\n\u2777 Properties decorated with the [BindProperty] attribute are model-bound.<br \/>\n\u4f7f\u7528 [BindProperty] \u5c5e\u6027\u4fee\u9970\u7684\u5c5e\u6027\u662f\u6a21\u578b\u7ed1\u5b9a\u7684\u3002<br \/>\n\u2778 Undecorated properties are not model-bound.<br \/>\n\u672a\u4fee\u9970\u7684\u5c5e\u6027\u4e0d\u53d7\u6a21\u578b\u9650\u5236\u3002<br \/>\n\u2779 The page handler doesn\u2019t need to check if the model is valid. Returning void renders the view.<br \/>\n\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u4e0d\u9700\u8981\u68c0\u67e5\u6a21\u578b\u662f\u5426\u6709\u6548\u3002\u8fd4\u56de void \u5c06\u5448\u73b0\u89c6\u56fe\u3002<br \/>\n\u277a The max parameter is model-bound using values in the request.<br \/>\nmax \u53c2\u6570\u4f7f\u7528\u8bf7\u6c42\u4e2d\u7684\u503c\u8fdb\u884c\u6a21\u578b\u7ed1\u5b9a\u3002<br \/>\n\u277b If the request was not valid, the method indicates the user should be redirected to the Index page.<br \/>\n\u5982\u679c\u8bf7\u6c42\u65e0\u6548\uff0c\u8be5\u65b9\u6cd5\u6307\u793a\u5e94\u5c06\u7528\u6237\u91cd\u5b9a\u5411\u5230 Index \u9875\u9762\u3002<\/p>\n<p>In this example, the OnGet handler doesn\u2019t require any parameters, and the method is simple: it returns void, which means the associated Razor view will be rendered. It could also have returned a PageResult; the effect would have been the same. Note that this handler is for HTTP GET requests, so the Input property decorated with [BindProperty] is not bound.<br \/>\n\u5728\u6b64\u793a\u4f8b\u4e2d\uff0cOnGet \u5904\u7406\u7a0b\u5e8f\u4e0d\u9700\u8981\u4efb\u4f55\u53c2\u6570\uff0c\u65b9\u6cd5\u5f88\u7b80\u5355\uff1a\u5b83\u8fd4\u56de void\uff0c\u8fd9\u610f\u5473\u7740\u5c06\u5448\u73b0\u5173\u8054\u7684 Razor \u89c6\u56fe\u3002\u5b83\u8fd8\u53ef\u80fd\u8fd4\u56de PageResult;\u6548\u679c\u662f\u4e00\u6837\u7684\u3002\u8bf7\u6ce8\u610f\uff0c\u6b64\u5904\u7406\u7a0b\u5e8f\u7528\u4e8e HTTP GET \u8bf7\u6c42\uff0c\u56e0\u6b64\u4e0d\u4f1a\u7ed1\u5b9a\u7528 [BindProperty] \u4fee\u9970\u7684 Input \u5c5e\u6027\u3002<\/p>\n<p><b>Tip<\/b> To bind properties for GET requests too, use the SupportsGet property of the attribute, as in [BindProperty(SupportsGet = true)].<br \/>\n\u63d0\u793a:\u82e5\u8981\u540c\u65f6\u7ed1\u5b9a GET \u8bf7\u6c42\u7684\u5c5e\u6027\uff0c\u8bf7\u4f7f\u7528\u8be5\u5c5e\u6027\u7684 SupportsGet \u5c5e\u6027\uff0c\u5982 [BindProperty\uff08SupportsGet = true\uff09] \u4e2d\u6240\u793a\u3002<\/p>\n<p>The OnPost handler, conversely, accepts a parameter max as an argument. In this case it\u2019s a simple type, int, but it could also be a complex object. Additionally, as this handler corresponds to an HTTP POST request, the Input property is also model-bound to the request.<br \/>\n\u76f8\u53cd\uff0cOnPost \u5904\u7406\u7a0b\u5e8f\u63a5\u53d7\u53c2\u6570 max \u4f5c\u4e3a\u53c2\u6570\u3002\u5728\u672c\u4f8b\u4e2d\uff0c\u5b83\u662f\u4e00\u4e2a\u7b80\u5355\u7c7b\u578b int\uff0c\u4f46\u5b83\u4e5f\u53ef\u80fd\u662f\u4e00\u4e2a\u590d\u6742\u5bf9\u8c61\u3002\u6b64\u5916\uff0c\u7531\u4e8e\u6b64\u5904\u7406\u7a0b\u5e8f\u5bf9\u5e94\u4e8e HTTP POST \u8bf7\u6c42\uff0c\u56e0\u6b64 Input \u5c5e\u6027\u4e5f\u4e0e\u8bf7\u6c42\u6a21\u578b\u7ed1\u5b9a\u3002<\/p>\n<p><b>NOTE<\/b> Unlike most .NET classes, you can\u2019t use method overloading to have multiple page handlers on a Razor Page with the same name.<br \/>\n\u6ce8\u610f:\u4e0e\u5927\u591a\u6570 .NET \u7c7b\u4e0d\u540c\uff0c\u4e0d\u80fd\u4f7f\u7528\u65b9\u6cd5\u91cd\u8f7d\u5728 Razor \u9875\u9762\u4e0a\u62e5\u6709\u591a\u4e2a\u540c\u540d\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u3002<\/p>\n<p>When a page handler uses model-bound properties or parameters, it should always check that the provided model is valid using ModelState.IsValid. The ModelState property is exposed as a property on the base PageModel class and can be used to check that all the bound properties and parameters are valid. You\u2019ll see how the process works in chapter 16 when you learn about validation.<br \/>\n\u5f53\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u4f7f\u7528\u6a21\u578b\u7ed1\u5b9a\u5c5e\u6027\u6216\u53c2\u6570\u65f6\uff0c\u5b83\u5e94\u59cb\u7ec8\u4f7f\u7528 ModelState.IsValid \u68c0\u67e5\u63d0\u4f9b\u7684\u6a21\u578b\u662f\u5426\u6709\u6548\u3002ModelState \u5c5e\u6027\u4f5c\u4e3a\u57fa PageModel \u7c7b\u4e0a\u7684\u5c5e\u6027\u516c\u5f00\uff0c\u53ef\u7528\u4e8e\u68c0\u67e5\u6240\u6709\u7ed1\u5b9a\u7684\u5c5e\u6027\u548c\u53c2\u6570\u662f\u5426\u6709\u6548\u3002\u5f53\u60a8\u4e86\u89e3\u9a8c\u8bc1\u65f6\uff0c\u60a8\u5c06\u5728\u7b2c 16 \u7ae0\u4e2d\u770b\u5230\u8be5\u8fc7\u7a0b\u7684\u5de5\u4f5c\u539f\u7406\u3002<\/p>\n<p>Once a page handler establishes that the arguments provided to a page handler method are valid, it can execute the appropriate business logic and handle the request. In the case of the OnPost handler, this involves calling the injected SearchService and setting the result on the Results property. Finally, the handler returns a PageResult by calling the helper method on the PageModel base class:<br \/>\n\u4e00\u65e6\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u786e\u5b9a\u63d0\u4f9b\u7ed9\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u65b9\u6cd5\u7684\u53c2\u6570\u6709\u6548\uff0c\u5b83\u5c31\u53ef\u4ee5\u6267\u884c\u76f8\u5e94\u7684\u4e1a\u52a1\u903b\u8f91\u5e76\u5904\u7406\u8bf7\u6c42\u3002\u5bf9\u4e8e OnPost \u5904\u7406\u7a0b\u5e8f\uff0c\u8fd9\u6d89\u53ca\u8c03\u7528\u6ce8\u5165\u7684 SearchService \u5e76\u5728 Results \u5c5e\u6027\u4e0a\u8bbe\u7f6e\u7ed3\u679c\u3002\u6700\u540e\uff0c\u5904\u7406\u7a0b\u5e8f\u901a\u8fc7\u8c03\u7528 PageModel \u57fa\u7c7b\u4e0a\u7684\u5e2e\u52a9\u7a0b\u5e8f\u65b9\u6cd5\u8fd4\u56de PageResult\uff1a<\/p>\n<pre><code>return Page();<\/code><\/pre>\n<p>If the model isn\u2019t valid, as indicated by ModelState.IsValid, you don\u2019t have any results to display! In this example, the action returns a RedirectToPageResult using the RedirectToPage() helper method. When executed, this result sends a 302 Redirect response to the user, which will cause their browser to navigate to the Index Razor Page.<br \/>\n\u5982\u679c\u6a21\u578b\u65e0\u6548\uff08\u5982 ModelState.IsValid \u6240\u793a\uff09\uff0c\u5219\u6ca1\u6709\u4efb\u4f55\u7ed3\u679c\u53ef\u663e\u793a\uff01\u5728\u6b64\u793a\u4f8b\u4e2d\uff0c\u8be5\u4f5c\u4f7f\u7528 RedirectToPage\uff08\uff09 \u5e2e\u52a9\u7a0b\u5e8f\u65b9\u6cd5\u8fd4\u56de RedirectToPageResult\u3002\u6267\u884c\u65f6\uff0c\u6b64\u7ed3\u679c\u4f1a\u5411\u7528\u6237\u53d1\u9001 302 Redirect \u54cd\u5e94\uff0c\u8fd9\u5c06\u5bfc\u81f4\u5176\u6d4f\u89c8\u5668\u5bfc\u822a\u5230 Index Razor \u9875\u9762\u3002<\/p>\n<p>Note that the OnGet method returns void in the method signature, whereas the OnPost method returns an IActionResult. This is required in the OnPost method to allow the C# to compile (as the Page() and RedirectToPage() helper methods return different types), but it doesn\u2019t change the final behavior of the methods. You could easily have called Page() in the OnGet method and returned an IActionResult, and the behavior would be identical.<br \/>\n\u8bf7\u6ce8\u610f\uff0cOnGet \u65b9\u6cd5\u5728\u65b9\u6cd5\u7b7e\u540d\u4e2d\u8fd4\u56de void\uff0c\u800c OnPost \u65b9\u6cd5\u8fd4\u56de IActionResult\u3002\u8fd9\u5728 OnPost \u65b9\u6cd5\u4e2d\u662f\u5fc5\u9700\u7684\uff0c\u4ee5\u5141\u8bb8 C# \u8fdb\u884c\u7f16\u8bd1\uff08\u56e0\u4e3a Page\uff08\uff09 \u548c RedirectToPage\uff08\uff09 \u5e2e\u52a9\u7a0b\u5e8f\u65b9\u6cd5\u8fd4\u56de\u4e0d\u540c\u7684\u7c7b\u578b\uff09\uff0c\u4f46\u5b83\u4e0d\u4f1a\u66f4\u6539\u65b9\u6cd5\u7684\u6700\u7ec8\u884c\u4e3a\u3002\u60a8\u53ef\u4ee5\u8f7b\u677e\u5730\u5728 OnGet \u65b9\u6cd5\u4e2d\u8c03\u7528 Page\uff08\uff09 \u5e76\u8fd4\u56de IActionResult\uff0c\u5e76\u4e14\u884c\u4e3a\u662f\u76f8\u540c\u7684\u3002<\/p>\n<p><b>Tip<\/b> If you\u2019re returning more than one type of result from a page handler, you\u2019ll need to ensure that your method returns an IActionResult.<br \/>\n\u63d0\u793a:\u5982\u679c\u8981\u4ece\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u8fd4\u56de\u591a\u79cd\u7c7b\u578b\u7684\u7ed3\u679c\uff0c\u5219\u9700\u8981\u786e\u4fdd\u65b9\u6cd5\u8fd4\u56de IActionResult\u3002<\/p>\n<p>In listing 15.2 I used Page() and RedirectToPage() methods to generate the return value. IActionResult instances can be created and returned using the normal new syntax of C#:<br \/>\n\u5728\u6e05\u5355 15.2 \u4e2d\uff0c\u6211\u4f7f\u7528\u4e86 Page\uff08\uff09 \u548c RedirectToPage\uff08\uff09 \u65b9\u6cd5\u6765\u751f\u6210\u8fd4\u56de\u503c\u3002\u53ef\u4ee5\u4f7f\u7528 C# \u7684\u5e38\u89c4\u65b0\u8bed\u6cd5\u521b\u5efa\u548c\u8fd4\u56de IActionResult \u5b9e\u4f8b\uff1a<\/p>\n<pre><code>return new PageResult()<\/code><\/pre>\n<p>However, the Razor Pages PageModel base class also provides several helper methods for generating responses, which are thin wrappers around the new syntax. It\u2019s common to use the Page() method to generate an appropriate PageResult, the RedirectToPage() method to generate a RedirectToPageResult, or the NotFound() method to generate a NotFoundResult.<br \/>\n\u4f46\u662f\uff0cRazor Pages PageModel \u57fa\u7c7b\u8fd8\u63d0\u4f9b\u4e86\u591a\u4e2a\u7528\u4e8e\u751f\u6210\u54cd\u5e94\u7684\u5e2e\u52a9\u7a0b\u5e8f\u65b9\u6cd5\uff0c\u8fd9\u4e9b\u65b9\u6cd5\u662f\u65b0\u8bed\u6cd5\u7684\u7cbe\u7b80\u5305\u88c5\u5668\u3002\u901a\u5e38\u4f7f\u7528 Page\uff08\uff09 \u65b9\u6cd5\u751f\u6210\u76f8\u5e94\u7684 PageResult\uff0c\u4f7f\u7528 RedirectToPage\uff08\uff09 \u65b9\u6cd5\u751f\u6210 RedirectToPageResult\uff0c\u6216\u4f7f\u7528 NotFound\uff08\uff09 \u65b9\u6cd5\u751f\u6210 NotFoundResult\u3002<\/p>\n<p><b>Tip<\/b> Most IActionResult implementations have a helper method on the base PageModel class. They\u2019re typically named Type, and the result generated is called TypeResult. For example, the StatusCode() method returns a StatusCodeResult instance.<br \/>\n\u63d0\u793a:\u5927\u591a\u6570 IActionResult \u5b9e\u73b0\u5728\u57fa PageModel \u7c7b\u4e0a\u90fd\u6709\u4e00\u4e2a\u5e2e\u52a9\u7a0b\u5e8f\u65b9\u6cd5\u3002\u5b83\u4eec\u901a\u5e38\u547d\u540d\u4e3a Type\uff0c\u751f\u6210\u7684\u7ed3\u679c\u79f0\u4e3a TypeResult\u3002\u4f8b\u5982\uff0cStatusCode\uff08\uff09 \u65b9\u6cd5\u8fd4\u56de StatusCodeResult \u5b9e\u4f8b\u3002<\/p>\n<p>In the next section we\u2019ll look in more depth at some of the common IActionResult types.<br \/>\n\u5728\u4e0b\u4e00\u8282\u4e2d\uff0c\u6211\u4eec\u5c06\u66f4\u6df1\u5165\u5730\u4e86\u89e3\u4e00\u4e9b\u5e38\u89c1\u7684 IActionResult \u7c7b\u578b\u3002<\/p>\n<h2>15.4 Returning IActionResult responses<\/h2>\n<p>15.4 \u8fd4\u56de IActionResult \u54cd\u5e94<\/p>\n<p>In the previous section, I emphasized that page handlers decide what type of response to return, but they don\u2019t generate the response themselves. It\u2019s the IActionResult returned by a page handler that, when executed by the Razor Pages infrastructure using the view engine, generates the response.<br \/>\n\u5728\u4e0a\u4e00\u8282\u4e2d\uff0c\u6211\u5f3a\u8c03\u4e86\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u51b3\u5b9a\u8fd4\u56de\u54ea\u79cd\u7c7b\u578b\u7684\u54cd\u5e94\uff0c\u4f46\u5b83\u4eec\u81ea\u5df1\u4e0d\u4f1a\u751f\u6210\u54cd\u5e94\u3002\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u8fd4\u56de\u7684 IActionResult \u5728\u7531\u4f7f\u7528\u89c6\u56fe\u5f15\u64ce\u7684 Razor Pages \u57fa\u7840\u7ed3\u6784\u6267\u884c\u65f6\uff0c\u4f1a\u751f\u6210\u54cd\u5e94\u3002<\/p>\n<p><b>Warning<\/b> Note that the interface type is IActionResult not IResult. IResult is used in minimal APIs and should generally be avoided in Razor Pages (and MVC controllers). In .NET 7, IResult types returned from Razor Pages or MVC controllers execute as expected, but they don\u2019t have all the same features as IActionResult, so you should favor IActionResult in Razor Pages.<br \/>\n\u8b66\u544a:\u8bf7\u6ce8\u610f\uff0c\u63a5\u53e3\u7c7b\u578b\u662f IActionResult \u800c\u4e0d\u662f IResult\u3002IResult \u7528\u4e8e\u6700\u5c0f\u7684 API\uff0c\u901a\u5e38\u5e94\u907f\u514d\u5728 Razor Pages\uff08\u548c MVC \u63a7\u5236\u5668\uff09\u4e2d\u4f7f\u7528\u3002\u5728 .NET 7 \u4e2d\uff0c\u4ece Razor Pages \u6216 MVC \u63a7\u5236\u5668\u8fd4\u56de\u7684 IResult \u7c7b\u578b\u6309\u9884\u671f\u6267\u884c\uff0c\u4f46\u5b83\u4eec\u4e0d\u5177\u6709\u4e0e IActionResult \u76f8\u540c\u7684\u6240\u6709\u529f\u80fd\uff0c\u56e0\u6b64\u4f60\u5e94\u8be5\u5728 Razor Pages \u4e2d\u9996\u9009 IActionResult\u3002<\/p>\n<p>IActionResults are a key part of the MVC design pattern. They separate the decision of what sort of response to send from the generation of the response. This allows you to test your action method logic to confirm that the right sort of response is sent for a given input. You can then separately test that a given IActionResult generates the expected HTML, for example.<br \/>\nIActionResults \u662f MVC \u8bbe\u8ba1\u6a21\u5f0f\u7684\u5173\u952e\u90e8\u5206\u3002\u5b83\u4eec\u5c06\u53d1\u9001\u54ea\u79cd\u54cd\u5e94\u7684\u51b3\u5b9a\u4e0e\u54cd\u5e94\u7684\u751f\u6210\u5206\u5f00\u3002\u8fd9\u5141\u8bb8\u60a8\u6d4b\u8bd5\u4f5c\u65b9\u6cd5\u903b\u8f91\uff0c\u4ee5\u786e\u8ba4\u4e3a\u7ed9\u5b9a\u8f93\u5165\u53d1\u9001\u4e86\u6b63\u786e\u7c7b\u578b\u7684\u54cd\u5e94\u3002\u4f8b\u5982\uff0c\u60a8\u53ef\u4ee5\u5355\u72ec\u6d4b\u8bd5\u7ed9\u5b9a\u7684 IActionResult \u662f\u5426\u751f\u6210\u4e86\u9884\u671f\u7684 HTML\u3002<\/p>\n<p>ASP.NET Core has many types of IActionResult, such as<br \/>\nASP.NET Core \u5177\u6709\u591a\u79cd\u7c7b\u578b\u7684 IActionResult\uff0c\u4f8b\u5982<\/p>\n<p>\u2022  PageResult\u2014Generates an HTML view for the associated page in Razor Pages and returns a 200 HTTP response.<br \/>\nPageResult - \u5728 Razor Pages \u4e2d\u4e3a\u5173\u8054\u9875\u9762\u751f\u6210 HTML \u89c6\u56fe\uff0c\u5e76\u8fd4\u56de 200 HTTP \u54cd\u5e94\u3002<br \/>\n\u2022  ViewResult\u2014Generates an HTML view for a given Razor view when using MVC controllers and returns a 200 HTTP response.<br \/>\nViewResult - \u4f7f\u7528 MVC \u63a7\u5236\u5668\u65f6\uff0c\u4e3a\u7ed9\u5b9a Razor \u89c6\u56fe\u751f\u6210 HTML \u89c6\u56fe\uff0c\u5e76\u8fd4\u56de 200 HTTP \u54cd\u5e94\u3002<br \/>\n\u2022  PartialViewResult\u2014Renders part of an HTML page using a given Razor view and returns a 200 HTTP result; typically used with MVC controllers and AJAX requests.<br \/>\nPartialViewResult - \u4f7f\u7528\u7ed9\u5b9a\u7684 Razor \u89c6\u56fe\u5448\u73b0 HTML \u9875\u9762\u7684\u4e00\u90e8\u5206\uff0c\u5e76\u8fd4\u56de 200 HTTP \u7ed3\u679c;\u901a\u5e38\u7528\u4e8e MVC \u63a7\u5236\u5668\u548c AJAX \u8bf7\u6c42\u3002<br \/>\n\u2022  RedirectToPageResult\u2014Sends a 302 HTTP redirect response to automatically send a user to another page.<br \/>\nRedirectToPageResult - \u53d1\u9001 302 HTTP \u91cd\u5b9a\u5411\u54cd\u5e94\u4ee5\u81ea\u52a8\u5c06\u7528\u6237\u53d1\u9001\u5230\u5176\u4ed6\u9875\u9762\u3002<br \/>\n\u2022  RedirectResult\u2014Sends a 302 HTTP redirect response to automatically send a user to a specified URL (doesn\u2019t have to be a Razor Page).<br \/>\nRedirectResult - \u53d1\u9001 302 HTTP \u91cd\u5b9a\u5411\u54cd\u5e94\u4ee5\u81ea\u52a8\u5c06\u7528\u6237\u53d1\u9001\u5230\u6307\u5b9a\u7684 URL \uff08\u4e0d\u5fc5\u662f Razor \u9875\u9762\uff09\u3002<br \/>\n\u2022  FileResult\u2014Returns a file as the response. This is a base class with several derived types:<br \/>\nFileResult - \u8fd4\u56de\u6587\u4ef6\u4f5c\u4e3a\u54cd\u5e94\u3002\u8fd9\u662f\u4e00\u4e2a\u5177\u6709\u591a\u4e2a\u6d3e\u751f\u7c7b\u578b\u7684\u57fa\u7c7b\uff1a<br \/>\n\u2022  \u2022  FileContentResult\u2014Returns a byte[] as a file response to the browser<br \/>\nFileContentResult - \u8fd4\u56de byte[] \u4f5c\u4e3a\u5bf9\u6d4f\u89c8\u5668\u7684\u6587\u4ef6\u54cd\u5e94<br \/>\n\u2022  \u2022  FileStreamResult\u2014Returns the contents of a Stream as a file response to the browser<br \/>\nFileStreamResult - \u5c06 Stream \u7684\u5185\u5bb9\u4f5c\u4e3a\u6587\u4ef6\u54cd\u5e94\u8fd4\u56de\u7ed9\u6d4f\u89c8\u5668<br \/>\n\u2022  \u2022  PhysicalFileResult\u2014Returns the contents of a file on disk as a file response to the browser<br \/>\nPhysicalFileResult - \u5c06\u78c1\u76d8\u4e0a\u6587\u4ef6\u7684\u5185\u5bb9\u4f5c\u4e3a\u6587\u4ef6\u54cd\u5e94\u8fd4\u56de\u7ed9\u6d4f\u89c8\u5668<br \/>\n\u2022  ContentResult\u2014Returns a provided string as the response.<br \/>\nContentResult - \u8fd4\u56de\u63d0\u4f9b\u7684\u5b57\u7b26\u4e32\u4f5c\u4e3a\u54cd\u5e94\u3002<br \/>\n\u2022  StatusCodeResult\u2014Sends a raw HTTP status code as the response, optionally with associated response body content.<br \/>\nStatusCodeResult - \u53d1\u9001\u539f\u59cb HTTP \u72b6\u6001\u4ee3\u7801\u4f5c\u4e3a\u54cd\u5e94\uff0c\u53ef\u9009\u62e9\u53d1\u9001\u5173\u8054\u7684\u54cd\u5e94\u6b63\u6587\u5185\u5bb9\u3002<br \/>\n\u2022  NotFoundResult\u2014Sends a raw 404 HTTP status code as the response.<br \/>\nNotFoundResult - \u53d1\u9001\u539f\u59cb 404 HTTP \u72b6\u6001\u4ee3\u7801\u4f5c\u4e3a\u54cd\u5e94\u3002<\/p>\n<p>Each of these, when executed by Razor Pages, generates a response to send back through the middleware pipeline and out to the user.<br \/>\n\u5f53 Razor Pages \u6267\u884c\u65f6\uff0c\u6bcf\u4e2a\u4f5c\u90fd\u4f1a\u751f\u6210\u4e00\u4e2a\u54cd\u5e94\uff0c\u4ee5\u901a\u8fc7\u4e2d\u95f4\u4ef6\u7ba1\u9053\u53d1\u9001\u56de\u7ed9\u7528\u6237\u3002<\/p>\n<p><b>Tip<\/b> When you\u2019re using Razor Pages, you generally won\u2019t use some of these action results, such as ContentResult and StatusCodeResult. It\u2019s good to be aware of them, though, as you will likely use them if you are building Web APIs with MVC controllers, as you\u2019ll see in chapter 20.<br \/>\n\u63d0\u793a:\u4f7f\u7528 Razor Pages \u65f6\uff0c\u901a\u5e38\u4e0d\u4f1a\u4f7f\u7528\u5176\u4e2d\u4e00\u4e9b\u4f5c\u7ed3\u679c\uff0c\u4f8b\u5982 ContentResult \u548c StatusCodeResult\u3002\u4e0d\u8fc7\uff0c\u4e86\u89e3\u5b83\u4eec\u662f\u4ef6\u597d\u4e8b\uff0c\u56e0\u4e3a\u5982\u679c\u4f60\u6b63\u5728\u4f7f\u7528 MVC \u63a7\u5236\u5668\u6784\u5efa Web API\uff0c\u4f60\u53ef\u80fd\u4f1a\u4f7f\u7528\u5b83\u4eec\uff0c\u5982\u7b2c 20 \u7ae0\u6240\u793a\u3002<\/p>\n<p>In sections 15.4.1\u201315.4.3 I give a brief description of the most common IActionResult types that you\u2019ll use with Razor Pages.<br \/>\n\u5728\u7b2c 15.4.1\u201315.4.3 \u8282\u4e2d\uff0c\u6211\u7b80\u8981\u4ecb\u7ecd\u4e86\u60a8\u5c06\u7528\u4e8e Razor Pages \u7684\u6700\u5e38\u89c1 IActionResult \u7c7b\u578b\u3002<\/p>\n<h3>15.4.1 PageResult and RedirectToPageResult<\/h3>\n<p>15.4.1 PageResult \u548c RedirectToPageResult<\/p>\n<p>When you\u2019re building a traditional web application with Razor Pages, usually you\u2019ll be using PageResult, which generates an HTML response from the Razor Page\u2019s associated Razor view. We\u2019ll look at how this happens in detail in chapter 17.<br \/>\n\u4f7f\u7528 Razor Pages \u6784\u5efa\u4f20\u7edf Web \u5e94\u7528\u7a0b\u5e8f\u65f6\uff0c\u901a\u5e38\u4f1a\u4f7f\u7528 PageResult\uff0c\u5b83\u4f1a\u4ece Razor Page \u7684\u5173\u8054 Razor \u89c6\u56fe\u751f\u6210 HTML \u54cd\u5e94\u3002\u6211\u4eec\u5c06\u5728\u7b2c 17 \u7ae0\u8be6\u7ec6\u770b\u770b\u8fd9\u662f\u5982\u4f55\u53d1\u751f\u7684\u3002<\/p>\n<p>You\u2019ll also commonly use the various redirect-based results to send the user to a new web page. For example, when you place an order on an e-commerce website, you typically navigate through multiple pages, as shown in figure 15.3. The web application sends HTTP redirects whenever it needs you to move to a different page, such as when a user submits a form. Your browser automatically follows the redirect requests, creating a seamless flow through the checkout process.<br \/>\n\u60a8\u901a\u5e38\u8fd8\u4f1a\u4f7f\u7528\u5404\u79cd\u57fa\u4e8e\u91cd\u5b9a\u5411\u7684\u7ed3\u679c\u5c06\u7528\u6237\u53d1\u9001\u5230\u65b0\u7f51\u9875\u3002\u4f8b\u5982\uff0c\u5f53\u60a8\u5728\u7535\u5b50\u5546\u52a1\u7f51\u7ad9\u4e0a\u4e0b\u8ba2\u5355\u65f6\uff0c\u901a\u5e38\u4f1a\u6d4f\u89c8\u591a\u4e2a\u9875\u9762\uff0c\u5982\u56fe 15.3 \u6240\u793a\u3002\u6bcf\u5f53 Web \u5e94\u7528\u7a0b\u5e8f\u9700\u8981\u60a8\u79fb\u52a8\u5230\u5176\u4ed6\u9875\u9762\u65f6\uff08\u4f8b\u5982\uff0c\u5f53\u7528\u6237\u63d0\u4ea4\u8868\u5355\u65f6\uff09\uff0c\u5b83\u90fd\u4f1a\u53d1\u9001 HTTP \u91cd\u5b9a\u5411\u3002\u60a8\u7684\u6d4f\u89c8\u5668\u4f1a\u81ea\u52a8\u9075\u5faa\u91cd\u5b9a\u5411\u8bf7\u6c42\uff0c\u4ece\u800c\u5728\u7ed3\u5e10\u8fc7\u7a0b\u4e2d\u521b\u5efa\u65e0\u7f1d\u6d41\u7a0b\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1503.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 15.3 A typical POST, REDIRECT, GET flow through a website. A user sends their shopping basket to a checkout page, which validates its contents and redirects to a payment page without the user\u2019s having to change the URL manually.<br \/>\n\u56fe 15.3 \u5178\u578b\u7684 POST\u3001REDIRECT\u3001GET \u6d41\u7ecf\u7f51\u7ad9\u3002\u7528\u6237\u5c06\u4ed6\u4eec\u7684\u8d2d\u7269\u7bee\u53d1\u9001\u5230\u7ed3\u5e10\u9875\u9762\uff0c\u8be5\u9875\u9762\u4f1a\u9a8c\u8bc1\u5176\u5185\u5bb9\u5e76\u91cd\u5b9a\u5411\u5230\u652f\u4ed8\u9875\u9762\uff0c\u800c\u65e0\u9700\u7528\u6237\u624b\u52a8\u66f4\u6539 URL\u3002<\/p>\n<p>In this flow, whenever you return HTML you use a PageResult; when you redirect to a new page, you use a RedirectToPageResult.<br \/>\n\u5728\u6b64\u6d41\u7a0b\u4e2d\uff0c\u65e0\u8bba\u4f55\u65f6\u8fd4\u56de HTML\uff0c\u60a8\u90fd\u4f1a\u4f7f\u7528 PageResult;\u5f53\u60a8\u91cd\u5b9a\u5411\u5230\u65b0\u9875\u9762\u65f6\uff0c\u60a8\u5c06\u4f7f\u7528 RedirectToPageResult\u3002<\/p>\n<p><b>Tip<\/b> Razor Pages are generally designed to be stateless, so if you want to persist data between multiple pages, you need to place it in a database or similar store. If you want to store data for a single request, you may be able to use TempData, which stores small amounts of data in cookies for a single request. See the documentation for details: <a href=\"http:\/\/mng.bz\/XdXp\">http:\/\/mng.bz\/XdXp<\/a>.<br \/>\n\u63d0\u793a:Razor \u9875\u9762\u901a\u5e38\u8bbe\u8ba1\u4e3a\u65e0\u72b6\u6001\u7684\uff0c\u56e0\u6b64\u5982\u679c\u8981\u5728\u591a\u4e2a\u9875\u9762\u4e4b\u95f4\u4fdd\u5b58\u6570\u636e\uff0c\u5219\u9700\u8981\u5c06\u5176\u653e\u7f6e\u5728\u6570\u636e\u5e93\u6216\u7c7b\u4f3c\u5b58\u50a8\u4e2d\u3002\u5982\u679c\u8981\u5b58\u50a8\u5355\u4e2a\u8bf7\u6c42\u7684\u6570\u636e\uff0c\u5219\u53ef\u4ee5\u4f7f\u7528 TempData\uff0c\u5b83\u5c06\u5c11\u91cf\u6570\u636e\u5b58\u50a8\u5728\u5355\u4e2a\u8bf7\u6c42\u7684 Cookie \u4e2d\u3002\u6709\u5173\u8be6\u7ec6\u4fe1\u606f\uff0c\u8bf7\u53c2\u9605\u6587\u6863\uff1a<a href=\"http:\/\/mng.bz\/XdXp\">http:\/\/mng.bz\/XdXp<\/a>\u3002<\/p>\n<h3>15.4.2 NotFoundResult and StatusCodeResult<\/h3>\n<p>15.4.2 NotFoundResult \u548c StatusCodeResult<\/p>\n<p>As well as sending HTML and redirect responses, you\u2019ll occasionally need to send specific HTTP status codes. If you request a page for viewing a product on an e-commerce application, and that product doesn\u2019t exist, a 404 HTTP status code is returned to the browser, and you\u2019ll typically see a \u201cNot found\u201d web page. Razor Pages can achieve this behavior by returning a NotFoundResult, which returns a raw 404 HTTP status code. You could achieve a similar result using StatusCodeResult and setting the status code returned explicitly to 404.<br \/>\n\u9664\u4e86\u53d1\u9001 HTML \u548c\u91cd\u5b9a\u5411\u54cd\u5e94\u5916\uff0c\u60a8\u6709\u65f6\u8fd8\u9700\u8981\u53d1\u9001\u7279\u5b9a\u7684 HTTP \u72b6\u6001\u4ee3\u7801\u3002\u5982\u679c\u60a8\u8bf7\u6c42\u4e00\u4e2a\u9875\u9762\u6765\u67e5\u770b\u7535\u5b50\u5546\u52a1\u5e94\u7528\u7a0b\u5e8f\u4e0a\u7684\u4ea7\u54c1\uff0c\u4f46\u8be5\u4ea7\u54c1\u4e0d\u5b58\u5728\uff0c\u5219\u4f1a\u5411\u6d4f\u89c8\u5668\u8fd4\u56de 404 HTTP \u72b6\u6001\u4ee3\u7801\uff0c\u5e76\u4e14\u60a8\u901a\u5e38\u4f1a\u770b\u5230\u201c\u672a\u627e\u5230\u201d\u7f51\u9875\u3002Razor Pages \u53ef\u4ee5\u901a\u8fc7\u8fd4\u56de NotFoundResult \u6765\u5b9e\u73b0\u6b64\u884c\u4e3a\uff0c\u8be5\u7ed3\u679c\u8fd4\u56de\u539f\u59cb 404 HTTP \u72b6\u6001\u4ee3\u7801\u3002\u60a8\u53ef\u4ee5\u4f7f\u7528 StatusCodeResult \u5e76\u5c06\u8fd4\u56de\u7684\u72b6\u6001\u4ee3\u7801\u663e\u5f0f\u8bbe\u7f6e\u4e3a 404 \u6765\u5b9e\u73b0\u7c7b\u4f3c\u7684\u7ed3\u679c\u3002<\/p>\n<p>Note that NotFoundResult doesn\u2019t generate any HTML; it only generates a raw 404 status code and returns it through the middleware pipeline. This generally isn\u2019t a great user experience, as the browser typically displays a default page, such as that shown in figure 15.4.<br \/>\n\u8bf7\u6ce8\u610f\uff0cNotFoundResult \u4e0d\u4f1a\u751f\u6210\u4efb\u4f55 HTML;\u5b83\u53ea\u751f\u6210\u4e00\u4e2a\u539f\u59cb\u7684 404 \u72b6\u6001\u7801\uff0c\u5e76\u901a\u8fc7\u4e2d\u95f4\u4ef6\u7ba1\u9053\u8fd4\u56de\u3002\u8fd9\u901a\u5e38\u4e0d\u662f\u5f88\u597d\u7684\u7528\u6237\u4f53\u9a8c\uff0c\u56e0\u4e3a\u6d4f\u89c8\u5668\u901a\u5e38\u4f1a\u663e\u793a\u9ed8\u8ba4\u9875\u9762\uff0c\u5982\u56fe 15.4 \u6240\u793a\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1504.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 15.4 If you return a raw 404 status code without any HTML, the browser will render a generic default page instead. The message is of limited utility to users and may leave many of them confused or thinking that your web application is broken.<br \/>\n\u56fe 15.4 \u5982\u679c\u8fd4\u56de\u4e0d\u5e26\u4efb\u4f55 HTML \u7684\u539f\u59cb 404 \u72b6\u6001\u4ee3\u7801\uff0c\u6d4f\u89c8\u5668\u5c06\u5448\u73b0\u901a\u7528\u7684\u9ed8\u8ba4\u9875\u9762\u3002\u8be5\u6d88\u606f\u5bf9\u7528\u6237\u7684\u5b9e\u7528\u6027\u6709\u9650\uff0c\u53ef\u80fd\u4f1a\u8ba9\u8bb8\u591a\u4eba\u611f\u5230\u56f0\u60d1\u6216\u8ba4\u4e3a\u60a8\u7684 Web \u5e94\u7528\u7a0b\u5e8f\u5df2\u635f\u574f\u3002<\/p>\n<p>Returning raw status codes is fine when you\u2019re building an API, but for a Razor Pages application, this is rarely good enough. In section 15.5 you\u2019ll learn how you can intercept this raw 404 status code after it\u2019s been generated and provide a user-friendly HTML response for it instead.<br \/>\n\u5728\u6784\u5efa API \u65f6\uff0c\u8fd4\u56de\u539f\u59cb\u72b6\u6001\u4ee3\u7801\u662f\u53ef\u4ee5\u7684\uff0c\u4f46\u5bf9\u4e8e Razor Pages \u5e94\u7528\u7a0b\u5e8f\uff0c\u8fd9\u5f88\u5c11\u8db3\u591f\u597d\u3002\u5728 Section 15.5 \u4e2d\uff0c\u60a8\u5c06\u5b66\u4e60\u5982\u4f55\u5728\u751f\u6210\u539f\u59cb 404 \u72b6\u6001\u4ee3\u7801\u540e\u62e6\u622a\u5b83\uff0c\u5e76\u4e3a\u5176\u63d0\u4f9b\u7528\u6237\u53cb\u597d\u7684 HTML \u54cd\u5e94\u3002<\/p>\n<h2>15.5 Handler status codes with StatusCodePagesMiddleware<\/h2>\n<p>15.5 \u4f7f\u7528 StatusCodePagesMiddleware \u7684\u5904\u7406\u7a0b\u5e8f\u72b6\u6001\u7801<\/p>\n<p>In chapter 4 we discussed error handling middleware, which is designed to catch exceptions generated anywhere in your middleware pipeline, catch them, and generate a user-friendly response. In this section you\u2019ll learn about an analogous piece of middleware that intercepts error HTTP status codes: StatusCodePagesMiddleware.<br \/>\n\u5728\u7b2c 4 \u7ae0\u4e2d\uff0c\u6211\u4eec\u8ba8\u8bba\u4e86\u9519\u8bef\u5904\u7406\u4e2d\u95f4\u4ef6\uff0c\u5b83\u65e8\u5728\u6355\u83b7\u4e2d\u95f4\u4ef6\u7ba1\u9053\u4e2d\u4efb\u4f55\u4f4d\u7f6e\u751f\u6210\u7684\u5f02\u5e38\uff0c\u6355\u83b7\u5b83\u4eec\uff0c\u5e76\u751f\u6210\u7528\u6237\u53cb\u597d\u7684\u54cd\u5e94\u3002\u5728\u672c\u8282\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3\u4e00\u4e2a\u7c7b\u4f3c\u7684\u4e2d\u95f4\u4ef6\uff0c\u7528\u4e8e\u62e6\u622a\u9519\u8bef HTTP \u72b6\u6001\u4ee3\u7801\uff1aStatusCodePagesMiddleware\u3002<\/p>\n<p>Your Razor Pages application can return a wide range of HTTP status codes that indicate some sort of error state. You\u2019ve seen previously that a 500 \u201cserver error\u201d is sent when an exception occurs and isn\u2019t handled and that a 404 \u201cfile not found\u201d error is sent when you return a NotFoundResult from a page handler. 404 errors are particularly common, often occurring when a user enters an invalid URL.<br \/>\nRazor Pages \u5e94\u7528\u7a0b\u5e8f\u53ef\u4ee5\u8fd4\u56de\u5404\u79cd HTTP \u72b6\u6001\u4ee3\u7801\uff0c\u8fd9\u4e9b\u4ee3\u7801\u6307\u793a\u67d0\u79cd\u9519\u8bef\u72b6\u6001\u3002\u60a8\u4e4b\u524d\u5df2\u7ecf\u770b\u5230\uff0c\u5f53\u53d1\u751f\u5f02\u5e38\u4e14\u672a\u5f97\u5230\u5904\u7406\u65f6\uff0c\u4f1a\u53d1\u9001 500 \u201cserver error\u201d \uff0c\u5f53\u60a8\u4ece\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u8fd4\u56de NotFoundResult \u65f6\uff0c\u4f1a\u53d1\u9001 404 \u201cfile not found\u201d \u9519\u8bef\u3002404 \u9519\u8bef\u7279\u522b\u5e38\u89c1\uff0c\u901a\u5e38\u5728\u7528\u6237\u8f93\u5165\u65e0\u6548\u7684 URL \u65f6\u53d1\u751f\u3002<\/p>\n<p><b>Tip<\/b> 404 errors are often used to indicate that a specific requested object was not found. For example, a request for the details of a product with an ID of 23 might return a 404 if no such product exists. They\u2019re also generated automatically if no endpoint in your application matches the request URL.<br \/>\nTip: 404 \u9519\u8bef\u901a\u5e38\u7528\u4e8e\u6307\u793a\u672a\u627e\u5230\u7279\u5b9a\u8bf7\u6c42\u7684\u5bf9\u8c61\u3002\u4f8b\u5982\uff0c\u5982\u679c\u4e0d\u5b58\u5728 ID \u4e3a 23 \u7684\u4ea7\u54c1\u7684\u8be6\u7ec6\u4fe1\u606f\uff0c\u5219\u8bf7\u6c42 ID \u4e3a 23 \u7684\u4ea7\u54c1\u53ef\u80fd\u4f1a\u8fd4\u56de 404\u3002\u5982\u679c\u5e94\u7528\u7a0b\u5e8f\u4e2d\u6ca1\u6709\u7ec8\u7aef\u8282\u70b9\u4e0e\u8bf7\u6c42 URL \u5339\u914d\uff0c\u7cfb\u7edf\u4e5f\u4f1a\u81ea\u52a8\u751f\u6210\u8fd9\u4e9b URL\u3002<\/p>\n<p>Returning \u201craw\u201d status codes without additional content is generally OK if you\u2019re building a minimal API or web API application. But as mentioned before, for apps consumed directly by users such as Razor Pages apps, this can result in a poor user experience. If you don\u2019t handle these status codes, users will see a generic error page, as you saw in figure 15.4, which may leave many confused users thinking your application is broken. A better approach is to handle these error codes and return an error page that\u2019s in keeping with the rest of your application or at least doesn\u2019t make your application look broken.<br \/>\n\u5982\u679c\u60a8\u6b63\u5728\u6784\u5efa\u6700\u5c0f\u7684 API \u6216 Web API \u5e94\u7528\u7a0b\u5e8f\uff0c\u5219\u8fd4\u56de\u4e0d\u5e26\u989d\u5916\u5185\u5bb9\u7684\u201c\u539f\u59cb\u201d\u72b6\u6001\u4ee3\u7801\u901a\u5e38\u662f\u53ef\u4ee5\u7684\u3002\u4f46\u5982\u524d\u6240\u8ff0\uff0c\u5bf9\u4e8e\u7528\u6237\u76f4\u63a5\u4f7f\u7528\u7684\u5e94\u7528\u7a0b\u5e8f\uff08\u5982 Razor Pages \u5e94\u7528\u7a0b\u5e8f\uff09\uff0c\u8fd9\u53ef\u80fd\u4f1a\u5bfc\u81f4\u7528\u6237\u4f53\u9a8c\u4e0d\u4f73\u3002\u5982\u679c\u4f60\u4e0d\u5904\u7406\u8fd9\u4e9b\u72b6\u6001\u7801\uff0c\u7528\u6237\u5c06\u770b\u5230\u4e00\u4e2a\u901a\u7528\u7684\u9519\u8bef\u9875\u9762\uff0c\u5982\u56fe 15.4 \u6240\u793a\uff0c\u8fd9\u53ef\u80fd\u4f1a\u8ba9\u8bb8\u591a\u56f0\u60d1\u7684\u7528\u6237\u8ba4\u4e3a\u4f60\u7684\u5e94\u7528\u7a0b\u5e8f\u574f\u4e86\u3002\u66f4\u597d\u7684\u65b9\u6cd5\u662f\u5904\u7406\u8fd9\u4e9b\u9519\u8bef\u4ee3\u7801\u5e76\u8fd4\u56de\u4e00\u4e2a\u9519\u8bef\u9875\u9762\uff0c\u8be5\u9875\u9762\u4e0e\u5e94\u7528\u7a0b\u5e8f\u7684\u5176\u4f59\u90e8\u5206\u4fdd\u6301\u4e00\u81f4\uff0c\u6216\u8005\u81f3\u5c11\u4e0d\u4f1a\u4f7f\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u770b\u8d77\u6765\u635f\u574f\u3002<\/p>\n<p>Microsoft provides StatusCodePagesMiddleware for handling this use case. As with all error handling middleware, you should add it early in your middleware pipeline, as it will handle only errors generated by later middleware components.<br \/>\nMicrosoft \u63d0\u4f9b\u4e86 StatusCodePagesMiddleware \u6765\u5904\u7406\u6b64\u7528\u4f8b\u3002\u4e0e\u6240\u6709\u9519\u8bef\u5904\u7406\u4e2d\u95f4\u4ef6\u4e00\u6837\uff0c\u60a8\u5e94\u8be5\u5728\u4e2d\u95f4\u4ef6\u7ba1\u9053\u7684\u65e9\u671f\u6dfb\u52a0\u5b83\uff0c\u56e0\u4e3a\u5b83\u5c06\u4ec5\u5904\u7406\u540e\u7eed\u4e2d\u95f4\u4ef6\u7ec4\u4ef6\u751f\u6210\u7684\u9519\u8bef\u3002<\/p>\n<p>You can use the middleware several ways in your application. The simplest approach is to add the middleware to your pipeline without any additional configuration, using<br \/>\n\u60a8\u53ef\u4ee5\u5728\u5e94\u7528\u7a0b\u5e8f\u4e2d\u4ee5\u591a\u79cd\u65b9\u5f0f\u4f7f\u7528\u4e2d\u95f4\u4ef6\u3002\u6700\u7b80\u5355\u7684\u65b9\u6cd5\u662f\u5c06\u4e2d\u95f4\u4ef6\u6dfb\u52a0\u5230\u60a8\u7684\u7ba1\u9053\u4e2d\uff0c\u65e0\u9700\u4efb\u4f55\u5176\u4ed6\u914d\u7f6e\uff0c\u4f7f\u7528<\/p>\n<pre><code>app.UseStatusCodePages();<\/code><\/pre>\n<p>With this method, the middleware intercepts any response that has an HTTP status code that starts with 4xx or 5xx and has no response body. For the simplest case, where you don\u2019t provide any additional configuration, the middleware adds a plain-text response body, indicating the type and name of the response, as shown in figure 15.5. This is arguably worse than the default message at this point, but it is a starting point for providing a more consistent experience to users.<br \/>\n\u4f7f\u7528\u6b64\u65b9\u6cd5\uff0c\u4e2d\u95f4\u4ef6\u4f1a\u62e6\u622a HTTP \u72b6\u6001\u4ee3\u7801\u4ee5 4xx \u6216 5xx \u5f00\u5934\u4e14\u6ca1\u6709\u54cd\u5e94\u6b63\u6587\u7684\u4efb\u4f55\u54cd\u5e94\u3002\u5bf9\u4e8e\u6700\u7b80\u5355\u7684\u60c5\u51b5\uff0c\u5982\u679c\u60a8\u4e0d\u63d0\u4f9b\u4efb\u4f55\u5176\u4ed6\u914d\u7f6e\uff0c\u4e2d\u95f4\u4ef6\u4f1a\u6dfb\u52a0\u4e00\u4e2a\u7eaf\u6587\u672c\u54cd\u5e94\u6b63\u6587\uff0c\u6307\u793a\u54cd\u5e94\u7684\u7c7b\u578b\u548c\u540d\u79f0\uff0c\u5982\u56fe 15.5 \u6240\u793a\u3002\u8fd9\u53ef\u4ee5\u8bf4\u6bd4\u6b64\u65f6\u7684\u9ed8\u8ba4\u6d88\u606f\u66f4\u7cdf\u7cd5\uff0c\u4f46\u5b83\u662f\u4e3a\u7528\u6237\u63d0\u4f9b\u66f4\u4e00\u81f4\u4f53\u9a8c\u7684\u8d77\u70b9\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1505.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 15.5 Status code error page for a 404 error. You generally won\u2019t use this version of the middleware in production, as it doesn\u2019t provide a great user experience, but it demonstrates that the error codes are being intercepted correctly.<br \/>\n\u56fe 15.5 404 \u9519\u8bef\u7684\u72b6\u6001\u4ee3\u7801\u9519\u8bef\u9875\u9762\u3002\u60a8\u901a\u5e38\u4e0d\u4f1a\u5728\u751f\u4ea7\u73af\u5883\u4e2d\u4f7f\u7528\u6b64\u7248\u672c\u7684\u4e2d\u95f4\u4ef6\uff0c\u56e0\u4e3a\u5b83\u4e0d\u4f1a\u63d0\u4f9b\u51fa\u8272\u7684\u7528\u6237\u4f53\u9a8c\uff0c\u4f46\u5b83\u8868\u660e\u9519\u8bef\u4ee3\u7801\u88ab\u6b63\u786e\u62e6\u622a\u3002<\/p>\n<p>A more typical approach to using StatusCodePagesMiddleware in production is to reexecute the pipeline when an error is captured, using a similar technique to the ExceptionHandlerMiddleware. This allows you to have dynamic error pages that fit with the rest of your application. To use this technique, replace the call to UseStatusCodePages with the following extension method:<br \/>\n\u5728\u751f\u4ea7\u73af\u5883\u4e2d\u4f7f\u7528 StatusCodePagesMiddleware \u7684\u66f4\u5178\u578b\u65b9\u6cd5\u662f\u5728\u6355\u83b7\u9519\u8bef\u65f6\u91cd\u65b0\u6267\u884c\u7ba1\u9053\uff0c\u4f7f\u7528\u4e0e ExceptionHandlerMiddleware \u7c7b\u4f3c\u7684\u6280\u672f\u3002\u8fd9\u5141\u8bb8\u4f60\u62e5\u6709\u9002\u5408\u5e94\u7528\u7a0b\u5e8f\u5176\u4f59\u90e8\u5206\u7684\u52a8\u6001\u9519\u8bef\u9875\u9762\u3002\u82e5\u8981\u4f7f\u7528\u6b64\u6280\u672f\uff0c\u8bf7\u5c06\u5bf9 UseStatusCodePages \u7684\u8c03\u7528\u66ff\u6362\u4e3a\u4ee5\u4e0b\u6269\u5c55\u65b9\u6cd5\uff1a<\/p>\n<pre><code>app.UseStatusCodePagesWithReExecute(&quot;\/{0}&quot;);<\/code><\/pre>\n<p>This extension method configures StatusCodePagesMiddleware to reexecute the pipeline whenever a 4xx or 5xx response code is found, using the provided error handling path. This is similar to the way ExceptionHandlerMiddleware reexecutes the pipeline, as shown in figure 15.6.<br \/>\n\u6b64\u6269\u5c55\u65b9\u6cd5\u5c06 StatusCodePagesMiddleware \u914d\u7f6e\u4e3a\u5728\u627e\u5230 4xx \u6216 5xx \u54cd\u5e94\u4ee3\u7801\u65f6\uff0c\u4f7f\u7528\u63d0\u4f9b\u7684\u9519\u8bef\u5904\u7406\u8def\u5f84\u91cd\u65b0\u6267\u884c\u7ba1\u9053\u3002\u8fd9\u7c7b\u4f3c\u4e8e ExceptionHandlerMiddleware \u91cd\u65b0\u6267\u884c\u7ba1\u9053\u7684\u65b9\u5f0f\uff0c\u5982\u56fe 15.6 \u6240\u793a\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1506.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 15.6 StatusCodePagesMiddleware reexecuting the pipeline to generate an HTML body for a 404 response. A request to the \/ path returns a 404 response, which is handled by the status code middleware. The pipeline is reexecuted using the \/404 path to generate the HTML response.<br \/>\n\u56fe 15.6 StatusCodePagesMiddleware \u91cd\u65b0\u6267\u884c\u7ba1\u9053\u4ee5\u751f\u6210 404 \u54cd\u5e94\u7684 HTML \u6b63\u6587\u3002\u5bf9 \/ \u8def\u5f84\u7684\u8bf7\u6c42\u5c06\u8fd4\u56de 404 \u54cd\u5e94\uff0c\u8be5\u54cd\u5e94\u7531\u72b6\u6001\u4ee3\u7801\u4e2d\u95f4\u4ef6\u5904\u7406\u3002\u4f7f\u7528 \/404 \u8def\u5f84\u91cd\u65b0\u6267\u884c\u7ba1\u9053\u4ee5\u751f\u6210 HTML \u54cd\u5e94\u3002<\/p>\n<p>Note that the error handling path &quot;\/{0}&quot; contains a format string token, {0}. When the path is reexecuted, the middleware replaces this token with the status code number. For example, a 404 error would reexecute the \/404 path. The handler for the path (typically a Razor Page, but it can be any endpoint) has access to the status code and can optionally tailor the response, depending on the status code. You can choose any error handling path as long as your application knows how to handle it.<br \/>\n\u8bf7\u6ce8\u610f\uff0c\u9519\u8bef\u5904\u7406\u8def\u5f84 \u201c\/{0}\u201d \u5305\u542b\u683c\u5f0f\u5b57\u7b26\u4e32\u6807\u8bb0 {0}\u3002\u91cd\u65b0\u6267\u884c\u8def\u5f84\u65f6\uff0c\u4e2d\u95f4\u4ef6\u4f1a\u5c06\u6b64\u4ee4\u724c\u66ff\u6362\u4e3a\u72b6\u6001\u4ee3\u7801\u7f16\u53f7\u3002\u4f8b\u5982\uff0c404 \u9519\u8bef\u5c06\u91cd\u65b0\u6267\u884c \/404 \u8def\u5f84\u3002\u8def\u5f84\u7684\u5904\u7406\u7a0b\u5e8f\uff08\u901a\u5e38\u662f Razor Page\uff0c\u4f46\u53ef\u4ee5\u662f\u4efb\u4f55\u7ec8\u7ed3\u70b9\uff09\u6709\u6743\u8bbf\u95ee\u72b6\u6001\u4ee3\u7801\uff0c\u5e76\u4e14\u53ef\u4ee5\u6839\u636e\u72b6\u6001\u4ee3\u7801\u9009\u62e9\u6027\u5730\u5b9a\u5236\u54cd\u5e94\u3002\u60a8\u53ef\u4ee5\u9009\u62e9\u4efb\u4f55\u9519\u8bef\u5904\u7406\u8def\u5f84\uff0c\u53ea\u8981\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u77e5\u9053\u5982\u4f55\u5904\u7406\u5b83\u3002<\/p>\n<p>With this approach in place, you can create different error pages for different error codes, such as the 404-specific error page shown in figure 15.7. This technique ensures that your error pages are consistent with the rest of your application, including any dynamically generated content, while also allowing you to tailor the message for common errors.<br \/>\n\u4f7f\u7528\u8fd9\u79cd\u65b9\u6cd5\uff0c\u60a8\u53ef\u4ee5\u4e3a\u4e0d\u540c\u7684\u9519\u8bef\u4ee3\u7801\u521b\u5efa\u4e0d\u540c\u7684\u9519\u8bef\u9875\u9762\uff0c\u4f8b\u5982\u56fe 15.7 \u4e2d\u6240\u793a\u7684\u7279\u5b9a\u4e8e 404 \u7684\u9519\u8bef\u9875\u9762\u3002\u6b64\u6280\u672f\u53ef\u786e\u4fdd\u9519\u8bef\u9875\u9762\u4e0e\u5e94\u7528\u7a0b\u5e8f\u7684\u5176\u4f59\u90e8\u5206\uff08\u5305\u62ec\u4efb\u4f55\u52a8\u6001\u751f\u6210\u7684\u5185\u5bb9\uff09\u4fdd\u6301\u4e00\u81f4\uff0c\u540c\u65f6\u8fd8\u5141\u8bb8\u60a8\u9488\u5bf9\u5e38\u89c1\u9519\u8bef\u5b9a\u5236\u6d88\u606f\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1507.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 15.7 An error status code page for a missing file. When an error code is detected (in this case, a 404 error), the middleware pipeline is reexecuted to generate the response. This allows dynamic portions of your web page to remain consistent on error pages.<br \/>\n\u56fe 15.7 \u7f3a\u5931\u6587\u4ef6\u7684\u9519\u8bef\u72b6\u6001\u4ee3\u7801\u9875\u9762\u3002\u5f53\u68c0\u6d4b\u5230\u9519\u8bef\u4ee3\u7801\uff08\u5728\u672c\u4f8b\u4e2d\u4e3a 404 \u9519\u8bef\uff09\u65f6\uff0c\u5c06\u91cd\u65b0\u6267\u884c\u4e2d\u95f4\u4ef6\u7ba1\u9053\u4ee5\u751f\u6210\u54cd\u5e94\u3002\u8fd9\u5141\u8bb8\u7f51\u9875\u7684\u52a8\u6001\u90e8\u5206\u5728\u9519\u8bef\u9875\u9762\u4e0a\u4fdd\u6301\u4e00\u81f4\u3002<\/p>\n<p><b>Warning<\/b> As I mentioned in chapter 4, if your error handling path generates an error, the user will see a generic browser error. To mitigate this, it\u2019s often better to use a static error page that will always work rather than a dynamic page that risks throwing more errors.<br \/>\n\u8b66\u544a:\u6b63\u5982\u6211\u5728\u7b2c 4 \u7ae0\u4e2d\u63d0\u5230\u7684\uff0c\u5982\u679c\u4f60\u7684\u9519\u8bef\u5904\u7406\u8def\u5f84\u4ea7\u751f\u4e86\u4e00\u4e2a\u9519\u8bef\uff0c\u7528\u6237\u5c06\u770b\u5230\u4e00\u4e2a\u901a\u7528\u7684\u6d4f\u89c8\u5668\u9519\u8bef\u3002\u4e3a\u4e86\u7f13\u89e3\u8fd9\u79cd\u60c5\u51b5\uff0c\u901a\u5e38\u6700\u597d\u4f7f\u7528\u59cb\u7ec8\u6709\u6548\u7684\u9759\u6001\u9519\u8bef\u9875\u9762\uff0c\u800c\u4e0d\u662f\u5192\u7740\u5f15\u53d1\u66f4\u591a\u9519\u8bef\u7684\u52a8\u6001\u9875\u9762\u3002<\/p>\n<p>The UseStatusCodePagesWithReExecute() method is great for returning a friendly error page when something goes wrong in a request, but there\u2019s a second way to use the StatusCodePagesMiddleware. Instead of reexecuting the pipeline to generate the error response, you can redirect the browser to the error page instead, by calling<br \/>\nUseStatusCodePagesWithReExecute\uff08\uff09 \u65b9\u6cd5\u975e\u5e38\u9002\u5408\u5728\u8bf7\u6c42\u51fa\u9519\u65f6\u8fd4\u56de\u53cb\u597d\u7684\u9519\u8bef\u9875\u9762\uff0c\u4f46\u8fd8\u6709\u7b2c\u4e8c\u79cd\u65b9\u6cd5\u53ef\u4ee5\u4f7f\u7528 StatusCodePagesMiddleware\u3002\u60a8\u53ef\u4ee5\u901a\u8fc7\u8c03\u7528<\/p>\n<pre><code>app.UseStatusCodePagesWithRedirects(&quot;\/{0}&quot;);<\/code><\/pre>\n<p>As for the reexecute version, this method takes a format string that defines the URL to generate the response. However, whereas the reexecute version generates the error response for the original request, the redirect version returns a 302 response initially, directing the browser to send a second request, this time for the error URL, as shown in figure 15.8. This second request generates the error page response, returning it with a 200 status code.<br \/>\n\u5bf9\u4e8e reexecute \u7248\u672c\uff0c\u6b64\u65b9\u6cd5\u91c7\u7528\u5b9a\u4e49 URL \u4ee5\u751f\u6210\u54cd\u5e94\u7684\u683c\u5f0f\u5b57\u7b26\u4e32\u3002\u4f46\u662f\uff0creexecute \u7248\u672c\u4e3a\u539f\u59cb\u8bf7\u6c42\u751f\u6210\u9519\u8bef\u54cd\u5e94\uff0c\u800c\u91cd\u5b9a\u5411\u7248\u672c\u6700\u521d\u8fd4\u56de 302 \u54cd\u5e94\uff0c\u6307\u793a\u6d4f\u89c8\u5668\u53d1\u9001\u7b2c\u4e8c\u4e2a\u8bf7\u6c42\uff0c\u8fd9\u6b21\u662f\u9488\u5bf9\u9519\u8bef URL\uff0c\u5982\u56fe 15.8 \u6240\u793a\u3002\u7b2c\u4e8c\u4e2a\u8bf7\u6c42\u751f\u6210\u9519\u8bef\u9875\u9762\u54cd\u5e94\uff0c\u5e76\u8fd4\u56de 200 \u72b6\u6001\u4ee3\u7801\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1508.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 15.8 StatusCodePagesMiddleware returning redirects to generate error pages. A request to the \/ path returns a 404 response, which is intercepted by the status code middleware and converted to a 302 response. The browser makes a second request using the \/404 path to generate the HTML response.<br \/>\n\u56fe 15.8 StatusCodePagesMiddleware \u8fd4\u56de\u91cd\u5b9a\u5411\u4ee5\u751f\u6210\u9519\u8bef\u9875\u9762\u3002\u5bf9 \/ \u8def\u5f84\u7684\u8bf7\u6c42\u8fd4\u56de 404 \u54cd\u5e94\uff0c\u8be5\u54cd\u5e94\u88ab\u72b6\u6001\u4ee3\u7801\u4e2d\u95f4\u4ef6\u62e6\u622a\u5e76\u8f6c\u6362\u4e3a 302 \u54cd\u5e94\u3002\u6d4f\u89c8\u5668\u4f7f\u7528 \/404 \u8def\u5f84\u53d1\u51fa\u7b2c\u4e8c\u4e2a\u8bf7\u6c42\u4ee5\u751f\u6210 HTML \u54cd\u5e94\u3002<\/p>\n<p>Whether you use the reexecute or redirect method, the browser ultimately receives essentially the same HTML. However, there are some important differences:<br \/>\n\u65e0\u8bba\u60a8\u4f7f\u7528 reexecute \u8fd8\u662f redirect \u65b9\u6cd5\uff0c\u6d4f\u89c8\u5668\u6700\u7ec8\u90fd\u4f1a\u6536\u5230\u57fa\u672c\u76f8\u540c\u7684 HTML\u3002\u4f46\u662f\uff0c\u5b58\u5728\u4e00\u4e9b\u91cd\u8981\u7684\u5dee\u5f02\uff1a<\/p>\n<p>\u2022  With the reexecute approach, the original status code (such as a 404) is preserved. The browser sees the error page HTML as the response to the original request. If the user refreshes the page, the browser makes a second request for the original path.<br \/>\n\u4f7f\u7528\u91cd\u65b0\u6267\u884c\u65b9\u6cd5\u65f6\uff0c\u5c06\u4fdd\u7559\u539f\u59cb\u72b6\u6001\u4ee3\u7801 \uff08\u5982 404\uff09\u3002\u6d4f\u89c8\u5668\u5c06\u9519\u8bef\u9875\u9762 HTML \u89c6\u4e3a\u5bf9\u539f\u59cb\u8bf7\u6c42\u7684\u54cd\u5e94\u3002\u5982\u679c\u7528\u6237\u5237\u65b0\u9875\u9762\uff0c\u6d4f\u89c8\u5668\u5c06\u5bf9\u539f\u59cb\u8def\u5f84\u53d1\u51fa\u7b2c\u4e8c\u4e2a\u8bf7\u6c42\u3002<br \/>\n\u2022  With the redirect approach, the original status code is lost. The browser treats the redirect and second request as two separate requests and doesn\u2019t \u201cknow\u201d about the error. If the user refreshes the page, the browser makes a request for the same error path; it doesn\u2019t resend the original request.<br \/>\n\u4f7f\u7528\u91cd\u5b9a\u5411\u65b9\u6cd5\u65f6\uff0c\u539f\u59cb\u72b6\u6001\u4ee3\u7801\u5c06\u4e22\u5931\u3002\u6d4f\u89c8\u5668\u5c06\u91cd\u5b9a\u5411\u548c\u7b2c\u4e8c\u4e2a\u8bf7\u6c42\u89c6\u4e3a\u4e24\u4e2a\u5355\u72ec\u7684\u8bf7\u6c42\uff0c\u5e76\u4e14\u201c\u4e0d\u77e5\u9053\u201d\u9519\u8bef\u3002\u5982\u679c\u7528\u6237\u5237\u65b0\u9875\u9762\uff0c\u6d4f\u89c8\u5668\u4f1a\u8bf7\u6c42\u76f8\u540c\u7684\u9519\u8bef\u8def\u5f84;\u5b83\u4e0d\u4f1a\u91cd\u65b0\u53d1\u9001\u539f\u59cb\u8bf7\u6c42\u3002<\/p>\n<p>In most cases, I find the reexecute approach to be more useful, as it preserves the original error and typically has the behavior that users expect. There may be some cases where the redirect approach is useful, however, such as when an entirely different application generates the error page.<br \/>\n\u5728\u5927\u591a\u6570\u60c5\u51b5\u4e0b\uff0c\u6211\u53d1\u73b0 reexecute \u65b9\u6cd5\u66f4\u6709\u7528\uff0c\u56e0\u4e3a\u5b83\u4fdd\u7559\u4e86\u539f\u59cb\u9519\u8bef\uff0c\u5e76\u4e14\u901a\u5e38\u5177\u6709\u7528\u6237\u671f\u671b\u7684\u884c\u4e3a\u3002\u4f46\u662f\uff0c\u5728\u67d0\u4e9b\u60c5\u51b5\u4e0b\uff0c\u91cd\u5b9a\u5411\u65b9\u6cd5\u53ef\u80fd\u5f88\u6709\u7528\uff0c\u4f8b\u5982\uff0c\u5f53\u5b8c\u5168\u4e0d\u540c\u7684\u5e94\u7528\u7a0b\u5e8f\u751f\u6210\u9519\u8bef\u9875\u9762\u65f6\u3002<\/p>\n<p><b>Tip<\/b> Favor using UseStatusCodePagesWithReExecute over the redirect approach when the same app is generating the error page HTML for your app.<br \/>\n\u63d0\u793a:\u5f53\u540c\u4e00\u5e94\u7528\u7a0b\u5e8f\u4e3a\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u751f\u6210\u9519\u8bef\u9875\u9762 HTML \u65f6\uff0c\u4f18\u5148\u4f7f\u7528 UseStatusCodePagesWithReExecute \u800c\u4e0d\u662f\u91cd\u5b9a\u5411\u65b9\u6cd5\u3002<\/p>\n<p>You can use StatusCodePagesMiddleware in combination with other exception handling middleware by adding both to the pipeline. StatusCodePagesMiddleware modifies the response only if no response body has been written. So if another component, such as ExceptionHandlerMiddleware, returns a message body along with an error code, it won\u2019t be modified.<br \/>\n\u60a8\u53ef\u4ee5\u5c06 StatusCodePagesMiddleware \u4e0e\u5176\u4ed6\u5f02\u5e38\u5904\u7406\u4e2d\u95f4\u4ef6\u7ed3\u5408\u4f7f\u7528\uff0c\u65b9\u6cd5\u662f\u5c06\u4e24\u8005\u6dfb\u52a0\u5230\u7ba1\u9053\u4e2d\u3002StatusCodePagesMiddleware \u4ec5\u5728\u672a\u5199\u5165\u54cd\u5e94\u6b63\u6587\u65f6\u4fee\u6539\u54cd\u5e94\u3002\u56e0\u6b64\uff0c\u5982\u679c\u53e6\u4e00\u4e2a\u7ec4\u4ef6\uff08\u6bd4\u5982 ExceptionHandlerMiddleware\uff09\u8fd4\u56de\u6d88\u606f\u6b63\u6587\u548c\u9519\u8bef\u4ee3\u7801\uff0c\u5219\u4e0d\u4f1a\u5bf9\u5176\u8fdb\u884c\u4fee\u6539\u3002<\/p>\n<p><b>NOTE<\/b> StatusCodePagesMiddleware has additional overloads that let you execute custom middleware when an error occurs instead of reexecuting the middleware pipeline. You can read about this approach at <a href=\"http:\/\/mng.bz\/0K66\">http:\/\/mng.bz\/0K66<\/a>.<br \/>\n\u6ce8\u610f:StatusCodePagesMiddleware \u5177\u6709\u989d\u5916\u7684\u91cd\u8f7d\uff0c\u5141\u8bb8\u60a8\u5728\u53d1\u751f\u9519\u8bef\u65f6\u6267\u884c\u81ea\u5b9a\u4e49\u4e2d\u95f4\u4ef6\uff0c\u800c\u4e0d\u662f\u91cd\u65b0\u6267\u884c\u4e2d\u95f4\u4ef6\u7ba1\u9053\u3002\u60a8\u53ef\u4ee5\u5728 <a href=\"http:\/\/mng.bz\/0K66\">http:\/\/mng.bz\/0K66<\/a> \u4e0a\u9605\u8bfb\u6709\u5173\u6b64\u65b9\u6cd5\u7684\u4fe1\u606f\u3002<\/p>\n<p>Error handling is essential when developing any web application; errors happen, and you need to handle them gracefully. The StatusCodePagesMiddleware is practically a must-have for any production Razor Pages app.<br \/>\n\u5728\u5f00\u53d1\u4efb\u4f55 Web \u5e94\u7528\u7a0b\u5e8f\u65f6\uff0c\u9519\u8bef\u5904\u7406\u90fd\u662f\u5fc5\u4e0d\u53ef\u5c11\u7684;\u9519\u8bef\u4f1a\u53d1\u751f\uff0c\u60a8\u9700\u8981\u59a5\u5584\u5904\u7406\u5b83\u4eec\u3002StatusCodePagesMiddleware \u5b9e\u9645\u4e0a\u662f\u4efb\u4f55\u751f\u4ea7 Razor Pages \u5e94\u7528\u7684\u5fc5\u5907\u5de5\u5177\u3002<\/p>\n<p>In chapter 16 we\u2019ll dive into model binding. You\u2019ll see how the route values generated during routing are bound to your page handler parameters, and perhaps more important, how to validate the values you\u2019re provided.<br \/>\n\u5728\u7b2c 16 \u7ae0\u4e2d\uff0c\u6211\u4eec\u5c06\u6df1\u5165\u63a2\u8ba8\u6a21\u578b\u7ed1\u5b9a\u3002\u60a8\u5c06\u770b\u5230\u8def\u7531\u671f\u95f4\u751f\u6210\u7684\u8def\u7531\u503c\u5982\u4f55\u7ed1\u5b9a\u5230\u60a8\u7684\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u53c2\u6570\uff0c\u4e5f\u8bb8\u66f4\u91cd\u8981\u7684\u662f\uff0c\u5982\u4f55\u9a8c\u8bc1\u60a8\u63d0\u4f9b\u7684\u503c\u3002<\/p>\n<h2>15.6 Summary<\/h2>\n<p>15.6 \u603b\u7ed3<\/p>\n<p>A Razor Page page handler is the method in the Razor Page PageModel class that is executed when a Razor Page handles a request.<br \/>\nRazor Page \u9875\u9762\u5904\u7406\u7a0b\u5e8f\u662f Razor Page PageModel \u7c7b\u4e2d\u7684\u65b9\u6cd5\uff0c\u5728 Razor Page \u5904\u7406\u8bf7\u6c42\u65f6\u6267\u884c\u3002<\/p>\n<p>Page handlers should ensure that the incoming request is valid, call in to the appropriate domain services to handle the request, and then choose the kind of response to return. They typically don\u2019t generate the response directly; instead, they describe how to generate the response.<br \/>\n\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u5e94\u786e\u4fdd\u4f20\u5165\u8bf7\u6c42\u6709\u6548\uff0c\u8c03\u7528\u76f8\u5e94\u7684\u57df\u670d\u52a1\u4ee5\u5904\u7406\u8bf7\u6c42\uff0c\u7136\u540e\u9009\u62e9\u8981\u8fd4\u56de\u7684\u54cd\u5e94\u7c7b\u578b\u3002\u5b83\u4eec\u901a\u5e38\u4e0d\u4f1a\u76f4\u63a5\u751f\u6210\u54cd\u5e94;\u76f8\u53cd\uff0c\u5b83\u4eec\u63cf\u8ff0\u4e86\u5982\u4f55\u751f\u6210\u54cd\u5e94\u3002<\/p>\n<p>Page handlers should generally 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<p>When a Razor Page is executed, a single page handler is invoked based on the HTTP verb of the request and the value of the handler route value. If no page handler is found, an \u201cimplicit\u201d handler is used instead, simply rendering the content of the Razor Page.<br \/>\n\u6267\u884c Razor \u9875\u9762\u65f6\uff0c\u5c06\u6839\u636e\u8bf7\u6c42\u7684 HTTP \u8c13\u8bcd\u548c\u5904\u7406\u7a0b\u5e8f\u8def\u7531\u503c\u7684\u503c\u8c03\u7528\u5355\u4e2a\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u3002\u5982\u679c\u672a\u627e\u5230\u9875\u9762\u5904\u7406\u7a0b\u5e8f\uff0c\u5219\u6539\u7528\u201c\u9690\u5f0f\u201d\u5904\u7406\u7a0b\u5e8f\uff0c\u53ea\u5448\u73b0 Razor Page \u7684\u5185\u5bb9\u3002<\/p>\n<p>Page handlers can have parameters whose values are taken from properties of the incoming request in a process called model binding. Properties decorated with [BindProperty] can also be bound to the request. These are the canonical ways of reading values from the HTTP request inside your Razor Page.<br \/>\n\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u53ef\u4ee5\u5177\u6709\u53c2\u6570\uff0c\u8fd9\u4e9b\u53c2\u6570\u7684\u503c\u53d6\u81ea\u79f0\u4e3a\u6a21\u578b\u7ed1\u5b9a\u7684\u8fdb\u7a0b\u4e2d\u4f20\u5165\u8bf7\u6c42\u7684\u5c5e\u6027\u3002\u4f7f\u7528 [BindProperty] \u4fee\u9970\u7684\u5c5e\u6027\u4e5f\u53ef\u4ee5\u7ed1\u5b9a\u5230\u8bf7\u6c42\u3002\u8fd9\u4e9b\u662f\u4ece Razor \u9875\u9762\u5185\u7684 HTTP \u8bf7\u6c42\u4e2d\u8bfb\u53d6\u503c\u7684\u89c4\u8303\u65b9\u6cd5\u3002<\/p>\n<p>By default, properties decorated with [BindProperty] are not bound for GET requests. To enable binding, use [BindProperty(SupportsGet = true)].<br \/>\n\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u4f7f\u7528 [BindProperty] \u4fee\u9970\u7684\u5c5e\u6027\u4e0d\u4f1a\u7ed1\u5b9a\u5230 GET \u8bf7\u6c42\u3002\u82e5\u8981\u542f\u7528\u7ed1\u5b9a\uff0c\u8bf7\u4f7f\u7528 [BindProperty\uff08SupportsGet = true\uff09]\u3002<\/p>\n<p>Page handlers can return a PageResult or void to generate an HTML response. The Razor Page infrastructure uses the associated Razor view to generate the HTML and returns a 200 OK response.<br \/>\n\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u53ef\u4ee5\u8fd4\u56de PageResult \u6216 void \u4ee5\u751f\u6210 HTML \u54cd\u5e94\u3002Razor \u9875\u9762\u57fa\u7840\u7ed3\u6784\u4f7f\u7528\u5173\u8054\u7684 Razor \u89c6\u56fe\u751f\u6210 HTML \u5e76\u8fd4\u56de 200 OK \u54cd\u5e94\u3002<\/p>\n<p>You can send users to a different Razor Page using a RedirectToPageResult. It\u2019s common to send users to a new page as part of the POST-REDIRECT-GET flow for handling user input via forms<br \/>\n\u60a8\u53ef\u4ee5\u4f7f\u7528 RedirectToPageResult \u5c06\u7528\u6237\u53d1\u9001\u5230\u4e0d\u540c\u7684 Razor \u9875\u9762\u3002\u5c06\u7528\u6237\u53d1\u9001\u5230\u65b0\u9875\u9762\u901a\u5e38\u662f\u901a\u8fc7 POST-REDIRECT-GET \u6d41\u7a0b\u5904\u7406\u7528\u6237\u8f93\u5165\u7684\u4e00\u90e8\u5206<\/p>\n<p>The PageModel base class exposes many helper methods for creating an IActionResult, such as Page() which creates a PageResult, and RedirectToPage() which creates a RedirectToPageResult. These methods are simple wrappers around calling new on the corresponding IActionResult type.<br \/>\nPageModel \u57fa\u7c7b\u516c\u5f00\u4e86\u8bb8\u591a\u7528\u4e8e\u521b\u5efa IActionResult \u7684\u5e2e\u52a9\u7a0b\u5e8f\u65b9\u6cd5\uff0c\u4f8b\u5982\u521b\u5efa PageResult \u7684 Page\uff08\uff09 \u548c\u7528\u4e8e\u521b\u5efa RedirectToPageResult \u7684 RedirectToPage\uff08\uff09\u3002\u8fd9\u4e9b\u65b9\u6cd5\u662f\u5bf9\u76f8\u5e94\u7684 IActionResult \u7c7b\u578b\u8c03\u7528 new \u7684\u7b80\u5355\u5305\u88c5\u5668\u3002<\/p>\n<p>StatusCodePagesMiddleware lets you provide user-friendly custom error handling messages when the pipeline returns a raw error response status code. This is important for providing a consistent user experience when status code errors are returned, such as 404 errors when a URL is not matched to an endpoint.<br \/>\nStatusCodePagesMiddleware \u5141\u8bb8\u60a8\u5728\u7ba1\u9053\u8fd4\u56de\u539f\u59cb\u9519\u8bef\u54cd\u5e94\u72b6\u6001\u4ee3\u7801\u65f6\u63d0\u4f9b\u7528\u6237\u53cb\u597d\u7684\u81ea\u5b9a\u4e49\u9519\u8bef\u5904\u7406\u6d88\u606f\u3002\u8fd9\u5bf9\u4e8e\u5728\u8fd4\u56de\u72b6\u6001\u4ee3\u7801\u9519\u8bef\u65f6\u63d0\u4f9b\u4e00\u81f4\u7684\u7528\u6237\u4f53\u9a8c\u975e\u5e38\u91cd\u8981\uff0c\u4f8b\u5982\uff0c\u5f53 URL \u4e0e\u7ec8\u7aef\u8282\u70b9\u4e0d\u5339\u914d\u65f6\u51fa\u73b0 404 \u9519\u8bef\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>15 Generating responses with page handlers in Razor Pages 15 \u5728 Razor Pages \u4e2d\u4f7f\u7528\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u751f\u6210\u54cd\u5e94 This chapter covers \u672c\u7ae0\u6db5\u76d6 \u2022 Selecting which page handler in a Razor Page to invoke for a request \u9009\u62e9\u8981\u4e3a\u8bf7\u6c42\u8c03\u7528\u7684 Razor \u9875\u9762\u4e2d\u7684\u9875\u9762\u5904\u7406\u7a0b\u5e8f \u2022 Returning an IActionResult from a page handler \u4ece\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u8fd4\u56de IActionResult \u2022 Handling status code errors with StatusCodePagesMiddleware \u4f7f\u7528 StatusCodePagesMiddleware \u5904\u7406\u72b6\u6001\u4ee3\u7801\u9519\u8bef [&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-601","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\/601","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=601"}],"version-history":[{"count":0,"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts\/601\/revisions"}],"wp:attachment":[{"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=601"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=601"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=601"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}