{"id":613,"date":"2025-04-05T11:42:18","date_gmt":"2025-04-05T03:42:18","guid":{"rendered":"https:\/\/www.hyy.net\/?p=613"},"modified":"2025-04-05T11:42:18","modified_gmt":"2025-04-05T03:42:18","slug":"asp-net-core-in-action-21-the-mvc-and-razor-pages-%ef%ac%81lter-pipeline","status":"publish","type":"post","link":"https:\/\/diji.net\/?p=613","title":{"rendered":"ASP.NET Core in Action 21 The MVC and Razor Pages \ufb01lter pipeline"},"content":{"rendered":"<p>21 The MVC and Razor Pages filter pipeline<br \/>\n21 MVC \u548c Razor Pages \u7b5b\u9009\u5668\u7ba1\u9053<\/p>\n<p>This chapter covers<br \/>\n\u672c\u7ae0\u6db5\u76d6<br \/>\n\u2022  The filter pipeline and how it differs from middleware<br \/>\n\u8fc7\u6ee4\u5668\u7ba1\u9053\u53ca\u5176\u4e0e\u4e2d\u95f4\u4ef6\u7684\u533a\u522b<br \/>\n\u2022  The different types of filters<br \/>\n\u8fc7\u6ee4\u5668\u7684\u4e0d\u540c\u7c7b\u578b\u7684<br \/>\n\u2022  Filter ordering<br \/>\n\u8fc7\u6ee4\u5668\u6392\u5e8f<\/p>\n<p>Part 3 of this book has covered the Model-View-Controller (MVC) and Razor Pages frameworks of ASP.NET Core in some detail. You learned how routing is used to select a Razor Page or action to execute. You also saw model binding, validation, and how to generate a response by returning an IActionResult from your actions and page handlers. In this chapter I\u2019m going to head deeper into the MVC\/Razor Pages frameworks and look at the filter pipeline, sometimes called the action invocation pipeline, which is analogous to the minimal API endpoint filter pipeline you learned about in chapter 5.<br \/>\n\u672c\u4e66\u7684\u7b2c 3 \u90e8\u5206\u8be6\u7ec6\u4ecb\u7ecd\u4e86 ASP.NET Core \u7684\u6a21\u578b-\u89c6\u56fe-\u63a7\u5236\u5668 \uff08MVC\uff09 \u548c Razor Pages \u6846\u67b6\u3002\u4f60\u4e86\u89e3\u4e86\u5982\u4f55\u4f7f\u7528\u8def\u7531\u6765\u9009\u62e9\u8981\u6267\u884c\u7684 Razor \u9875\u9762\u6216\u4f5c\u3002\u60a8\u8fd8\u4e86\u89e3\u4e86\u6a21\u578b\u7ed1\u5b9a\u3001\u9a8c\u8bc1\u4ee5\u53ca\u5982\u4f55\u901a\u8fc7\u4ece\u4f5c\u548c\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u8fd4\u56de IActionResult \u6765\u751f\u6210\u54cd\u5e94\u3002\u5728\u672c\u7ae0\u4e2d\uff0c\u6211\u5c06\u66f4\u6df1\u5165\u5730\u7814\u7a76 MVC\/Razor Pages \u6846\u67b6\uff0c\u5e76\u67e5\u770b\u7b5b\u9009\u5668\u7ba1\u9053\uff0c\u6709\u65f6\u79f0\u4e3a\u4f5c\u8c03\u7528\u7ba1\u9053\uff0c\u5b83\u7c7b\u4f3c\u4e8e\u60a8\u5728\u7b2c 5 \u7ae0\u4e2d\u4e86\u89e3\u7684\u6700\u5c0f API \u7aef\u70b9\u7b5b\u9009\u5668\u7ba1\u9053\u3002<\/p>\n<p>MVC and Razor Pages use several built-in filters to handle cross-cutting concerns, such as authorization (controlling which users can access which action methods and pages in your application). Any application that has the concept of users will use authorization filters as a minimum, but filters are much more powerful than this single use case. In sections 21.1 and 21.2 you\u2019ll learn about all the different types of filters and how they combine to create the MVC filter pipeline for a request that reaches the MVC or Razor Pages framework.<br \/>\nMVC \u548c Razor Pages \u4f7f\u7528\u591a\u4e2a\u5185\u7f6e\u7b5b\u9009\u5668\u6765\u5904\u7406\u6a2a\u5207\u5173\u6ce8\u70b9\uff0c\u4f8b\u5982\u6388\u6743\uff08\u63a7\u5236\u54ea\u4e9b\u7528\u6237\u53ef\u4ee5\u8bbf\u95ee\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u54ea\u4e9b\u4f5c\u65b9\u6cd5\u548c\u9875\u9762\uff09\u3002\u4efb\u4f55\u5177\u6709\u7528\u6237\u6982\u5ff5\u7684\u5e94\u7528\u7a0b\u5e8f\u90fd\u5c06\u81f3\u5c11\u4f7f\u7528\u6388\u6743\u8fc7\u6ee4\u5668\uff0c\u4f46\u8fc7\u6ee4\u5668\u6bd4\u8fd9\u4e2a\u5355\u4e00\u7528\u4f8b\u5f3a\u5927\u5f97\u591a\u3002\u5728\u7b2c 21.1 \u8282\u548c\u7b2c 21.2 \u8282\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3\u6240\u6709\u4e0d\u540c\u7c7b\u578b\u7684\u7b5b\u9009\u5668\uff0c\u4ee5\u53ca\u5b83\u4eec\u5982\u4f55\u7ec4\u5408\u8d77\u6765\u4e3a\u5230\u8fbe MVC \u6216 Razor Pages \u6846\u67b6\u7684\u8bf7\u6c42\u521b\u5efa MVC \u7b5b\u9009\u5668\u7ba1\u9053\u3002<\/p>\n<p>Think of the MVC filter pipeline as a mini middleware pipeline running inside the MVC and Razor Pages frameworks, like the minimal API endpoint filter pipeline. Like the middleware pipeline in ASP.NET Core, the MVC filter pipeline consists of a series of components connected as a pipe, so the output of one filter feeds into the input of the next. In section 21.3 we\u2019ll look at the similarities and differences between these two pipelines, and when you should choose one over the other.<br \/>\n\u5c06 MVC \u7b5b\u9009\u5668\u7ba1\u9053\u89c6\u4e3a\u5728 MVC \u548c Razor Pages \u6846\u67b6\u5185\u8fd0\u884c\u7684\u5fae\u578b\u4e2d\u95f4\u4ef6\u7ba1\u9053\uff0c\u5c31\u50cf\u6700\u5c0f API \u7ec8\u7ed3\u70b9\u7b5b\u9009\u5668\u7ba1\u9053\u4e00\u6837\u3002\u4e0e ASP.NET Core \u4e2d\u7684\u4e2d\u95f4\u4ef6\u7ba1\u9053\u4e00\u6837\uff0cMVC \u7b5b\u9009\u5668\u7ba1\u9053\u7531\u4e00\u7cfb\u5217\u4f5c\u4e3a\u7ba1\u9053\u8fde\u63a5\u7684\u7ec4\u4ef6\u7ec4\u6210\uff0c\u56e0\u6b64\u4e00\u4e2a\u7b5b\u9009\u5668\u7684\u8f93\u51fa\u4f1a\u9988\u9001\u5230\u4e0b\u4e00\u4e2a\u7b5b\u9009\u5668\u7684\u8f93\u5165\u4e2d\u3002\u5728 Section 21.3 \u4e2d\uff0c\u6211\u4eec\u5c06\u4e86\u89e3\u8fd9\u4e24\u4e2a pipelines \u4e4b\u95f4\u7684\u76f8\u4f3c\u4e4b\u5904\u548c\u4e0d\u540c\u4e4b\u5904\uff0c\u4ee5\u53ca\u4f55\u65f6\u5e94\u8be5\u9009\u62e9\u4e00\u4e2a\u800c\u4e0d\u662f\u53e6\u4e00\u4e2a\u3002<\/p>\n<p>In section 21.4 you\u2019ll see how to create a simple custom filter. Rather than focus on the functionality of the filter itself, you\u2019ll learn how to apply it to multiple endpoints in section 21.5. In section 21.6 you\u2019ll see how the choice of where you apply your attributes affects the order in which your filters execute.<br \/>\n\u5728 Section 21.4 \u4e2d\uff0c\u60a8\u5c06\u770b\u5230\u5982\u4f55\u521b\u5efa\u7b80\u5355\u7684\u81ea\u5b9a\u4e49\u8fc7\u6ee4\u5668\u3002\u60a8\u5c06\u5b66\u4e60 21.5 \u8282\u4e2d\u7684\u5982\u4f55\u5c06\u5b83\u5e94\u7528\u4e8e\u591a\u4e2a\u7aef\u70b9\uff0c\u800c\u4e0d\u662f\u5173\u6ce8\u8fc7\u6ee4\u5668\u672c\u8eab\u7684\u529f\u80fd\u3002\u5728 Section 21.6 \u4e2d\uff0c\u60a8\u5c06\u770b\u5230\u9009\u62e9\u5e94\u7528\u5c5e\u6027\u7684\u4f4d\u7f6e\u5982\u4f55\u5f71\u54cd\u8fc7\u6ee4\u5668\u7684\u6267\u884c\u987a\u5e8f\u3002<\/p>\n<p>The filter pipeline is a complex topic, but it can enable some advanced behaviors in your app and potentially reduce overall complexity. In this chapter you\u2019ll learn the basics of the pipeline and how it works. In chapter 22 we dig into practical examples of filters, looking at the filters that come out of the box in ASP.NET Core, as well as building custom filters to extract common code from your controllers and Razor Pages.<br \/>\n\u7b5b\u9009\u7ba1\u9053\u662f\u4e00\u4e2a\u590d\u6742\u7684\u4e3b\u9898\uff0c\u4f46\u5b83\u53ef\u4ee5\u5728\u60a8\u7684\u5e94\u7528\u4e2d\u542f\u7528\u4e00\u4e9b\u9ad8\u7ea7\u884c\u4e3a\uff0c\u5e76\u53ef\u80fd\u964d\u4f4e\u6574\u4f53\u590d\u6742\u6027\u3002\u5728\u672c\u7ae0\u4e2d\uff0c\u60a8\u5c06\u5b66\u4e60\u7ba1\u9053\u7684\u57fa\u7840\u77e5\u8bc6\u53ca\u5176\u5de5\u4f5c\u539f\u7406\u3002\u5728\u7b2c 22 \u7ae0\u4e2d\uff0c\u6211\u4eec\u6df1\u5165\u63a2\u8ba8\u4e86\u7b5b\u9009\u5668\u7684\u5b9e\u9645\u793a\u4f8b\uff0c\u67e5\u770b\u4e86 ASP.NET Core \u4e2d\u5f00\u7bb1\u5373\u7528\u7684\u7b5b\u9009\u5668\uff0c\u5e76\u6784\u5efa\u4e86\u81ea\u5b9a\u4e49\u7b5b\u9009\u5668\u4ee5\u4ece\u63a7\u5236\u5668\u548c Razor \u9875\u9762\u4e2d\u63d0\u53d6\u5e38\u89c1\u4ee3\u7801\u3002<\/p>\n<p>Before we can start writing code, we should get to grips with the basics of the filter pipeline. The first section of this chapter explains what the pipeline is, why you might want to use it, and how it differs from the middleware pipeline.<br \/>\n\u5728\u5f00\u59cb\u7f16\u5199\u4ee3\u7801\u4e4b\u524d\uff0c\u6211\u4eec\u5e94\u8be5\u5148\u4e86\u89e3\u8fc7\u6ee4\u5668\u7ba1\u9053\u7684\u57fa\u7840\u77e5\u8bc6\u3002\u672c\u7ae0\u7684\u7b2c\u4e00\u90e8\u5206\u4ecb\u7ecd\u4e86\u7ba1\u9053\u662f\u4ec0\u4e48\uff0c\u4e3a\u4ec0\u4e48\u60a8\u53ef\u80fd\u5e0c\u671b\u4f7f\u7528\u5b83\uff0c\u4ee5\u53ca\u5b83\u4e0e\u4e2d\u95f4\u4ef6\u7ba1\u9053\u6709\u4f55\u4e0d\u540c\u3002<\/p>\n<h2>21.1 Understanding the MVC filter pipeline<\/h2>\n<p>21.1 \u4e86\u89e3 MVC \u8fc7\u6ee4\u5668\u7ba1\u9053<\/p>\n<p>In this section you\u2019ll learn all about the MVC filter pipeline. You\u2019ll see where it fits in the life cycle of a typical request and the roles of the six types of filters available.<br \/>\n\u5728\u672c\u8282\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3\u6709\u5173 MVC \u7b5b\u9009\u5668\u7ba1\u9053\u7684\u6240\u6709\u4fe1\u606f\u3002\u60a8\u5c06\u770b\u5230\u5b83\u5728\u5178\u578b\u8bf7\u6c42\u7684\u751f\u547d\u5468\u671f\u4e2d\u7684\u4f4d\u7f6e\uff0c\u4ee5\u53ca\u53ef\u7528\u7684\u516d\u79cd\u7b5b\u9009\u5668\u7684\u89d2\u8272\u3002<\/p>\n<p>The filter pipeline is a relatively simple concept in that it provides hooks into the normal MVC request, as shown in figure 21.1. For example, say you wanted to ensure that users can create or edit products on an e-commerce app only if they\u2019re logged in. The app would redirect anonymous users to a login page instead of executing the action.<br \/>\n\u8fc7\u6ee4\u5668\u7ba1\u9053\u662f\u4e00\u4e2a\u76f8\u5bf9\u7b80\u5355\u7684\u6982\u5ff5\uff0c\u56e0\u4e3a\u5b83\u4e3a\u666e\u901a\u7684 MVC \u8bf7\u6c42\u63d0\u4f9b\u4e86\u94a9\u5b50\uff0c\u5982\u56fe 21.1 \u6240\u793a\u3002\u4f8b\u5982\uff0c\u5047\u8bbe\u60a8\u5e0c\u671b\u786e\u4fdd\u7528\u6237\u53ea\u6709\u5728\u767b\u5f55\u540e\u624d\u80fd\u5728\u7535\u5b50\u5546\u52a1\u5e94\u7528\u7a0b\u5e8f\u4e0a\u521b\u5efa\u6216\u7f16\u8f91\u4ea7\u54c1\u3002\u8be5\u5e94\u7528\u7a0b\u5e8f\u4f1a\u5c06\u533f\u540d\u7528\u6237\u91cd\u5b9a\u5411\u5230\u767b\u5f55\u9875\u9762\uff0c\u800c\u4e0d\u662f\u6267\u884c\u4f5c\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2101.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 21.1 Filters run at multiple points in the EndpointMiddleware as part of the normal handling of an MVC request. A similar pipeline exists for Razor Page requests.<br \/>\n\u56fe 21.1 \u8fc7\u6ee4\u5668\u5728 EndpointMiddleware \u4e2d\u7684\u591a\u4e2a\u70b9\u8fd0\u884c\uff0c\u4f5c\u4e3a MVC \u8bf7\u6c42\u7684\u6b63\u5e38\u5904\u7406\u7684\u4e00\u90e8\u5206\u3002Razor Page \u8bf7\u6c42\u5b58\u5728\u7c7b\u4f3c\u7684\u7ba1\u9053\u3002<\/p>\n<p>Without filters, you\u2019d need to include the same code to check for a logged-in user at the start of each specific action method. With this approach, the MVC framework would still execute the model binding and validation, even if the user were not logged in.<br \/>\n\u5982\u679c\u6ca1\u6709\u7b5b\u9009\u5668\uff0c\u5219\u9700\u8981\u5728\u6bcf\u4e2a\u7279\u5b9a\u4f5c\u65b9\u6cd5\u7684\u5f00\u5934\u5305\u542b\u76f8\u540c\u7684\u4ee3\u7801\u6765\u68c0\u67e5\u5df2\u767b\u5f55\u7684\u7528\u6237\u3002\u4f7f\u7528\u8fd9\u79cd\u65b9\u6cd5\uff0cMVC \u6846\u67b6\u4ecd\u5c06\u6267\u884c\u6a21\u578b\u7ed1\u5b9a\u548c\u9a8c\u8bc1\uff0c\u5373\u4f7f\u7528\u6237\u672a\u767b\u5f55\u3002<\/p>\n<p>With filters, you can use the hooks in the MVC request to run common code across all requests or a subset of requests. This way you can do a wide range of things, such as<br \/>\n\u501f\u52a9\u7b5b\u9009\u5668\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528 MVC \u8bf7\u6c42\u4e2d\u7684\u6302\u94a9\u5728\u6240\u6709\u8bf7\u6c42\u6216\u8bf7\u6c42\u5b50\u96c6\u4e2d\u8fd0\u884c\u901a\u7528\u4ee3\u7801\u3002\u901a\u8fc7\u8fd9\u79cd\u65b9\u5f0f\uff0c\u60a8\u53ef\u4ee5\u6267\u884c\u5404\u79cd\u4f5c\uff0c\u4f8b\u5982<\/p>\n<p>\u2022  Ensure that a user is logged in before an action method, model binding, or validation runs.<br \/>\n\u786e\u4fdd\u5728\u4f5c\u65b9\u6cd5\u3001\u6a21\u578b\u7ed1\u5b9a\u6216\u9a8c\u8bc1\u8fd0\u884c\u4e4b\u524d\u767b\u5f55\u7528\u6237\u3002<br \/>\n\u2022  Customize the output format of particular action methods.<br \/>\n\u81ea\u5b9a\u4e49\u7279\u5b9a\u4f5c\u65b9\u6cd5\u7684\u8f93\u51fa\u683c\u5f0f\u3002<br \/>\n\u2022  Handle model validation failures before an action method is invoked.<br \/>\n\u5728\u8c03\u7528\u4f5c\u65b9\u6cd5\u4e4b\u524d\u5904\u7406\u6a21\u578b\u9a8c\u8bc1\u5931\u8d25\u3002<br \/>\n\u2022  Catch exceptions from an action method and handle them in a special way.<br \/>\n\u4ece\u4f5c\u65b9\u6cd5\u6355\u83b7\u5f02\u5e38\uff0c\u5e76\u4ee5\u7279\u6b8a\u65b9\u5f0f\u5904\u7406\u5b83\u4eec\u3002<\/p>\n<p>In many ways, the MVC filter pipeline is like an extra middleware pipeline, restricted to MVC and Razor Pages requests only. Like middleware, filters are good for handling cross-cutting concerns for your application and are useful tools for reducing code duplication in many cases.<br \/>\n\u5728\u8bb8\u591a\u65b9\u9762\uff0cMVC \u7b5b\u9009\u5668\u7ba1\u9053\u5c31\u50cf\u4e00\u4e2a\u989d\u5916\u7684\u4e2d\u95f4\u4ef6\u7ba1\u9053\uff0c\u4ec5\u9650\u4e8e MVC \u548c Razor Pages \u8bf7\u6c42\u3002\u4e0e middleware \u4e00\u6837\uff0c\u8fc7\u6ee4\u5668\u975e\u5e38\u9002\u5408\u5904\u7406\u5e94\u7528\u7a0b\u5e8f\u7684\u6a2a\u5207\u5173\u6ce8\u70b9\uff0c\u5e76\u4e14\u5728\u8bb8\u591a\u60c5\u51b5\u4e0b\u662f\u51cf\u5c11\u4ee3\u7801\u91cd\u590d\u7684\u6709\u7528\u5de5\u5177\u3002<\/p>\n<p>The linear1 view of an MVC request and the filter pipeline that I\u2019ve used so far doesn\u2019t quite match up with how these filters execute. There are five types of filters that apply to MVC requests, each of which runs at a different stage in the MVC framework, as shown in figure 21.2.<br \/>\n\u5230\u76ee\u524d\u4e3a\u6b62\uff0c\u6211\u4f7f\u7528\u7684 MVC \u8bf7\u6c42\u7684 linear1 \u89c6\u56fe\u548c\u7b5b\u9009\u5668\u7ba1\u9053\u4e0e\u8fd9\u4e9b\u7b5b\u9009\u5668\u7684\u6267\u884c\u65b9\u5f0f\u5e76\u4e0d\u5b8c\u5168\u5339\u914d\u3002\u6709\u4e94\u79cd\u7c7b\u578b\u7684\u8fc7\u6ee4\u5668\u9002\u7528\u4e8e MVC \u8bf7\u6c42\uff0c\u6bcf\u4e00\u79cd\u90fd\u5728 MVC \u6846\u67b6\u7684\u4e0d\u540c\u9636\u6bb5\u8fd0\u884c\uff0c\u5982\u56fe 21.2 \u6240\u793a\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2102.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 21.2 The MVC filter pipeline, including the five filter stages. Some filter stages (resource, action, and result) run twice, before and after the remainder of the pipeline.<br \/>\n\u56fe 21.2 MVC \u8fc7\u6ee4\u5668\u7ba1\u9053\uff0c\u5305\u62ec 5 \u4e2a\u8fc7\u6ee4\u5668\u9636\u6bb5\u3002\u67d0\u4e9b\u7b5b\u9009\u9636\u6bb5\uff08resource\u3001action \u548c result\uff09\u5728\u7ba1\u9053\u7684\u5176\u4f59\u90e8\u5206\u4e4b\u524d\u548c\u4e4b\u540e\u8fd0\u884c\u4e24\u6b21\u3002<\/p>\n<p>Each filter stage lends itself to a particular use case, thanks to its specific location in the pipeline, with respect to model binding, action execution, and result execution:<br \/>\n\u6bcf\u4e2a\u8fc7\u6ee4\u5668\u9636\u6bb5\u90fd\u9002\u7528\u4e8e\u7279\u5b9a\u7684\u7528\u4f8b\uff0c\u8fd9\u8981\u5f52\u529f\u4e8e\u5b83\u5728\u7ba1\u9053\u4e2d\u7684\u7279\u5b9a\u4f4d\u7f6e\uff0c\u5305\u62ec\u6a21\u578b\u7ed1\u5b9a\u3001\u4f5c\u6267\u884c\u548c\u7ed3\u679c\u6267\u884c\uff1a<\/p>\n<p>\u2022  Authorization filters\u2014These run first in the pipeline, so they\u2019re useful for protecting your APIs and action methods. If an authorization filter deems the request unauthorized, it short-circuits the request, preventing the rest of the filter pipeline (or action) from running.<br \/>\n\u6388\u6743\u8fc7\u6ee4\u5668 - \u8fd9\u4e9b\u8fc7\u6ee4\u5668\u9996\u5148\u5728\u7ba1\u9053\u4e2d\u8fd0\u884c\uff0c\u56e0\u6b64\u5b83\u4eec\u53ef\u7528\u4e8e\u4fdd\u62a4\u60a8\u7684 API \u548c\u4f5c\u65b9\u6cd5\u3002\u5982\u679c\u6388\u6743\u7b5b\u9009\u6761\u4ef6\u8ba4\u4e3a\u8bf7\u6c42\u672a\u7ecf\u6388\u6743\uff0c\u5219\u4f1a\u4f7f\u8bf7\u6c42\u77ed\u8def\uff0c\u4ece\u800c\u963b\u6b62\u7b5b\u9009\u6761\u4ef6\u7ba1\u9053\uff08\u6216\u4f5c\uff09\u7684\u5176\u4f59\u90e8\u5206\u8fd0\u884c\u3002<br \/>\n\u2022  Resource filters\u2014After authorization, resource filters are the next filters to run in the pipeline. They can also execute at the end of the pipeline, in much the same way that middleware components can handle both the incoming request and the outgoing response. Alternatively, resource filters can completely short-circuit the request pipeline and return a response directly.<br \/>\n\u8d44\u6e90\u8fc7\u6ee4\u5668 - \u6388\u6743\u540e\uff0c\u8d44\u6e90\u8fc7\u6ee4\u5668\u662f\u7ba1\u9053\u4e2d\u8fd0\u884c\u7684\u4e0b\u4e00\u4e2a\u8fc7\u6ee4\u5668\u3002\u5b83\u4eec\u8fd8\u53ef\u4ee5\u5728\u7ba1\u9053\u7684\u672b\u5c3e\u6267\u884c\uff0c\u5c31\u50cf\u4e2d\u95f4\u4ef6\u7ec4\u4ef6\u53ef\u4ee5\u540c\u65f6\u5904\u7406\u4f20\u5165\u8bf7\u6c42\u548c\u4f20\u51fa\u54cd\u5e94\u4e00\u6837\u3002\u6216\u8005\uff0c\u8d44\u6e90\u7b5b\u9009\u6761\u4ef6\u53ef\u4ee5\u5b8c\u5168\u77ed\u8def\u8bf7\u6c42\u7ba1\u9053\u5e76\u76f4\u63a5\u8fd4\u56de\u54cd\u5e94\u3002<\/p>\n<p>Thanks to their early position in the pipeline, resource filters can have a variety of uses. You could add metrics to an action method; prevent an action method from executing if an unsupported content type is requested; or, as they run before model binding, control the way model binding works for that request.<br \/>\n\u7531\u4e8e\u5b83\u4eec\u5728\u7ba1\u9053\u4e2d\u7684\u65e9\u671f\u4f4d\u7f6e\uff0c\u8d44\u6e90\u8fc7\u6ee4\u5668\u53ef\u4ee5\u6709\u591a\u79cd\u7528\u9014\u3002\u60a8\u53ef\u4ee5\u5411\u4f5c\u65b9\u6cd5\u6dfb\u52a0\u5ea6\u91cf;\u5728\u8bf7\u6c42\u4e0d\u53d7\u652f\u6301\u7684\u5185\u5bb9\u7c7b\u578b\u65f6\u963b\u6b62\u6267\u884c\u4f5c\u65b9\u6cd5;\u6216\u8005\uff0c\u5f53\u5b83\u4eec\u5728\u6a21\u578b\u7ed1\u5b9a\u4e4b\u524d\u8fd0\u884c\u65f6\uff0c\u63a7\u5236\u6a21\u578b\u7ed1\u5b9a\u5bf9\u8be5\u8bf7\u6c42\u7684\u5de5\u4f5c\u65b9\u5f0f\u3002<\/p>\n<p>\u2022  Action filters\u2014Action filters run immediately before and after an action method is executed. As model binding has already happened, action filters let you manipulate the arguments to the method\u2014before it executes\u2014or they can short-circuit the action completely and return a different IActionResult. Because they also run after the action executes, they can optionally customize an IActionResult returned by the action before the action result is executed.<br \/>\n\u4f5c\u7b5b\u9009\u5668 -\u4f5c\u7b5b\u9009\u5668\u5728\u6267\u884c\u4f5c\u65b9\u6cd5\u4e4b\u524d\u548c\u4e4b\u540e\u7acb\u5373\u8fd0\u884c\u3002\u7531\u4e8e\u6a21\u578b\u7ed1\u5b9a\u5df2\u7ecf\u53d1\u751f\uff0c\u56e0\u6b64\u4f5c\u7b5b\u9009\u5668\u5141\u8bb8\u60a8\u5728\u65b9\u6cd5\u6267\u884c\u4e4b\u524d\u4f5c\u65b9\u6cd5\u7684\u53c2\u6570\uff0c\u6216\u8005\u5b83\u4eec\u53ef\u4ee5\u5b8c\u5168\u77ed\u8def\u4f5c\u5e76\u8fd4\u56de\u4e0d\u540c\u7684 IActionResult\u3002\u7531\u4e8e\u5b83\u4eec\u4e5f\u5728\u4f5c\u6267\u884c\u540e\u8fd0\u884c\uff0c\u56e0\u6b64\u53ef\u4ee5\u9009\u62e9\u5728\u6267\u884c\u4f5c\u7ed3\u679c\u4e4b\u524d\u81ea\u5b9a\u4e49\u4f5c\u8fd4\u56de\u7684 IActionResult\u3002<br \/>\n\u2022  Exception filters\u2014Exception filters catch exceptions that occur in the filter pipeline and handle them appropriately. You can use exception filters to write custom, MVC-specific error-handling code, which can be useful in some situations. For example, you could catch exceptions in API actions and format them differently from exceptions in your Razor Pages.<br \/>\n\u5f02\u5e38\u8fc7\u6ee4\u5668 - \u5f02\u5e38\u8fc7\u6ee4\u5668\u53ef\u6355\u83b7\u8fc7\u6ee4\u5668\u7ba1\u9053\u4e2d\u53d1\u751f\u7684\u5f02\u5e38\u5e76\u5bf9\u5176\u8fdb\u884c\u9002\u5f53\u5904\u7406\u3002\u60a8\u53ef\u4ee5\u4f7f\u7528\u5f02\u5e38\u7b5b\u9009\u5668\u7f16\u5199\u7279\u5b9a\u4e8e MVC \u7684\u81ea\u5b9a\u4e49\u9519\u8bef\u5904\u7406\u4ee3\u7801\uff0c\u8fd9\u5728\u67d0\u4e9b\u60c5\u51b5\u4e0b\u53ef\u80fd\u5f88\u6709\u7528\u3002\u4f8b\u5982\uff0c\u53ef\u4ee5\u5728 API\u4f5c\u4e2d\u6355\u83b7\u5f02\u5e38\uff0c\u5e76\u5bf9\u5176\u8fdb\u884c\u4e0d\u540c\u4e8e Razor Pages \u4e2d\u7684\u5f02\u5e38\u683c\u5f0f\u8bbe\u7f6e\u3002<br \/>\n\u2022  Result filters\u2014Result filters run before and after an action method\u2019s IActionResult is executed. You can use result filters to control the execution of the result or even to short-circuit the execution of the result.<br \/>\n\u7ed3\u679c\u7b5b\u9009\u5668 - \u7ed3\u679c\u7b5b\u9009\u5668\u5728\u6267\u884c\u4f5c\u65b9\u6cd5\u7684 IActionResult \u4e4b\u524d\u548c\u4e4b\u540e\u8fd0\u884c\u3002\u60a8\u53ef\u4ee5\u4f7f\u7528\u7ed3\u679c\u7b5b\u9009\u5668\u6765\u63a7\u5236\u7ed3\u679c\u7684\u6267\u884c\uff0c\u751a\u81f3\u53ef\u4ee5\u7f29\u77ed\u7ed3\u679c\u7684\u6267\u884c\u3002<\/p>\n<p>Exactly which filter you pick to implement will depend on the functionality you\u2019re trying to introduce. Want to short-circuit a request as early as possible? Resource filters are a good fit. Need access to the action method parameters? Use an action filter.<br \/>\n\u60a8\u9009\u62e9\u5b9e\u65bd\u54ea\u4e2a\u8fc7\u6ee4\u5668\u5c06\u53d6\u51b3\u4e8e\u60a8\u5c1d\u8bd5\u5f15\u5165\u7684\u529f\u80fd\u3002\u60f3\u8981\u5c3d\u65e9\u4f7f\u8bf7\u6c42\u77ed\u8def\uff1f\u8d44\u6e90\u7b5b\u9009\u5668\u975e\u5e38\u9002\u5408\u3002\u9700\u8981\u8bbf\u95ee\u4f5c\u65b9\u6cd5\u53c2\u6570\uff1f\u4f7f\u7528\u4f5c\u7b5b\u9009\u5668\u3002<\/p>\n<p>Think of the filter pipeline as a small middleware pipeline that lives by itself in the MVC framework. Alternatively, you could think of filters as hooks into the MVC action invocation process that let you run code at a particular point in a request\u2019s life cycle.<br \/>\n\u5c06\u8fc7\u6ee4\u5668\u7ba1\u9053\u89c6\u4e3a\u4e00\u4e2a\u5c0f\u578b\u4e2d\u95f4\u4ef6\u7ba1\u9053\uff0c\u5b83\u72ec\u7acb\u5b58\u5728\u4e8e MVC \u6846\u67b6\u4e2d\u3002\u6216\u8005\uff0c\u60a8\u53ef\u4ee5\u5c06\u7b5b\u9009\u5668\u89c6\u4e3a MVC\u4f5c\u8c03\u7528\u8fc7\u7a0b\u7684\u6302\u94a9\uff0c\u5141\u8bb8\u60a8\u5728\u8bf7\u6c42\u751f\u547d\u5468\u671f\u7684\u7279\u5b9a\u70b9\u8fd0\u884c\u4ee3\u7801\u3002<\/p>\n<p><b>NOTE<\/b> The design of the MVC filter pipeline is quite different from the minimal API endpoint filter pipeline you saw in chapter 5. The endpoint filter pipeline is linear and doesn\u2019t have multiple types of filters.<br \/>\n\u6ce8\u610f:MVC \u8fc7\u6ee4\u5668\u7ba1\u9053\u7684\u8bbe\u8ba1\u4e0e\u60a8\u5728\u7b2c 5 \u7ae0\u4e2d\u770b\u5230\u7684\u6700\u5c0f API \u7aef\u70b9\u8fc7\u6ee4\u5668\u7ba1\u9053\u5b8c\u5168\u4e0d\u540c\u3002\u7ec8\u7aef\u8282\u70b9\u7b5b\u9009\u6761\u4ef6\u7ba1\u9053\u662f\u7ebf\u6027\u7684\uff0c\u6ca1\u6709\u591a\u79cd\u7c7b\u578b\u7684\u7b5b\u9009\u6761\u4ef6\u3002<\/p>\n<p>This section described how the filter pipeline works for MVC and Web API controllers; Razor Pages use an almost-identical filter pipeline.<br \/>\n\u672c\u90e8\u5206\u4ecb\u7ecd\u4e86\u7b5b\u9009\u5668\u7ba1\u9053\u5982\u4f55\u7528\u4e8e MVC \u548c Web API \u63a7\u5236\u5668;Razor Pages \u4f7f\u7528\u51e0\u4e4e\u76f8\u540c\u7684\u7b5b\u9009\u7ba1\u9053\u3002<\/p>\n<h2>21.2 The Razor Pages filter pipeline<\/h2>\n<p>21.2 Razor Pages \u7b5b\u9009\u5668\u7ba1\u9053<\/p>\n<p>The Razor Pages framework uses the same underlying architecture as MVC and Web API controllers, so it\u2019s perhaps not surprising that the filter pipeline is virtually identical. The only difference between the pipelines is that Razor Pages do not use action filters. Instead, they use page filters, as shown in figure 21.3.<br \/>\nRazor Pages \u6846\u67b6\u4f7f\u7528\u4e0e MVC \u548c Web API \u63a7\u5236\u5668\u76f8\u540c\u7684\u5e95\u5c42\u4f53\u7cfb\u7ed3\u6784\uff0c\u56e0\u6b64\u7b5b\u9009\u5668\u7ba1\u9053\u51e0\u4e4e\u76f8\u540c\u53ef\u80fd\u4e0d\u8db3\u4e3a\u5947\u3002\u7ba1\u9053\u4e4b\u95f4\u7684\u552f\u4e00\u533a\u522b\u662f Razor Pages \u4e0d\u4f7f\u7528\u4f5c\u7b5b\u9009\u5668\u3002\u76f8\u53cd\uff0c\u5b83\u4eec\u4f7f\u7528\u9875\u9762\u8fc7\u6ee4\u5668\uff0c\u5982\u56fe 21.3 \u6240\u793a\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2103.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 21.3 The Razor Pages filter pipeline, including the five filter stages. Authorization, resource, exception, and result filters execute in exactly the same way as for the MVC pipeline. Page filters are specific to Razor Pages and execute in three places: after page hander selection, after model binding and validation, and after page handler execution.<br \/>\n\u56fe 21.3 Razor Pages \u7b5b\u9009\u5668\u7ba1\u9053\uff0c\u5305\u62ec 5 \u4e2a\u7b5b\u9009\u5668\u9636\u6bb5\u3002\u6388\u6743\u3001\u8d44\u6e90\u3001\u5f02\u5e38\u548c\u7ed3\u679c\u7b5b\u9009\u5668\u7684\u6267\u884c\u65b9\u5f0f\u4e0e MVC \u7ba1\u9053\u7684\u6267\u884c\u65b9\u5f0f\u5b8c\u5168\u76f8\u540c\u3002\u9875\u9762\u7b5b\u9009\u5668\u7279\u5b9a\u4e8e Razor \u9875\u9762\uff0c\u5e76\u5728\u4e09\u4e2a\u4f4d\u7f6e\u6267\u884c\uff1a\u9009\u62e9\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u540e\u3001\u6a21\u578b\u7ed1\u5b9a\u548c\u9a8c\u8bc1\u540e\u4ee5\u53ca\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u6267\u884c\u540e\u3002<\/p>\n<p>The authorization, resource, exception, and result filters are exactly the same filters you saw for the MVC pipeline. They execute in the same way, serve the same purposes, and can be short-circuited in the same way.<br \/>\nauthorization\u3001resource\u3001exception \u548c result \u8fc7\u6ee4\u5668\u4e0e\u60a8\u5728 MVC \u7ba1\u9053\u4e2d\u770b\u5230\u7684\u8fc7\u6ee4\u5668\u5b8c\u5168\u76f8\u540c\u3002\u5b83\u4eec\u4ee5\u76f8\u540c\u7684\u65b9\u5f0f\u6267\u884c\uff0c\u670d\u52a1\u4e8e\u76f8\u540c\u7684\u76ee\u7684\uff0c\u5e76\u4e14\u53ef\u4ee5\u4ee5\u76f8\u540c\u7684\u65b9\u5f0f\u77ed\u8def\u3002<\/p>\n<p><b>NOTE<\/b> These filters are literally the same classes shared between the Razor Pages and MVC frameworks.<br \/>\n\u6ce8\u610f:\u8fd9\u4e9b\u7b5b\u9009\u5668\u5b9e\u9645\u4e0a\u662f Razor Pages \u548c MVC \u6846\u67b6\u4e4b\u95f4\u5171\u4eab\u7684\u76f8\u540c\u7c7b\u3002<\/p>\n<p>The difference with the Razor Pages filter pipeline is that it uses page filters instead of action filters. By contrast with other filter types, page filters run three times in the filter pipeline:<br \/>\n\u4e0e Razor Pages \u7b5b\u9009\u5668\u7ba1\u9053\u7684\u4e0d\u540c\u4e4b\u5904\u5728\u4e8e\uff0c\u5b83\u4f7f\u7528\u9875\u9762\u7b5b\u9009\u5668\u800c\u4e0d\u662f\u4f5c\u7b5b\u9009\u5668\u3002\u4e0e\u5176\u4ed6\u7b5b\u9009\u5668\u7c7b\u578b\u76f8\u6bd4\uff0c\u9875\u9762\u7b5b\u9009\u5668\u5728\u7b5b\u9009\u5668\u7ba1\u9053\u4e2d\u8fd0\u884c\u4e09\u6b21\uff1a<\/p>\n<p>\u2022  After page handler selection\u2014After the resource filters have executed, a page handler is selected, based on the request\u2019s HTTP verb and the {handler} route value, as you learned in chapter 15. After page handler selection, a page filter method executes for the first time. You can\u2019t short-circuit the pipeline at this stage, and model binding and validation have not yet executed.<br \/>\n\u9009\u62e9\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u540e - \u6267\u884c\u8d44\u6e90\u8fc7\u6ee4\u5668\u540e\uff0c\u5c06\u6839\u636e\u8bf7\u6c42\u7684 HTTP \u52a8\u8bcd\u548c {handler} \u8def\u7531\u503c\u9009\u62e9\u9875\u9762\u5904\u7406\u7a0b\u5e8f\uff0c\u5982\u7b2c 15 \u7ae0\u6240\u8ff0\u3002\u9009\u62e9\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u540e\uff0c\u5c06\u9996\u6b21\u6267\u884c\u9875\u9762\u7b5b\u9009\u65b9\u6cd5\u3002\u5728\u6b64\u9636\u6bb5\uff0c\u60a8\u4e0d\u80fd\u4f7f\u7ba1\u9053\u77ed\u8def\uff0c\u5e76\u4e14\u6a21\u578b\u7ed1\u5b9a\u548c\u9a8c\u8bc1\u5c1a\u672a\u6267\u884c\u3002<\/p>\n<p>\u2022  After model binding\u2014After the first page filter execution, the request is model-bound to the Razor Page\u2019s binding models and is validated. This execution is highly analogous to the action filter execution for API controllers. At this point you could manipulate the model-bound data or short-circuit the page handler execution completely by returning a different IActionResult.<br \/>\n\u6a21\u578b\u7ed1\u5b9a\u540e - \u5728\u6267\u884c\u7b2c\u4e00\u4e2a\u9875\u9762\u7b5b\u9009\u5668\u540e\uff0c\u8bf7\u6c42\u5c06\u6a21\u578b\u7ed1\u5b9a\u5230 Razor \u9875\u9762\u7684\u7ed1\u5b9a\u6a21\u578b\u5e76\u8fdb\u884c\u9a8c\u8bc1\u3002\u6b64\u6267\u884c\u4e0e API \u63a7\u5236\u5668\u7684 action filter \u6267\u884c\u9ad8\u5ea6\u76f8\u4f3c\u3002\u6b64\u65f6\uff0c\u60a8\u53ef\u4ee5\u901a\u8fc7\u8fd4\u56de\u4e0d\u540c\u7684 IActionResult \u6765\u4f5c\u6a21\u578b\u7ed1\u5b9a\u6570\u636e\u6216\u5b8c\u5168\u77ed\u8def\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u6267\u884c\u3002<\/p>\n<p>\u2022  After page handler execution\u2014If you don\u2019t short-circuit the page handler execution, the page filter runs a third and final time after the page handler has executed. At this point you could customize the IActionResult returned by the page handler before the result is executed.<br \/>\n\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u6267\u884c\u540e - \u5982\u679c\u4e0d\u4f7f\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u6267\u884c\u77ed\u8def\uff0c\u5219\u9875\u9762\u8fc7\u6ee4\u5668\u5c06\u5728\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u6267\u884c\u540e\u7b2c\u4e09\u6b21\u4e5f\u662f\u6700\u540e\u4e00\u6b21\u8fd0\u884c\u3002\u6b64\u65f6\uff0c\u60a8\u53ef\u4ee5\u5728\u6267\u884c\u7ed3\u679c\u4e4b\u524d\u81ea\u5b9a\u4e49\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u8fd4\u56de\u7684 IActionResult\u3002<\/p>\n<p>The triple execution of page filters makes it a bit harder to visualize the pipeline, but you can generally think of them as beefed-up action filters. Everything you can do with an action filter, you can do with a page filter, and you can hook in after page handler selection if necessary.<br \/>\n\u9875\u9762\u8fc7\u6ee4\u5668\u7684\u4e09\u91cd\u6267\u884c\u4f7f\u5f97\u53ef\u89c6\u5316\u7ba1\u9053\u6709\u70b9\u56f0\u96be\uff0c\u4f46\u60a8\u901a\u5e38\u53ef\u4ee5\u5c06\u5b83\u4eec\u89c6\u4e3a\u589e\u5f3a\u7684\u4f5c\u8fc7\u6ee4\u5668\u3002\u4f60\u53ef\u4ee5\u7528 action filter \u505a\u7684\u6240\u6709\u4e8b\u60c5\uff0c\u90fd\u53ef\u4ee5\u7528 page filter \u505a\uff0c\u5982\u679c\u9700\u8981\uff0c\u4f60\u53ef\u4ee5\u5728 Page handler \u9009\u62e9\u540e\u6302\u63a5\u3002<\/p>\n<p><b>Tip<\/b> Each execution of a filter executes a different method of the appropriate interface, so it\u2019s easy to know where you are in the pipeline and to execute a filter in only one of its possible locations if you wish.<br \/>\n\u63d0\u793a:\u6bcf\u6b21\u6267\u884c\u7b5b\u9009\u6761\u4ef6\u90fd\u4f1a\u6267\u884c\u76f8\u5e94\u63a5\u53e3\u7684\u4e0d\u540c\u65b9\u6cd5\uff0c\u56e0\u6b64\u5f88\u5bb9\u6613\u77e5\u9053\u60a8\u5728\u7ba1\u9053\u4e2d\u7684\u4f4d\u7f6e\uff0c\u5e76\u4e14\u5982\u679c\u60a8\u613f\u610f\uff0c\u53ea\u9700\u5728\u5176\u4e00\u4e2a\u53ef\u80fd\u7684\u4f4d\u7f6e\u6267\u884c\u7b5b\u9009\u6761\u4ef6\u3002<\/p>\n<p>One of the main questions I hear when people learn about filters in ASP.NET Core is \u201cWhy do we need them?\u201d If the filter pipeline is like a mini middleware pipeline, why not use a middleware component directly, instead of introducing the filter concept? That\u2019s an excellent point, which I\u2019ll tackle in the next section.<br \/>\n\u5f53\u4eba\u4eec\u4e86\u89e3 ASP.NET Core \u4e2d\u7684\u8fc7\u6ee4\u5668\u65f6\uff0c\u6211\u542c\u5230\u7684\u4e3b\u8981\u95ee\u9898\u4e4b\u4e00\u662f\u201c\u6211\u4eec\u4e3a\u4ec0\u4e48\u9700\u8981\u5b83\u4eec\uff1f\u5982\u679c filter pipeline \u5c31\u50cf\u4e00\u4e2a\u8ff7\u4f60\u7684 middleware pipeline \uff0c\u4e3a\u4ec0\u4e48\u4e0d\u76f4\u63a5\u4f7f\u7528\u4e00\u4e2a middleware \u7ec4\u4ef6\uff0c\u800c\u4e0d\u662f\u5f15\u5165 filter \u6982\u5ff5\u5462\uff1f\u8fd9\u662f\u4e00\u4e2a\u5f88\u597d\u7684\u89c2\u70b9\uff0c\u6211\u5c06\u5728\u4e0b\u4e00\u8282\u4e2d\u8ba8\u8bba\u3002<\/p>\n<h2>21.3 Filters or middleware: Which should you choose?<\/h2>\n<p>21.3 \u8fc7\u6ee4\u5668\u6216\u4e2d\u95f4\u4ef6\uff1a\u60a8\u5e94\u8be5\u9009\u62e9\u54ea\u4e2a\uff1f<\/p>\n<p>The filter pipeline is similar to the middleware pipeline in many ways, but there are several subtle differences that you should consider when deciding which approach to use. The considerations are essentially the same as those for the minimal API endpoint filter I discussed in chapter 5. MVC filters and middleware are similar in three ways:<br \/>\nfilter \u7ba1\u9053\u5728\u8bb8\u591a\u65b9\u9762\u4e0e\u4e2d\u95f4\u4ef6\u7ba1\u9053\u76f8\u4f3c\uff0c\u4f46\u5728\u51b3\u5b9a\u4f7f\u7528\u54ea\u79cd\u65b9\u6cd5\u65f6\uff0c\u5e94\u8003\u8651\u51e0\u4e2a\u7ec6\u5fae\u7684\u5dee\u5f02\u3002\u8fd9\u4e9b\u6ce8\u610f\u4e8b\u9879\u4e0e\u6211\u5728\u7b2c 5 \u7ae0\u4e2d\u8ba8\u8bba\u7684\u6700\u5c0f API \u7aef\u70b9\u8fc7\u6ee4\u5668\u7684\u6ce8\u610f\u4e8b\u9879\u57fa\u672c\u76f8\u540c\u3002MVC \u7b5b\u9009\u5668\u548c\u4e2d\u95f4\u4ef6\u5728\u4e09\u4e2a\u65b9\u9762\u76f8\u4f3c\uff1a<\/p>\n<p>\u2022  Requests pass through a middleware component on the way \u201cin,\u201d and responses pass through again on the way \u201cout.\u201d Resource, action, and result filters are also two-way, though authorization and exception filters run only once for a request, and page filters run three times.<br \/>\n\u8bf7\u6c42\u5728\u201cin\u201d\u9014\u4e2d\u901a\u8fc7\u4e2d\u95f4\u4ef6\u7ec4\u4ef6\uff0c\u54cd\u5e94\u5728\u201cout\u201d\u9014\u4e2d\u518d\u6b21\u4f20\u9012\u3002\u8d44\u6e90\u3001\u4f5c\u548c\u7ed3\u679c\u7b5b\u9009\u5668\u4e5f\u662f\u53cc\u5411\u7684\uff0c\u4f46\u6388\u6743\u548c\u5f02\u5e38\u7b5b\u9009\u5668\u53ea\u4e3a\u8bf7\u6c42\u8fd0\u884c\u4e00\u6b21\uff0c\u800c\u9875\u9762\u7b5b\u9009\u5668\u8fd0\u884c\u4e09\u6b21\u3002<br \/>\n\u2022  Middleware can short-circuit a request by returning a response instead of passing it on to later middleware. MVC and page filters can also short-circuit the filter pipeline by returning a response.<br \/>\n\u4e2d\u95f4\u4ef6\u53ef\u4ee5\u901a\u8fc7\u8fd4\u56de\u54cd\u5e94\u800c\u4e0d\u662f\u5c06\u5176\u4f20\u9012\u7ed9\u540e\u7eed\u4e2d\u95f4\u4ef6\u6765\u4f7f\u8bf7\u6c42\u77ed\u8def\u3002MVC \u548c\u9875\u9762\u7b5b\u9009\u5668\u8fd8\u53ef\u4ee5\u901a\u8fc7\u8fd4\u56de\u54cd\u5e94\u6765\u4f7f\u7b5b\u9009\u5668\u7ba1\u9053\u77ed\u8def\u3002<br \/>\n\u2022  Middleware is often used for cross-cutting application concerns, such as logging, performance profiling, and exception handling. Filters also lend themselves to cross-cutting concerns.<br \/>\n\u4e2d\u95f4\u4ef6\u901a\u5e38\u7528\u4e8e\u6a2a\u5207\u5e94\u7528\u7a0b\u5e8f\u95ee\u9898\uff0c\u4f8b\u5982\u65e5\u5fd7\u8bb0\u5f55\u3001\u6027\u80fd\u5206\u6790\u548c\u5f02\u5e38\u5904\u7406\u3002\u8fc7\u6ee4\u5668\u8fd8\u9002\u7528\u4e8e\u6a2a\u5207\u5173\u6ce8\u70b9\u3002<\/p>\n<p>Filters and middleware also differ primarily in three ways:<br \/>\n\u7b5b\u9009\u5668\u548c\u4e2d\u95f4\u4ef6\u4e5f\u4e3b\u8981\u5728\u4e09\u4e2a\u65b9\u9762\u6709\u6240\u4e0d\u540c\uff1a<\/p>\n<p>\u2022  Middleware can run for all requests; filters run only for requests that reach the EndpointMiddleware and execute a controller action or Razor Page handler.<br \/>\n\u4e2d\u95f4\u4ef6\u53ef\u4ee5\u9488\u5bf9\u6240\u6709\u8bf7\u6c42\u8fd0\u884c\u7b5b\u9009\u5668\u4ec5\u9488\u5bf9\u5230\u8fbe EndpointMiddleware \u5e76\u6267\u884c\u63a7\u5236\u5668\u4f5c\u6216 Razor Page \u5904\u7406\u7a0b\u5e8f\u7684\u8bf7\u6c42\u8fd0\u884c\u3002<br \/>\n\u2022  Filters have access to MVC constructs such as ModelState and IActionResults. Middleware in general is independent from MVC and Razor Pages and works at a lower level, so it can\u2019t use these concepts.<br \/>\n\u7b5b\u9009\u5668\u53ef\u4ee5\u8bbf\u95ee MVC \u6784\u9020\uff0c\u4f8b\u5982 ModelState \u548c IActionResults\u3002\u4e2d\u95f4\u4ef6\u901a\u5e38\u72ec\u7acb\u4e8e MVC \u548c Razor Pages\uff0c\u5e76\u4e14\u5728\u8f83\u4f4e\u7ea7\u522b\u5de5\u4f5c\uff0c\u56e0\u6b64\u5b83\u4e0d\u80fd\u4f7f\u7528\u8fd9\u4e9b\u6982\u5ff5\u3002<br \/>\n\u2022  Filters can be easily applied to a subset of requests, such as all actions on a single controller or a single Razor Page. Middleware generally applies to all requests that reach a given point in the middleware pipeline.<br \/>\n\u7b5b\u9009\u5668\u53ef\u4ee5\u8f7b\u677e\u5e94\u7528\u4e8e\u8bf7\u6c42\u7684\u5b50\u96c6\uff0c\u4f8b\u5982\u5355\u4e2a\u63a7\u5236\u5668\u6216\u5355\u4e2a Razor \u9875\u9762\u4e0a\u7684\u6240\u6709\u4f5c\u3002\u4e2d\u95f4\u4ef6\u901a\u5e38\u9002\u7528\u4e8e\u5230\u8fbe\u4e2d\u95f4\u4ef6\u7ba1\u9053\u4e2d\u7ed9\u5b9a\u70b9\u7684\u6240\u6709\u8bf7\u6c42\u3002<\/p>\n<p>As for the endpoint filter pipeline, I like to think of middleware versus MVC filters as a question of specificity. Middleware is the more general concept, so it has the wider reach. But if you need to access to MVC constructs or want to behave differently for some MVC actions or Razor Pages, you should consider using a filter.<br \/>\n\u81f3\u4e8e\u7aef\u70b9\u8fc7\u6ee4\u5668\u7ba1\u9053\uff0c\u6211\u559c\u6b22\u5c06\u4e2d\u95f4\u4ef6\u4e0e MVC \u8fc7\u6ee4\u5668\u89c6\u4e3a\u4e00\u4e2a\u7279\u5f02\u6027\u95ee\u9898\u3002\u4e2d\u95f4\u4ef6\u662f\u66f4\u901a\u7528\u7684\u6982\u5ff5\uff0c\u56e0\u6b64\u5b83\u7684\u8303\u56f4\u66f4\u5e7f\u3002\u4f46\u662f\uff0c\u5982\u679c\u9700\u8981\u8bbf\u95ee MVC \u6784\u9020\u6216\u5e0c\u671b\u5bf9\u67d0\u4e9b MVC\u4f5c\u6216 Razor Pages \u91c7\u53d6\u4e0d\u540c\u7684\u884c\u4e3a\uff0c\u5219\u5e94\u8003\u8651\u4f7f\u7528\u7b5b\u9009\u5668\u3002<\/p>\n<p>The middleware-versus-filters argument is a subtle one, and it doesn\u2019t matter which you choose as long as it works for you. You can even use middleware components inside the MVC filter pipeline, effectively turning a middleware component into a filter!<br \/>\nmiddleware-versus-filters \u7684\u53c2\u6570\u662f\u4e00\u4e2a\u5fae\u5999\u7684\u53c2\u6570\uff0c\u53ea\u8981\u5b83\u9002\u5408\u4f60\uff0c\u4f60\u9009\u62e9\u54ea\u4e00\u4e2a\u5e76\u4e0d\u91cd\u8981\u3002\u60a8\u751a\u81f3\u53ef\u4ee5\u5728 MVC \u8fc7\u6ee4\u5668\u7ba1\u9053\u4e2d\u4f7f\u7528\u4e2d\u95f4\u4ef6\u7ec4\u4ef6\uff0c\u4ece\u800c\u6709\u6548\u5730\u5c06\u4e2d\u95f4\u4ef6\u7ec4\u4ef6\u8f6c\u6362\u4e3a\u8fc7\u6ee4\u5668\uff01<\/p>\n<p><b>Tip<\/b> The middleware-as-filters feature was introduced in ASP.NET Core 1.1 and is also available in later versions. The canonical use case is for localizing requests to multiple languages. I have a blog series on how to use the feature here: <a href=\"http:\/\/mng.bz\/RXa0\">http:\/\/mng.bz\/RXa0<\/a>.<br \/>\n\u63d0\u793amiddleware-as-filters \u529f\u80fd\u662f\u5728 ASP.NET Core 1.1 \u4e2d\u5f15\u5165\u7684\uff0c\u5728\u4ee5\u540e\u7684\u7248\u672c\u4e2d\u4e5f\u53ef\u7528\u3002\u89c4\u8303\u7528\u4f8b\u662f\u5c06\u8bf7\u6c42\u672c\u5730\u5316\u4e3a\u591a\u79cd\u8bed\u8a00\u3002\u6211\u6709\u4e00\u4e2a\u5173\u4e8e\u5982\u4f55\u4f7f\u7528\u8be5\u529f\u80fd\u7684\u535a\u5ba2\u7cfb\u5217\uff1a<a href=\"http:\/\/mng.bz\/RXa0\">http:\/\/mng.bz\/RXa0<\/a>\u3002<\/p>\n<p>Filters can be a little abstract in isolation, so in the next section we\u2019ll look at some code and learn how to write a custom MVC filter in ASP.NET Core.<br \/>\n\u7b5b\u9009\u5668\u53ef\u4ee5\u5355\u72ec\u4f7f\u7528\u4e00\u4e9b\u62bd\u8c61\uff0c\u56e0\u6b64\u5728\u4e0b\u4e00\u8282\u4e2d\uff0c\u6211\u4eec\u5c06\u67e5\u770b\u4e00\u4e9b\u4ee3\u7801\u5e76\u5b66\u4e60\u5982\u4f55\u5728 ASP.NET Core \u4e2d\u7f16\u5199\u81ea\u5b9a\u4e49 MVC \u7b5b\u9009\u5668\u3002<\/p>\n<h2>21.4 Creating a simple filter<\/h2>\n<p>21.4 \u521b\u5efa\u7b80\u5355\u8fc7\u6ee4\u5668<\/p>\n<p>In this section, I show you how to create your first filters; in section 21.5 you\u2019ll see how to apply them to MVC controllers and actions. We\u2019ll start small, creating filters that only write to the console, but in chapter 22 we look at some more practical examples and discuss some of their nuances.<br \/>\n\u5728\u672c\u8282\u4e2d\uff0c\u6211\u5c06\u5411\u60a8\u5c55\u793a\u5982\u4f55\u521b\u5efa\u60a8\u7684\u7b2c\u4e00\u4e2a\u8fc7\u6ee4\u5668;\u5728 Section 21.5 \u4e2d\uff0c\u60a8\u5c06\u770b\u5230\u5982\u4f55\u5c06\u5b83\u4eec\u5e94\u7528\u4e8e MVC \u63a7\u5236\u5668\u548c\u4f5c\u3002\u6211\u4eec\u5c06\u4ece\u5c0f\u5904\u7740\u624b\uff0c\u521b\u5efa\u4ec5\u5199\u5165\u63a7\u5236\u53f0\u7684\u8fc7\u6ee4\u5668\uff0c\u4f46\u5728\u7b2c 22 \u7ae0\u4e2d\uff0c\u6211\u4eec\u5c06\u67e5\u770b\u4e00\u4e9b\u66f4\u5b9e\u9645\u7684\u793a\u4f8b\u5e76\u8ba8\u8bba\u5b83\u4eec\u7684\u4e00\u4e9b\u7ec6\u5fae\u5dee\u522b\u3002<\/p>\n<p>You implement a filter for a given stage by implementing one of a pair of interfaces, one synchronous (sync) and one asynchronous (async):<br \/>\n\u60a8\u53ef\u4ee5\u901a\u8fc7\u5b9e\u73b0\u4e00\u5bf9\u63a5\u53e3\u4e4b\u4e00\uff08\u4e00\u4e2a\u540c\u6b65 \uff08sync\uff09\u548c\u4e00\u4e2a\u5f02\u6b65 \uff08async\uff09\uff09\u6765\u4e3a\u7ed9\u5b9a\u9636\u6bb5\u5b9e\u73b0\u7b5b\u9009\u5668\uff1a<\/p>\n<p>\u2022  Authorization filters\u2014IAuthorizationFilter or IAsyncAuthorizationFilter<br \/>\n\u6388\u6743\u7b5b\u9009\u5668 - IAuthorizationFilter \u6216 IAsyncAuthorizationFilter<br \/>\n\u2022  Resource filters\u2014IResourceFilter or IAsyncResourceFilter<br \/>\n\u8d44\u6e90\u7b5b\u9009\u5668 - IResourceFilter \u6216 IAsyncResourceFilter<br \/>\n\u2022  Action filters\u2014IActionFilter or IAsyncActionFilter<br \/>\n\u52a8\u4f5c\u7b5b\u9009\u5668 - IActionFilter \u6216 IAsyncActionFilter<br \/>\n\u2022  Page filters\u2014IPageFilter or IAsyncPageFilter<br \/>\n\u9875\u9762\u7b5b\u9009\u5668 - IPageFilter \u6216 IAsyncPageFilter<br \/>\n\u2022  Exception filters\u2014IExceptionFilter or IAsyncExceptionFilter<br \/>\n\u5f02\u5e38\u7b5b\u9009\u5668 - IExceptionFilter \u6216 IAsyncExceptionFilter<br \/>\n\u2022  Result filters\u2014IResultFilter or IAsyncResultFilter<br \/>\n\u7ed3\u679c\u7b5b\u9009\u5668 - IResultFilter \u6216 IAsyncResultFilter<\/p>\n<p>You can use any plain old CLR object (POCO) class to implement a filter, but you\u2019ll typically implement them as C# attributes, which you can use to decorate your controllers, actions, and Razor Pages, as you\u2019ll see in section 21.5. You can achieve the same results with either the sync or async interface, so which you choose should depend on whether any services you call in the filter require async support.<br \/>\n\u60a8\u53ef\u4ee5\u4f7f\u7528\u4efb\u4f55\u666e\u901a\u7684\u65e7 CLR \u5bf9\u8c61 \uff08POCO\uff09 \u7c7b\u6765\u5b9e\u73b0\u8fc7\u6ee4\u5668\uff0c\u4f46\u60a8\u901a\u5e38\u4f1a\u5c06\u5b83\u4eec\u5b9e\u73b0\u4e3a C# \u5c5e\u6027\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528\u8fd9\u4e9b\u5c5e\u6027\u6765\u88c5\u9970\u60a8\u7684\u63a7\u5236\u5668\u3001\u4f5c\u548c Razor \u9875\u9762\uff0c\u5982\u7b2c 21.5 \u8282\u6240\u793a\u3002\u60a8\u53ef\u4ee5\u4f7f\u7528 sync \u6216 async \u63a5\u53e3\u5b9e\u73b0\u76f8\u540c\u7684\u7ed3\u679c\uff0c\u56e0\u6b64\u60a8\u9009\u62e9\u54ea\u4e2a\u63a5\u53e3\u53d6\u51b3\u4e8e\u60a8\u5728\u8fc7\u6ee4\u5668\u4e2d\u8c03\u7528\u7684\u4efb\u4f55\u670d\u52a1\u662f\u5426\u9700\u8981\u5f02\u6b65\u652f\u6301\u3002<\/p>\n<p><b>NOTE<\/b> You should implement either the sync interface or the async interface, not both. If you implement both, only the async interface will be used.<br \/>\n\u6ce8\u610f\uff1a\u60a8\u5e94\u8be5\u5b9e\u73b0 sync \u63a5\u53e3\u6216 async \u63a5\u53e3\uff0c\u800c\u4e0d\u662f\u4e24\u8005\u517c\u800c\u6709\u4e4b\u3002\u5982\u679c\u540c\u65f6\u5b9e\u73b0\u8fd9\u4e24\u4e2a\u63a5\u53e3\uff0c\u5219\u4ec5\u4f7f\u7528\u5f02\u6b65\u63a5\u53e3\u3002<\/p>\n<p>Listing 21.1 shows a resource filter that implements IResourceFilter and writes to the console when it executes. The OnResourceExecuting method is called when a request first reaches the resource filter stage of the filter pipeline. By contrast, the OnResourceExecuted method is called after the rest of the pipeline has executed: after model binding, action execution, result execution, and all intermediate filters have run.<br \/>\n\u6e05\u5355 21.1 \u663e\u793a\u4e86\u4e00\u4e2a\u8d44\u6e90\u8fc7\u6ee4\u5668\uff0c\u5b83\u5b9e\u73b0 IResourceFilter \u5e76\u5728\u6267\u884c\u65f6\u5199\u5165\u63a7\u5236\u53f0\u3002\u5f53\u8bf7\u6c42\u9996\u6b21\u5230\u8fbe\u7b5b\u9009\u7ba1\u9053\u7684\u8d44\u6e90\u7b5b\u9009\u9636\u6bb5\u65f6\uff0c\u5c06\u8c03\u7528 OnResourceExecuting \u65b9\u6cd5\u3002\u76f8\u6bd4\u4e4b\u4e0b\uff0cOnResourceExecuted \u65b9\u6cd5\u662f\u5728\u7ba1\u9053\u7684\u5176\u4f59\u90e8\u5206\u6267\u884c\u4e4b\u540e\u8c03\u7528\u7684\uff1a\u5728\u6a21\u578b\u7ed1\u5b9a\u3001\u4f5c\u6267\u884c\u3001\u7ed3\u679c\u6267\u884c\u548c\u6240\u6709\u4e2d\u95f4\u7b5b\u9009\u5668\u8fd0\u884c\u4e4b\u540e\u3002<\/p>\n<p>Listing 21.1 Example resource filter implementing IResourceFilter<br \/>\n\u6e05\u5355 21.1 \u5b9e\u73b0 IResourceFilter \u7684\u793a\u4f8b\u8d44\u6e90\u8fc7\u6ee4\u5668<\/p>\n<pre><code>public class LogResourceFilter : Attribute, IResourceFilter\n{\n    public void OnResourceExecuting(          #A\n        ResourceExecutingContext context)    #B\n    {\n        Console.WriteLine(&quot;Executing!&quot;);\n    }\n\n    public void OnResourceExecuted(             #C\n        ResourceExecutedContext context)    #D\n    {\n        Console.WriteLine(&quot;Executed&quot;);\n    }\n}<\/code><\/pre>\n<p>\u2776 Executed at the start of the pipeline, after authorization filters<br \/>\n\u5728\u7ba1\u9053\u5f00\u59cb\u65f6\u6267\u884c\uff0c\u5728\u6388\u6743\u8fc7\u6ee4\u5668\u4e4b\u540e<br \/>\n\u2777 The context contains the HttpContext, routing details, and information about the current action.<br \/>\n\u4e0a\u4e0b\u6587\u5305\u542b HttpContext\u3001\u8def\u7531\u8be6\u7ec6\u4fe1\u606f\u548c\u6709\u5173\u5f53\u524d\u4f5c\u7684\u4fe1\u606f\u3002<br \/>\n\u2778 Executed after model binding, action execution, and result execution<br \/>\n\u5728\u6a21\u578b\u7ed1\u5b9a\u3001\u4f5c\u6267\u884c\u548c\u7ed3\u679c\u6267\u884c\u4e4b\u540e\u6267\u884c<br \/>\n\u2779 Contains additional context information, such as the IActionResult returned by the action<br \/>\n\u5305\u542b\u5176\u4ed6\u4e0a\u4e0b\u6587\u4fe1\u606f\uff0c\u4f8b\u5982\u4f5c\u8fd4\u56de\u7684 IActionResult<\/p>\n<p>The interface methods are simple and are similar for each stage in the filter pipeline, passing a context object as a method parameter. Each of the two-method sync filters has an <em>Executing and an <\/em>Executed method. The type of the argument is different for each filter, but it contains all the details for the filter pipeline.<br \/>\n\u63a5\u53e3\u65b9\u6cd5\u5f88\u7b80\u5355\uff0c\u5e76\u4e14\u5bf9\u4e8e\u7b5b\u9009\u5668\u7ba1\u9053\u4e2d\u7684\u6bcf\u4e2a\u9636\u6bb5\u90fd\u7c7b\u4f3c\uff0c\u5c06\u4e0a\u4e0b\u6587\u5bf9\u8c61\u4f5c\u4e3a\u65b9\u6cd5\u53c2\u6570\u4f20\u9012\u3002\u4e24\u79cd\u65b9\u6cd5\u7684\u540c\u6b65\u7b5b\u9009\u5668\u4e2d\u7684\u6bcf\u4e00\u4e2a\u90fd\u6709\u4e00\u4e2a Executing \u548c\u4e00\u4e2a Executed \u65b9\u6cd5\u3002\u6bcf\u4e2a\u7b5b\u9009\u6761\u4ef6\u7684\u53c2\u6570\u7c7b\u578b\u90fd\u4e0d\u540c\uff0c\u4f46\u5b83\u5305\u542b\u7b5b\u9009\u6761\u4ef6\u7ba1\u9053\u7684\u6240\u6709\u8be6\u7ec6\u4fe1\u606f\u3002<\/p>\n<p>For example, the ResourceExecutingContext passed to the resource filter contains the HttpContext object itself, details about the route that selected this action, details about the action itself, and so on. Contexts for later filters contain additional details, such as the action method arguments for an action filter and the ModelState.<br \/>\n\u4f8b\u5982\uff0c\u4f20\u9012\u7ed9\u8d44\u6e90\u7b5b\u9009\u5668\u7684 ResourceExecutingContext \u5305\u542b HttpContext \u5bf9\u8c61\u672c\u8eab\u3001\u6709\u5173\u9009\u62e9\u6b64\u4f5c\u7684\u8def\u7531\u7684\u8be6\u7ec6\u4fe1\u606f\u3001\u6709\u5173\u4f5c\u672c\u8eab\u7684\u8be6\u7ec6\u4fe1\u606f\u7b49\u3002\u66f4\u9ad8\u7b5b\u9009\u5668\u7684\u4e0a\u4e0b\u6587\u5305\u542b\u5176\u4ed6\u8be6\u7ec6\u4fe1\u606f\uff0c\u4f8b\u5982\u4f5c\u7b5b\u9009\u5668\u7684\u4f5c\u65b9\u6cd5\u53c2\u6570\u548c ModelState\u3002<\/p>\n<p>The context object for the ResourceExecutedContext method is similar, but it also contains details about how the rest of the pipeline executed. You can check whether an unhandled exception occurred, you can see if another filter from the same stage short-circuited the pipeline, or you can see the IActionResult used to generate the response.<br \/>\nResourceExecutedContext \u65b9\u6cd5\u7684\u4e0a\u4e0b\u6587\u5bf9\u8c61\u7c7b\u4f3c\uff0c\u4f46\u5b83\u8fd8\u5305\u542b\u6709\u5173\u7ba1\u9053\u5176\u4f59\u90e8\u5206\u5982\u4f55\u6267\u884c\u7684\u8be6\u7ec6\u4fe1\u606f\u3002\u60a8\u53ef\u4ee5\u68c0\u67e5\u662f\u5426\u53d1\u751f\u4e86\u672a\u7ecf\u5904\u7406\u7684\u5f02\u5e38\uff0c\u53ef\u4ee5\u67e5\u770b\u540c\u4e00\u9636\u6bb5\u4e2d\u7684\u53e6\u4e00\u4e2a\u7b5b\u9009\u5668\u662f\u5426\u4f7f\u7ba1\u9053\u77ed\u8def\uff0c\u6216\u8005\u60a8\u53ef\u4ee5\u67e5\u770b\u7528\u4e8e\u751f\u6210\u54cd\u5e94\u7684 IActionResult\u3002<\/p>\n<p>These context objects are powerful and are the key to advanced filter behaviors like short-circuiting the pipeline and handling exceptions. We\u2019ll make use of them in chapter 22 when we create more complex filter examples.<br \/>\n\u8fd9\u4e9b\u4e0a\u4e0b\u6587\u5bf9\u8c61\u529f\u80fd\u5f3a\u5927\uff0c\u662f\u9ad8\u7ea7\u7b5b\u9009\u884c\u4e3a\uff08\u5982\u77ed\u8def\u7ba1\u9053\u548c\u5904\u7406\u5f02\u5e38\uff09\u7684\u5173\u952e\u3002\u6211\u4eec\u5c06\u5728\u7b2c 22 \u7ae0\u521b\u5efa\u66f4\u590d\u6742\u7684\u8fc7\u6ee4\u5668\u793a\u4f8b\u65f6\u4f7f\u7528\u5b83\u4eec\u3002<\/p>\n<p>The async version of the resource filter requires implementing a single method, as shown in listing 21.2. As for the sync version, you\u2019re passed a ResourceExecutingContext object as an argument, and you\u2019re passed a delegate representing the remainder of the filter pipeline. You must call this delegate (asynchronously) to execute the remainder of the pipeline, which returns an instance of ResourceExecutedContext.<br \/>\n\u8d44\u6e90\u8fc7\u6ee4\u5668\u7684\u5f02\u6b65\u7248\u672c\u9700\u8981\u5b9e\u73b0\u4e00\u4e2a\u65b9\u6cd5\uff0c\u5982\u6e05\u5355 21.2 \u6240\u793a\u3002\u5bf9\u4e8e\u540c\u6b65\u7248\u672c\uff0c\u5c06\u5411\u60a8\u4f20\u9012\u4e00\u4e2a ResourceExecutingContext \u5bf9\u8c61\u4f5c\u4e3a\u53c2\u6570\uff0c\u5e76\u4f20\u9012\u4e00\u4e2a\u8868\u793a\u7b5b\u9009\u7ba1\u9053\u5176\u4f59\u90e8\u5206\u7684\u59d4\u6258\u3002\u60a8\u5fc5\u987b\uff08\u5f02\u6b65\uff09\u8c03\u7528\u6b64\u59d4\u6258\u6765\u6267\u884c\u7ba1\u9053\u7684\u5176\u4f59\u90e8\u5206\uff0c\u8be5\u7ba1\u9053\u5c06\u8fd4\u56de ResourceExecutedContext \u7684\u5b9e\u4f8b\u3002<\/p>\n<p>Listing 21.2 Example resource filter implementing IAsyncResourceFilter<br \/>\n\u5217\u8868 21.2 \u5b9e\u73b0 IAsyncResourceFilter \u7684\u793a\u4f8b\u8d44\u6e90\u8fc7\u6ee4\u5668<\/p>\n<pre><code>public class LogAsyncResourceFilter : Attribute, IAsyncResourceFilter\n{\npublic async Task OnResourceExecutionAsync( \u2776\nResourceExecutingContext context,\nResourceExecutionDelegate next) \u2777\n{\nConsole.WriteLine(&quot;Executing async!&quot;); \u2778\nResourceExecutedContext executedContext = await next(); \u2779\nConsole.WriteLine(&quot;Executed async!&quot;); \u277a\n}\n}<\/code><\/pre>\n<p>\u2776 Executed at the start of the pipeline, after authorization filters<br \/>\n\u5728\u7ba1\u9053\u5f00\u59cb\u65f6\u6267\u884c\uff0c\u6388\u6743\u8fc7\u6ee4\u5668\u4e4b\u540e<br \/>\n\u2777 You\u2019re provided a delegate, which encapsulates the remainder of the filter pipeline.<br \/>\n\u4e3a\u60a8\u63d0\u4f9b\u4e00\u4e2a\u59d4\u6258\uff0c\u5b83\u5c01\u88c5\u4e86\u8fc7\u6ee4\u5668\u7ba1\u9053\u7684\u5176\u4f59\u90e8\u5206\u3002<br \/>\n\u2778 Called before the rest of the pipeline executes<br \/>\n\u5728\u7ba1\u9053\u7684\u5176\u4f59\u90e8\u5206\u6267\u884c\u4e4b\u524d\u8c03\u7528<br \/>\n\u2779 Executes the rest of the pipeline and obtains a ResourceExecutedContext instance<br \/>\n\u6267\u884c\u7ba1\u9053\u7684\u5176\u4f59\u90e8\u5206\u5e76\u83b7\u53d6 ResourceExecutedContext \u5b9e\u4f8b<br \/>\n\u277a Called after the rest of the pipeline executes<br \/>\n\u5728\u7ba1\u9053\u7684\u5176\u4f59\u90e8\u5206\u6267\u884c\u4e4b\u540e\u8c03\u7528<\/p>\n<p>The sync and async filter implementations have subtle differences, but for most purposes they\u2019re identical. I recommend implementing the sync version for simplicity, falling back to the async version only if you need to.<br \/>\nsync \u548c async filter \u5b9e\u73b0\u6709\u7ec6\u5fae\u7684\u5dee\u5f02\uff0c\u4f46\u5728\u5927\u591a\u6570\u60c5\u51b5\u4e0b\u5b83\u4eec\u662f\u76f8\u540c\u7684\u3002\u4e3a\u7b80\u5355\u8d77\u89c1\uff0c\u6211\u5efa\u8bae\u5b9e\u73b0\u540c\u6b65\u7248\u672c\uff0c\u4ec5\u5728\u9700\u8981\u65f6\u56de\u9000\u5230\u5f02\u6b65\u7248\u672c\u3002<\/p>\n<p>You\u2019ve created a couple of filters now, so we should look at how to use them in the application. In the next section we\u2019ll tackle two specific issues: how to control which requests execute your new filters and how to control the order in which they execute.<br \/>\n\u60a8\u73b0\u5728\u5df2\u7ecf\u521b\u5efa\u4e86\u51e0\u4e2a\u8fc7\u6ee4\u5668\uff0c\u56e0\u6b64\u6211\u4eec\u5e94\u8be5\u770b\u770b\u5982\u4f55\u5728\u5e94\u7528\u7a0b\u5e8f\u4e2d\u4f7f\u7528\u5b83\u4eec\u3002\u5728\u4e0b\u4e00\u8282\u4e2d\uff0c\u6211\u4eec\u5c06\u89e3\u51b3\u4e24\u4e2a\u5177\u4f53\u95ee\u9898\uff1a\u5982\u4f55\u63a7\u5236\u54ea\u4e9b\u8bf7\u6c42\u6267\u884c\u60a8\u7684\u65b0\u8fc7\u6ee4\u5668\uff0c\u4ee5\u53ca\u5982\u4f55\u63a7\u5236\u5b83\u4eec\u7684\u6267\u884c\u987a\u5e8f\u3002<\/p>\n<h2>21.5 Adding filters to your actions and Razor Pages<\/h2>\n<p>\u5411\u52a8\u4f5c\u548c Razor \u9875\u9762\u6dfb\u52a0\u8fc7\u6ee4\u5668<\/p>\n<p>In section 21.3 I discussed the similarities and differences between middleware and filters. One of those differences is that filters can be scoped to specific actions or controllers so that they run only for certain requests. Alternatively, you can apply a filter globally so that it runs for every MVC action and Razor Page.<br \/>\n\u5728 Section 21.3 \u4e2d\uff0c\u6211\u8ba8\u8bba\u4e86 middleware \u548c filters \u4e4b\u95f4\u7684\u5f02\u540c\u3002\u5176\u4e2d\u4e00\u4e2a\u533a\u522b\u662f\uff0c\u8fc7\u6ee4\u5668\u7684\u8303\u56f4\u53ef\u4ee5\u9650\u5b9a\u4e3a\u7279\u5b9a\u7684\u4f5c\u6216\u63a7\u5236\u5668\uff0c\u4ee5\u4fbf\u5b83\u4eec\u4ec5\u9488\u5bf9\u7279\u5b9a\u8bf7\u6c42\u8fd0\u884c\u3002\u6216\u8005\uff0c\u60a8\u53ef\u4ee5\u5168\u5c40\u5e94\u7528\u7b5b\u9009\u5668\uff0c\u4ee5\u4fbf\u5b83\u9488\u5bf9\u6bcf\u4e2a MVC\u4f5c\u548c Razor \u9875\u9762\u8fd0\u884c\u3002<\/p>\n<p>By adding filters in different ways, you can achieve several different results. Imagine you have a filter that forces you to log in to execute an action. How you add the filter to your app will significantly change your app\u2019s behavior:<br \/>\n\u901a\u8fc7\u4ee5\u4e0d\u540c\u7684\u65b9\u5f0f\u6dfb\u52a0\u8fc7\u6ee4\u5668\uff0c\u60a8\u53ef\u4ee5\u83b7\u5f97\u591a\u79cd\u4e0d\u540c\u7684\u7ed3\u679c\u3002\u5047\u8bbe\u60a8\u6709\u4e00\u4e2a\u8fc7\u6ee4\u5668\uff0c\u5b83\u5f3a\u5236\u60a8\u767b\u5f55\u4ee5\u6267\u884c\u4f5c\u3002\u5411\u5e94\u7528\u7a0b\u5e8f\u6dfb\u52a0\u8fc7\u6ee4\u5668\u7684\u65b9\u5f0f\u5c06\u663e\u8457\u6539\u53d8\u5e94\u7528\u7a0b\u5e8f\u7684\u884c\u4e3a\uff1a<\/p>\n<p>\u2022  Apply the filter to a single action or Razor Page. Anonymous users could browse the app as normal, but if they tried to access the protected action or Razor Page, they would be forced to log in.<br \/>\n\u5c06\u7b5b\u9009\u5668\u5e94\u7528\u4e8e\u5355\u4e2a\u4f5c\u6216 Razor \u9875\u9762\u3002\u533f\u540d\u7528\u6237\u53ef\u4ee5\u6b63\u5e38\u6d4f\u89c8\u5e94\u7528\u7a0b\u5e8f\uff0c\u4f46\u5982\u679c\u4ed6\u4eec\u5c1d\u8bd5\u8bbf\u95ee\u53d7\u4fdd\u62a4\u7684\u4f5c\u6216 Razor \u9875\u9762\uff0c\u4ed6\u4eec\u5c06\u88ab\u8feb\u767b\u5f55\u3002<br \/>\n\u2022  Apply the filter to a controller. Anonymous users could access actions from other controllers, but accessing any action on the protected controller would force them to log in.<br \/>\n\u5c06\u8fc7\u6ee4\u5668\u5e94\u7528\u4e8e\u63a7\u5236\u5668\u3002\u533f\u540d\u7528\u6237\u53ef\u4ee5\u8bbf\u95ee\u6765\u81ea\u5176\u4ed6\u63a7\u5236\u5668\u7684\u4f5c\uff0c\u4f46\u8bbf\u95ee\u53d7\u4fdd\u62a4\u63a7\u5236\u5668\u4e0a\u7684\u4efb\u4f55\u4f5c\u90fd\u4f1a\u5f3a\u5236\u4ed6\u4eec\u767b\u5f55\u3002<br \/>\n\u2022  Apply the filter globally. Users couldn\u2019t use the app without logging in. Any attempt to access an action or Razor Page would redirect the user to the login page.<br \/>\n\u5168\u5c40\u5e94\u7528\u7b5b\u9009\u5668\u3002\u7528\u6237\u5982\u679c\u4e0d\u767b\u5f55\u5c31\u65e0\u6cd5\u4f7f\u7528\u8be5\u5e94\u7528\u7a0b\u5e8f\u3002\u4efb\u4f55\u8bbf\u95ee\u4f5c\u6216 Razor \u9875\u9762\u7684\u5c1d\u8bd5\u90fd\u4f1a\u5c06\u7528\u6237\u91cd\u5b9a\u5411\u5230\u767b\u5f55\u9875\u9762\u3002<\/p>\n<p><b>NOTE<\/b> ASP.NET Core comes with such a filter out of the box: AuthorizeFilter. I discuss this filter in chapter 22, and you\u2019ll be seeing a lot more of it in chapter 24.<br \/>\n\u6ce8\u610f\uff1a ASP.NET Core \u9644\u5e26\u4e86\u8fd9\u6837\u4e00\u4e2a\u5f00\u7bb1\u5373\u7528\u7684\u7b5b\u9009\u5668\uff1aAuthorizeFilter\u3002\u6211\u5728\u7b2c 22 \u7ae0\u4e2d\u8ba8\u8bba\u4e86\u8fd9\u4e2a\u8fc7\u6ee4\u5668\uff0c\u60a8\u5c06\u5728\u7b2c 24 \u7ae0\u4e2d\u770b\u5230\u66f4\u591a\u5185\u5bb9\u3002<\/p>\n<p>As I described in the previous section, you normally create filters as attributes, and for good reason: it makes it easy for you to apply them to MVC controllers, actions, and Razor Pages. In this section you\u2019ll see how to apply LogResourceFilter from listing 21.1 to an action, a controller, a Razor Page, and globally. The level at which the filter applies is called its scope.<br \/>\n\u6b63\u5982\u6211\u5728\u4e0a\u4e00\u8282\u4e2d\u6240\u63cf\u8ff0\u7684\uff0c\u60a8\u901a\u5e38\u5c06\u7b5b\u9009\u5668\u521b\u5efa\u4e3a\u5c5e\u6027\uff0c\u8fd9\u662f\u6709\u5145\u5206\u7406\u7531\u7684\uff1a\u5b83\u4f7f\u60a8\u53ef\u4ee5\u8f7b\u677e\u5730\u5c06\u5b83\u4eec\u5e94\u7528\u4e8e MVC \u63a7\u5236\u5668\u3001\u4f5c\u548c Razor \u9875\u9762\u3002\u5728\u672c\u8282\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3\u5982\u4f55\u5c06\u6e05\u5355 21.1 \u4e2d\u7684 LogResourceFilter \u5e94\u7528\u4e8e\u4f5c\u3001\u63a7\u5236\u5668\u3001Razor Page \u548c\u5168\u5c40\u5e94\u7528\u3002\u7b5b\u9009\u5668\u5e94\u7528\u7684\u7ea7\u522b\u79f0\u4e3a\u5176\u8303\u56f4\u3002<\/p>\n<p><b>DEFINITION<\/b> The scope of a filter refers to how many different actions it applies to. A filter can be scoped to the action method, to the controller, to a Razor Page, or globally.<br \/>\n\u5b9a\u4e49\uff1a\u7b5b\u9009\u5668\u7684\u8303\u56f4\u662f\u6307\u5b83\u5e94\u7528\u4e8e\u591a\u5c11\u4e2a\u4e0d\u540c\u7684\u4f5c\u3002\u7b5b\u9009\u5668\u7684\u8303\u56f4\u53ef\u4ee5\u9650\u5b9a\u4e3a\u4f5c\u65b9\u6cd5\u3001\u63a7\u5236\u5668\u3001Razor \u9875\u9762\u6216\u5168\u5c40\u3002<\/p>\n<p>You\u2019ll start at the most specific scope: applying filters to a single action. The following listing shows an example of an MVC controller that has two action methods, one with LogResourceFilter and one without.<br \/>\n\u60a8\u5c06\u4ece\u6700\u5177\u4f53\u7684\u8303\u56f4\u5f00\u59cb\uff1a\u5c06\u7b5b\u9009\u6761\u4ef6\u5e94\u7528\u4e8e\u5355\u4e2a\u4f5c\u3002\u4e0b\u9762\u7684\u6e05\u5355\u663e\u793a\u4e86\u4e00\u4e2a MVC \u63a7\u5236\u5668\u7684\u793a\u4f8b\uff0c\u8be5\u63a7\u5236\u5668\u5177\u6709\u4e24\u4e2a\u4f5c\u65b9\u6cd5\uff0c\u4e00\u4e2a\u5e26\u6709 LogResourceFilter\uff0c\u53e6\u4e00\u4e2a\u6ca1\u6709\u3002<\/p>\n<p>Listing 21.3 Applying filters to an action method<br \/>\n\u6e05\u5355 21.3 \u5c06\u8fc7\u6ee4\u5668\u5e94\u7528\u4e8e\u4f5c\u65b9\u6cd5<\/p>\n<pre><code>public class RecipeController : ControllerBase\n{\n    [LogResourceFilter]            #A\n    public IActionResult Index()   #A\n    {                              #A\n        return Ok();               #A\n    }                              #A\n    public IActionResult View()   #B\n    {                             #B\n        return OK();              #B\n    }                             #B\n}<\/code><\/pre>\n<p>\u2776 LogResourceFilter runs as part of the pipeline when executing this action.<br \/>\nLogResourceFilter \u5728\u6267\u884c\u6b64\u4f5c\u65f6\u4f5c\u4e3a\u7ba1\u9053\u7684\u4e00\u90e8\u5206\u8fd0\u884c\u3002<br \/>\n\u2777 This action method has no filters at the action level.<br \/>\n\u6b64\u4f5c\u65b9\u6cd5\u5728\u4f5c\u7ea7\u522b\u6ca1\u6709\u7b5b\u9009\u5668\u3002<\/p>\n<p>Alternatively, if you want to apply the same filter to every action method, you could add the attribute at the controller scope, as in the next listing. Every action method in the controller uses LogResourceFilter without having to specifically decorate each method.<br \/>\n\u6216\u8005\uff0c\u5982\u679c\u8981\u5c06\u76f8\u540c\u7684\u8fc7\u6ee4\u5668\u5e94\u7528\u4e8e\u6bcf\u4e2a\u4f5c\u65b9\u6cd5\uff0c\u5219\u53ef\u4ee5\u5728\u63a7\u5236\u5668\u8303\u56f4\u5185\u6dfb\u52a0\u8be5\u5c5e\u6027\uff0c\u5982\u4e0b\u4e00\u4e2a\u6e05\u5355\u6240\u793a\u3002\u63a7\u5236\u5668\u4e2d\u7684\u6bcf\u4e2a action method \u90fd\u4f7f\u7528 LogResourceFilter\uff0c\u800c\u4e0d\u5fc5\u4e13\u95e8\u4fee\u9970\u6bcf\u4e2a\u65b9\u6cd5\u3002<\/p>\n<p>Listing 21.4 Applying filters to a controller<br \/>\n\u6e05\u5355 21.4 \u5c06\u8fc7\u6ee4\u5668\u5e94\u7528\u4e8e\u63a7\u5236\u5668<\/p>\n<pre><code>[LogResourceFilter]                             #A\npublic class RecipeController : ControllerBase\n{\n    public IActionResult Index ()   #B\n    {                               #B\n        return Ok();                #B\n    }                               #B\n    public IActionResult View()     #B\n    {                               #B\n        return Ok();                #B\n    }                               #B\n}<\/code><\/pre>\n<p>\u2776 The LogResourceFilter is added to every action on the controller.<br \/>\nLogResourceFilter \u88ab\u6dfb\u52a0\u5230\u63a7\u5236\u5668\u4e0a\u7684\u6bcf\u4e2a\u4f5c\u4e2d\u3002<br \/>\n\u2777 Every action in the controller is decorated with the filter.<br \/>\n\u63a7\u5236\u5668\u4e2d\u7684\u6bcf\u4e2a\u4f5c\u90fd\u7528\u8fc7\u6ee4\u5668\u88c5\u9970\u3002<\/p>\n<p>For Razor Pages, you can apply attributes to your PageModel, as shown in the following listing. The filter applies to all page handlers in the Razor Page. It\u2019s not possible to apply filters to a single page handler; you must apply them at the page level.<br \/>\n\u5bf9\u4e8e Razor Pages\uff0c\u60a8\u53ef\u4ee5\u5c06\u5c5e\u6027\u5e94\u7528\u4e8e PageModel\uff0c\u5982\u4e0b\u9762\u7684\u6e05\u5355\u6240\u793a\u3002\u7b5b\u9009\u5668\u9002\u7528\u4e8e Razor \u9875\u9762\u4e2d\u7684\u6240\u6709\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u3002\u65e0\u6cd5\u5c06\u8fc7\u6ee4\u5668\u5e94\u7528\u4e8e\u5355\u4e2a\u9875\u9762\u5904\u7406\u7a0b\u5e8f;\u60a8\u5fc5\u987b\u5728\u9875\u9762\u7ea7\u522b\u5e94\u7528\u5b83\u4eec\u3002<\/p>\n<p>Listing 21.5 Applying filters to a Razor Page<br \/>\n\u6e05\u5355 21.5 \u5c06\u8fc7\u6ee4\u5668\u5e94\u7528\u4e8e Razor \u9875\u9762<\/p>\n<pre><code>[LogResourceFilter]             #A\npublic class IndexModel : PageModel\n{\n    public void OnGet()    #B\n    {                      #B\n    }                      #B\n\n    public void OnPost()   #B\n    {                      #B\n    }                      #B\n}<\/code><\/pre>\n<p>\u2776 The LogResourceFilter is added to the Razor Page\u2019s PageModel.<br \/>\nLogResourceFilter \u5df2\u6dfb\u52a0\u5230 Razor \u9875\u9762\u7684 PageModel\u3002<br \/>\n\u2777 The filter applies to every page handler in the page.<br \/>\n\u8fc7\u6ee4\u5668\u9002\u7528\u4e8e\u9875\u9762\u4e2d\u7684\u6bcf\u4e2a\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u3002<\/p>\n<p>Filters you apply as attributes to controllers, actions, and Razor Pages are automatically discovered by the framework when your application starts up. For common attributes, you can go one step further and apply filters globally without having to decorate individual classes.<br \/>\n\u5f53\u5e94\u7528\u7a0b\u5e8f\u542f\u52a8\u65f6\uff0c\u6846\u67b6\u4f1a\u81ea\u52a8\u53d1\u73b0\u4f5c\u4e3a\u5c5e\u6027\u5e94\u7528\u4e8e\u63a7\u5236\u5668\u3001\u4f5c\u548c Razor \u9875\u9762\u7684\u7b5b\u9009\u5668\u3002\u5bf9\u4e8e\u901a\u7528\u5c5e\u6027\uff0c\u60a8\u53ef\u4ee5\u66f4\u8fdb\u4e00\u6b65\uff0c\u5168\u5c40\u5e94\u7528\u8fc7\u6ee4\u5668\uff0c\u800c\u4e0d\u5fc5\u88c5\u9970\u5355\u4e2a\u7c7b\u3002<\/p>\n<p>You add global filters in a different way from controller- or action-scoped filters\u2014by adding a filter directly to the MVC services when configuring your controllers and Razor Pages. The next listing shows three equivalent ways to add a globally scoped filter.<br \/>\n\u6dfb\u52a0\u5168\u5c40\u7b5b\u9009\u5668\u7684\u65b9\u5f0f\u4e0e\u63a7\u5236\u5668\u6216\u4f5c\u8303\u56f4\u7684\u7b5b\u9009\u5668\u4e0d\u540c\uff0c\u5373\u5728\u914d\u7f6e\u63a7\u5236\u5668\u548c Razor Pages \u65f6\u76f4\u63a5\u5411 MVC \u670d\u52a1\u6dfb\u52a0\u7b5b\u9009\u5668\u3002\u4e0b\u4e00\u4e2a\u6e05\u5355\u663e\u793a\u4e86\u6dfb\u52a0\u5168\u5c40\u8303\u56f4\u8fc7\u6ee4\u5668\u7684\u4e09\u79cd\u7b49\u6548\u65b9\u6cd5\u3002<\/p>\n<p>Listing 21.6 Applying filters globally to an application<br \/>\n\u6e05\u5355 21.6 \u5c06\u8fc7\u6ee4\u5668\u5168\u5c40\u5e94\u7528\u4e8e\u5e94\u7528\u7a0b\u5e8f<\/p>\n<pre><code>WebApplicationBuilder builder = WebApplication.CreateBuilder(args);\n\nbuilder.Services.AddControllers(options =&gt;    #A\n{\n    options.Filters.Add(new LogResourceFilter());     #B\n    options.Filters.Add(typeof(LogResourceFilter));   #C\n    options.Filters.Add&lt;LogResourceFilter&gt;();    #D\n});<\/code><\/pre>\n<p>\u2776 Adds filters using the MvcOptions object<br \/>\n\u4f7f\u7528 MvcOptions \u5bf9\u8c61\u6dfb\u52a0\u8fc7\u6ee4\u5668<br \/>\n\u2777 You can pass an instance of the filter directly. . .<br \/>\n\u60a8\u53ef\u4ee5\u76f4\u63a5\u4f20\u9012\u8fc7\u6ee4\u5668\u7684\u5b9e\u4f8b\u3002 . .<br \/>\n\u2778 . . . or pass in the Type of the filter and let the framework create it.<br \/>\n. . . .\u6216\u8005\u4f20\u5165\u8fc7\u6ee4\u5668\u7684 Type \u5e76\u8ba9\u6846\u67b6\u521b\u5efa\u5b83\u3002<br \/>\n\u2779 Alternatively, the framework can create a global filter using a generic type parameter.<br \/>\n\u6216\u8005\uff0c\u6846\u67b6\u53ef\u4ee5\u4f7f\u7528\u6cdb\u578b\u7c7b\u578b\u53c2\u6570\u521b\u5efa\u5168\u5c40\u8fc7\u6ee4\u5668\u3002<\/p>\n<p>You can configure the MvcOptions by using the AddControllers() overload. When you configure filters globally, they apply both to controllers and to any Razor Pages in your application. If you wish to configure a global filter for a Razor Pages application, there isn\u2019t an overload for configuring the MvcOptions. Instead, you need to use the AddMvcOptions() extension method to configure the filters, as shown in the following listing.<br \/>\n\u60a8\u53ef\u4ee5\u4f7f\u7528 AddControllers\uff08\uff09 \u91cd\u8f7d\u914d\u7f6e MvcOptions\u3002\u5168\u5c40\u914d\u7f6e\u7b5b\u9009\u5668\u65f6\uff0c\u5b83\u4eec\u5c06\u540c\u65f6\u5e94\u7528\u4e8e\u63a7\u5236\u5668\u548c\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u4efb\u4f55 Razor Pages\u3002\u5982\u679c\u8981\u4e3a Razor Pages \u5e94\u7528\u7a0b\u5e8f\u914d\u7f6e\u5168\u5c40\u7b5b\u9009\u5668\uff0c\u5219\u4e0d\u4f1a\u6709\u7528\u4e8e\u914d\u7f6e MvcOptions \u7684\u91cd\u8f7d\u3002\u76f8\u53cd\uff0c\u60a8\u9700\u8981\u4f7f\u7528 AddMvcOptions\uff08\uff09 \u6269\u5c55\u65b9\u6cd5\u6765\u914d\u7f6e\u8fc7\u6ee4\u5668\uff0c\u5982\u4e0b\u9762\u7684\u6e05\u5355\u6240\u793a\u3002<\/p>\n<p>Listing 21.7 Applying filters globally to a Razor Pages application<br \/>\n\u5217\u8868 21.7 \u5c06\u8fc7\u6ee4\u5668\u5168\u5c40\u5e94\u7528\u4e8e Razor Pages \u5e94\u7528\u7a0b\u5e8f<\/p>\n<pre><code>WebApplicationBuilder builder = WebApplication.CreateBuilder(args);\n\nbuilder.Services.RazorPages()  #A\n    .AddMvcOptions(options =&gt;    #B\n    {\n        options.Filters.Add(new LogResourceFilter());     #C\n        options.Filters.Add(typeof(LogResourceFilter));   #C\n        options.Filters.Add&lt;LogResourceFilter&gt;();    #C\n    });<\/code><\/pre>\n<p>\u2776 This method doesn\u2019t let you pass a lambda to configure the MvcOptions.<br \/>\n\u6b64\u65b9\u6cd5\u4e0d\u5141\u8bb8\u60a8\u4f20\u9012 lambda \u6765\u914d\u7f6e MvcOptions\u3002<br \/>\n\u2777 You must use an extension method to add the filters to the MvcOptions object.<br \/>\n\u5fc5\u987b\u4f7f\u7528\u6269\u5c55\u65b9\u6cd5\u5c06\u7b5b\u9009\u5668\u6dfb\u52a0\u5230 MvcOptions \u5bf9\u8c61\u3002<br \/>\n\u2778 You can configure the filters in any of the ways shown previously.<br \/>\n\u60a8\u53ef\u4ee5\u6309\u7167\u524d\u9762\u663e\u793a\u7684\u4efb\u4f55\u65b9\u5f0f\u914d\u7f6e\u8fc7\u6ee4\u5668\u3002<\/p>\n<p>With potentially three different scopes in play, you\u2019ll often find action methods that have multiple filters applied to them, some applied directly to the action method and others inherited from the controller or globally. Then the question becomes which filter runs first.<br \/>\n\u7531\u4e8e\u53ef\u80fd\u6709\u4e09\u79cd\u4e0d\u540c\u7684\u8303\u56f4\uff0c\u60a8\u901a\u5e38\u4f1a\u53d1\u73b0\u5e94\u7528\u4e86\u591a\u4e2a\u8fc7\u6ee4\u5668\u7684\u4f5c\u65b9\u6cd5\uff0c\u5176\u4e2d\u4e00\u4e9b\u76f4\u63a5\u5e94\u7528\u4e8e\u4f5c\u65b9\u6cd5\uff0c\u800c\u53e6\u4e00\u4e9b\u5219\u4ece\u63a7\u5236\u5668\u6216\u5168\u5c40\u7ee7\u627f\u3002\u7136\u540e\u95ee\u9898\u5c31\u53d8\u6210\u4e86\u54ea\u4e2a\u8fc7\u6ee4\u5668\u5148\u8fd0\u884c\u3002<\/p>\n<h2>21.6 Understanding the order of filter execution<\/h2>\n<p>21.6 \u4e86\u89e3\u8fc7\u6ee4\u5668\u7684\u6267\u884c\u987a\u5e8f<\/p>\n<p>You\u2019ve seen that the filter pipeline contains five stages, one for each type of filter. These stages always run in the fixed order I described in sections 21.1 and 21.2. But within each stage, you can also have multiple filters of the same type (for example, multiple resource filters) that are part of a single action method\u2019s pipeline. These could all have multiple scopes, depending on how you added them, as you saw in the preceding section.<br \/>\n\u60a8\u5df2\u7ecf\u770b\u5230 filter \u7ba1\u9053\u5305\u542b 5 \u4e2a\u9636\u6bb5\uff0c\u6bcf\u79cd\u7c7b\u578b\u7684 filter \u5bf9\u5e94\u4e00\u4e2a\u9636\u6bb5\u3002\u8fd9\u4e9b\u9636\u6bb5\u59cb\u7ec8\u6309\u7167\u6211\u5728\u7b2c 21.1 \u8282\u548c\u7b2c 21.2 \u8282\u4e2d\u63cf\u8ff0\u7684\u56fa\u5b9a\u987a\u5e8f\u8fd0\u884c\u3002\u4f46\u5728\u6bcf\u4e2a\u9636\u6bb5\u4e2d\uff0c\u60a8\u8fd8\u53ef\u4ee5\u62e5\u6709\u591a\u4e2a\u76f8\u540c\u7c7b\u578b\u7684\u7b5b\u9009\u6761\u4ef6\uff08\u4f8b\u5982\uff0c\u591a\u4e2a\u8d44\u6e90\u7b5b\u9009\u6761\u4ef6\uff09\uff0c\u8fd9\u4e9b\u7b5b\u9009\u6761\u4ef6\u662f\u5355\u4e2a\u4f5c\u65b9\u6cd5\u7684\u7ba1\u9053\u7684\u4e00\u90e8\u5206\u3002\u8fd9\u4e9b\u8303\u56f4\u53ef\u80fd\u90fd\u5177\u6709\u591a\u4e2a\u8303\u56f4\uff0c\u5177\u4f53\u53d6\u51b3\u4e8e\u60a8\u6dfb\u52a0\u5b83\u4eec\u7684\u65b9\u5f0f\uff0c\u5982\u4e0a\u4e00\u8282\u6240\u793a\u3002<\/p>\n<p>In this section we\u2019re thinking about the order of filters within a given stage and how scope affects this. We\u2019ll start by looking at the default order and then move on to ways to customize the order to your own requirements.<br \/>\n\u5728\u672c\u8282\u4e2d\uff0c\u6211\u4eec\u5c06\u8003\u8651\u7ed9\u5b9a\u9636\u6bb5\u4e2d\u8fc7\u6ee4\u5668\u7684\u987a\u5e8f\u4ee5\u53ca\u8303\u56f4\u5982\u4f55\u5f71\u54cd\u8fd9\u4e00\u70b9\u3002\u6211\u4eec\u5c06\u9996\u5148\u67e5\u770b\u9ed8\u8ba4\u987a\u5e8f\uff0c\u7136\u540e\u7ee7\u7eed\u8ba8\u8bba\u6839\u636e\u81ea\u5df1\u7684\u8981\u6c42\u81ea\u5b9a\u4e49\u987a\u5e8f\u7684\u65b9\u6cd5\u3002<\/p>\n<h3>21.6.1 The default scope execution order<\/h3>\n<p>21.6.1 \u9ed8\u8ba4\u8303\u56f4\u6267\u884c\u987a\u5e8f<\/p>\n<p>When thinking about filter ordering, it\u2019s important to remember that resource, action, and result filters implement two methods: an <em>Executing before method and an <\/em>Executed after method. On top of that, page filters implement three methods! The order in which each method executes depends on the scope of the filter, as shown in figure 21.4 for the resource filter stage.<br \/>\n\u5728\u8003\u8651\u7b5b\u9009\u5668\u6392\u5e8f\u65f6\uff0c\u8bf7\u52a1\u5fc5\u8bb0\u4f4f\uff0c\u8d44\u6e90\u3001\u4f5c\u548c\u7ed3\u679c\u7b5b\u9009\u5668\u5b9e\u73b0\u4e24\u79cd\u65b9\u6cd5\uff1aExecuting before \u65b9\u6cd5\u548c Executed after \u65b9\u6cd5\u3002\u6700\u91cd\u8981\u7684\u662f\uff0c\u9875\u9762\u8fc7\u6ee4\u5668\u5b9e\u73b0\u4e86\u4e09\u79cd\u65b9\u6cd5\uff01\u6bcf\u4e2a\u65b9\u6cd5\u7684\u6267\u884c\u987a\u5e8f\u53d6\u51b3\u4e8e\u8fc7\u6ee4\u5668\u7684\u8303\u56f4\uff0c\u5982\u56fe 21.4 \u6240\u793a\uff0c\u7528\u4e8e\u8d44\u6e90\u8fc7\u6ee4\u5668\u9636\u6bb5\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2104.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 21.4 The default filter ordering within a given stage, based on the scope of the filters. For the <em>Executing method, globally scoped filters run first, followed by controller-scoped, and finally action-scoped filters. For the <\/em>Executed method, the filters run in reverse order.<br \/>\n\u56fe 21.4 \u7ed9\u5b9a\u9636\u6bb5\u4e2d\u57fa\u4e8e\u8fc7\u6ee4\u5668\u8303\u56f4\u7684\u9ed8\u8ba4\u8fc7\u6ee4\u5668\u6392\u5e8f\u3002\u5bf9\u4e8e Executing \u65b9\u6cd5\uff0c\u5168\u5c40\u8303\u56f4\u7684\u7b5b\u9009\u5668\u9996\u5148\u8fd0\u884c\uff0c\u7136\u540e\u662f\u63a7\u5236\u5668\u8303\u56f4\u7684\u7b5b\u9009\u5668\uff0c\u6700\u540e\u662f\u4f5c\u8303\u56f4\u7684\u7b5b\u9009\u5668\u3002\u5bf9\u4e8e Executed \u65b9\u6cd5\uff0c\u7b5b\u9009\u5668\u6309\u76f8\u53cd\u7684\u987a\u5e8f\u8fd0\u884c\u3002<\/p>\n<p>By default, filters execute from the broadest scope (global) to the narrowest (action) when running the <em>Executing method for each stage. The filters\u2019 <\/em>Executed methods run in reverse order, from the narrowest scope (action) to the broadest (global).<br \/>\n\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5728\u4e3a\u6bcf\u4e2a\u9636\u6bb5\u8fd0\u884c Executing \u65b9\u6cd5\u65f6\uff0c\u7b5b\u9009\u5668\u4ece\u6700\u5e7f\u6cdb\u7684\u8303\u56f4 \uff08\u5168\u5c40\uff09 \u5230\u6700\u7a84\u7684 \uff08\u4f5c\uff09 \u6267\u884c\u3002\u7b5b\u9009\u5668\u7684 Executed \u65b9\u6cd5\u6309\u76f8\u53cd\u7684\u987a\u5e8f\u8fd0\u884c\uff0c\u4ece\u6700\u7a84\u7684\u8303\u56f4 \uff08\u4f5c\uff09 \u5230\u6700\u5e7f\u6cdb\u7684\u8303\u56f4 \uff08\u5168\u5c40\uff09\u3002<\/p>\n<p>The ordering for Razor Pages is somewhat simpler, given that you have only two scopes: global scope filters and Razor Page scope filters. For Razor Pages, global scope filters run the <em>Executing and PageHandlerSelected methods first, followed by the page scope filters. For the <\/em>Executed methods, the filters run in reverse order.<br \/>\nRazor Pages \u7684\u6392\u5e8f\u7a0d\u5fae\u7b80\u5355\u4e00\u4e9b\uff0c\u56e0\u4e3a\u4f60\u53ea\u6709\u4e24\u4e2a\u8303\u56f4\uff1a\u5168\u5c40\u8303\u56f4\u7b5b\u9009\u5668\u548c Razor Page \u8303\u56f4\u7b5b\u9009\u5668\u3002\u5bf9\u4e8e Razor Pages\uff0c\u5168\u5c40\u8303\u56f4\u7b5b\u9009\u5668\u9996\u5148\u8fd0\u884c Executing \u548c PageHandlerSelected \u65b9\u6cd5\uff0c\u7136\u540e\u8fd0\u884c\u9875\u9762\u8303\u56f4\u7b5b\u9009\u5668\u3002\u5bf9\u4e8e Executed \u65b9\u6cd5\uff0c\u7b5b\u9009\u5668\u6309\u76f8\u53cd\u7684\u987a\u5e8f\u8fd0\u884c\u3002<\/p>\n<p>You\u2019ll sometimes find you need a bit more control over this order, especially if you have, for example, multiple action filters applied at the same scope. The filter pipeline caters to this requirement by way of the IOrderedFilter interface.<br \/>\n\u60a8\u6709\u65f6\u4f1a\u53d1\u73b0\u9700\u8981\u5bf9\u6b64\u987a\u5e8f\u8fdb\u884c\u66f4\u591a\u63a7\u5236\uff0c\u5c24\u5176\u662f\u5728\u60a8\u5728\u540c\u4e00\u8303\u56f4\u5185\u5e94\u7528\u4e86\u591a\u4e2a\u4f5c\u7b5b\u9009\u5668\u65f6\u3002\u7b5b\u9009\u5668\u7ba1\u9053\u901a\u8fc7 IOrderedFilter \u63a5\u53e3\u6ee1\u8db3\u6b64\u8981\u6c42\u3002<\/p>\n<h3>21.6.2 Overriding the default order of filter execution with IOrderedFilter<\/h3>\n<p>21.6.2 \u4f7f\u7528 IOrderedFilter \u8986\u76d6\u8fc7\u6ee4\u5668\u6267\u884c\u7684\u9ed8\u8ba4\u987a\u5e8f<\/p>\n<p>Filters are great for extracting cross-cutting concerns from your controller actions and Razor Page, but if you have multiple filters applied to an action, you\u2019ll often need to control the precise order in which they execute.<br \/>\n\u7b5b\u9009\u5668\u975e\u5e38\u9002\u5408\u4ece\u63a7\u5236\u5668\u4f5c\u548c Razor Page \u4e2d\u63d0\u53d6\u6a2a\u5207\u5173\u6ce8\u70b9\uff0c\u4f46\u5982\u679c\u5c06\u591a\u4e2a\u7b5b\u9009\u5668\u5e94\u7528\u4e8e\u4e00\u4e2a\u4f5c\uff0c\u5219\u901a\u5e38\u9700\u8981\u63a7\u5236\u5b83\u4eec\u7684\u6267\u884c\u7cbe\u786e\u987a\u5e8f\u3002<\/p>\n<p>Scope can get you some of the way, but for those other cases, you can implement IOrderedFilter. This interface consists of a single property, Order:<br \/>\nScope \u53ef\u4ee5\u4e3a\u60a8\u63d0\u4f9b\u4e00\u4e9b\u65b9\u6cd5\uff0c\u4f46\u5bf9\u4e8e\u5176\u4ed6\u60c5\u51b5\uff0c\u60a8\u53ef\u4ee5\u5b9e\u73b0 IOrderedFilter\u3002\u6b64\u63a5\u53e3\u7531\u5355\u4e2a\u5c5e\u6027 Order \u7ec4\u6210\uff1a<\/p>\n<pre><code>public interface IOrderedFilter\n{\n    int Order { get; }\n}<\/code><\/pre>\n<p>You can implement this property in your filters to set the order in which they execute. The filter pipeline orders the filters in each stage based on the Order property first, from lowest to highest, and uses the default scope order to handle ties, as shown in figure 21.5.<br \/>\n\u60a8\u53ef\u4ee5\u5728\u7b5b\u9009\u6761\u4ef6\u4e2d\u5b9e\u73b0\u6b64\u5c5e\u6027\uff0c\u4ee5\u8bbe\u7f6e\u7b5b\u9009\u6761\u4ef6\u7684\u6267\u884c\u987a\u5e8f\u3002filter \u7ba1\u9053\u9996\u5148\u6839\u636e Order \u5c5e\u6027\u4ece\u6700\u4f4e\u5230\u6700\u9ad8\u5bf9\u6bcf\u4e2a\u9636\u6bb5\u4e2d\u7684\u8fc7\u6ee4\u5668\u8fdb\u884c\u6392\u5e8f\uff0c\u5e76\u4f7f\u7528\u9ed8\u8ba4\u7684\u4f5c\u7528\u57df order \u6765\u5904\u7406\u5e73\u5c40\uff0c\u5982\u56fe 21.5 \u6240\u793a\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2105.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 21.5 Controlling the filter order for a stage using the IOrderedFilter interface. Filters are ordered by the Order property first, and then by scope.<br \/>\n\u56fe 21.5 \u4f7f\u7528 IOrderedFilter \u63a5\u53e3\u63a7\u5236\u9636\u6bb5\u7684\u8fc7\u6ee4\u5668\u987a\u5e8f\u3002\u7b5b\u9009\u5668\u9996\u5148\u6309 Order \u5c5e\u6027\u6392\u5e8f\uff0c\u7136\u540e\u6309\u8303\u56f4\u6392\u5e8f\u3002<\/p>\n<p>The filters for Order = -1 execute first, as they have the lowest Order value. The controller filter executes first because it has a broader scope than the action-scope filter. The filters with Order = 0 execute next, in the default scope order, as shown in figure 21.5. Finally, the filter with Order = 1 executes.<br \/>\n\u9996\u5148\u6267\u884c Order = -1 \u7684\u7b5b\u9009\u5668\uff0c\u56e0\u4e3a\u5b83\u4eec\u5177\u6709\u6700\u4f4e\u7684 Order \u503c\u3002\u9996\u5148\u6267\u884c controller \u7b5b\u9009\u5668\uff0c\u56e0\u4e3a\u5b83\u7684\u8303\u56f4\u6bd4 action-scope \u7b5b\u9009\u5668\u66f4\u5e7f\u3002Order = 0 \u7684 filters \u63a5\u4e0b\u6765\u4ee5\u9ed8\u8ba4\u7684 scope \u987a\u5e8f\u6267\u884c\uff0c\u5982\u56fe 21.5 \u6240\u793a\u3002\u6700\u540e\uff0c\u6267\u884c Order = 1 \u7684\u7b5b\u9009\u5668\u3002<\/p>\n<p>By default, if a filter doesn\u2019t implement IOrderedFilter, it\u2019s assumed to have Order = 0. All the filters that ship as part of ASP.NET Core have Order = 0, so you can implement your own filters relative to these.<br \/>\n\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5982\u679c\u7b5b\u9009\u5668\u672a\u5b9e\u73b0 IOrderedFilter\uff0c\u5219\u5047\u5b9a\u5176 Order = 0\u3002\u4f5c\u4e3a ASP.NET Core \u7684\u4e00\u90e8\u5206\u63d0\u4f9b\u7684\u6240\u6709\u7b5b\u9009\u5668\u7684 Order = 0\uff0c\u56e0\u6b64\u60a8\u53ef\u4ee5\u5b9e\u73b0\u81ea\u5df1\u7684\u7b5b\u9009\u5668\u3002<\/p>\n<p><b>NOTE<\/b> You can completely customize how the filter pipeline is built by customizing the MVC frameworks application model conventions. These control everything about how controllers and Razor Pages are discovered, how they\u2019re added to the pipeline, and how filters are discovered. This is an advanced concept, that you won\u2019t often need, but it may occasionally come in handy. You can read about the MVC application model in the documentation at <a href=\"http:\/\/mng.bz\/nWNa\">http:\/\/mng.bz\/nWNa<\/a>.<br \/>\n\u6ce8\u610f\uff1a\u60a8\u53ef\u4ee5\u901a\u8fc7\u81ea\u5b9a\u4e49 MVC \u6846\u67b6\u5e94\u7528\u7a0b\u5e8f\u6a21\u578b\u7ea6\u5b9a\u6765\u5b8c\u5168\u81ea\u5b9a\u4e49\u7b5b\u9009\u5668\u7ba1\u9053\u7684\u6784\u5efa\u65b9\u5f0f\u3002\u5b83\u4eec\u63a7\u5236\u6709\u5173\u5982\u4f55\u53d1\u73b0\u63a7\u5236\u5668\u548c Razor \u9875\u9762\u3001\u5982\u4f55\u5c06\u5b83\u4eec\u6dfb\u52a0\u5230\u7ba1\u9053\u4ee5\u53ca\u5982\u4f55\u53d1\u73b0\u7b5b\u9009\u5668\u7684\u6240\u6709\u5185\u5bb9\u3002\u8fd9\u662f\u4e00\u4e2a\u9ad8\u7ea7\u6982\u5ff5\uff0c\u60a8\u901a\u5e38\u4e0d\u9700\u8981\u5b83\uff0c\u4f46\u5b83\u5076\u5c14\u53ef\u80fd\u4f1a\u6d3e\u4e0a\u7528\u573a\u3002\u60a8\u53ef\u4ee5\u5728 <a href=\"http:\/\/mng.bz\/nWNa\">http:\/\/mng.bz\/nWNa<\/a> \u7684\u6587\u6863 \u4e2d\u9605\u8bfb\u6709\u5173 MVC \u5e94\u7528\u7a0b\u5e8f\u6a21\u578b\u7684\u4fe1\u606f\u3002<\/p>\n<p>This chapter has provided a lot of background on the MVC filter pipeline, and we covered most of the technical details you need to use filters and create custom implementations for your own application. In chapter 22 you\u2019ll see some of the built-in filters provided by ASP.NET Core, as well as some practical examples of filters you might want to use in your own applications.<br \/>\n\u672c\u7ae0\u63d0\u4f9b\u4e86\u8bb8\u591a\u5173\u4e8e MVC \u8fc7\u6ee4\u5668\u7ba1\u9053\u7684\u80cc\u666f\u77e5\u8bc6\uff0c\u6211\u4eec\u4ecb\u7ecd\u4e86\u4f7f\u7528\u8fc7\u6ee4\u5668\u548c\u4e3a\u81ea\u5df1\u7684\u5e94\u7528\u7a0b\u5e8f\u521b\u5efa\u81ea\u5b9a\u4e49\u5b9e\u73b0\u6240\u9700\u7684\u5927\u90e8\u5206\u6280\u672f\u7ec6\u8282\u3002\u5728\u7b2c 22 \u7ae0\u4e2d\uff0c\u60a8\u5c06\u770b\u5230 ASP.NET Core \u63d0\u4f9b\u7684\u4e00\u4e9b\u5185\u7f6e\u8fc7\u6ee4\u5668\uff0c\u4ee5\u53ca\u60a8\u53ef\u80fd\u5e0c\u671b\u5728\u81ea\u5df1\u7684\u5e94\u7528\u7a0b\u5e8f\u4e2d\u4f7f\u7528\u7684\u4e00\u4e9b\u8fc7\u6ee4\u5668\u7684\u5b9e\u9645\u793a\u4f8b\u3002<\/p>\n<h2>21.7 Summary<\/h2>\n<p>21.7 \u603b\u7ed3<\/p>\n<p>The filter pipeline provides hooks into an MVC request so you can run functions at various points within an MVC request. With filters you can run code at specific points in the MVC process across all requests or a subset of requests. This is particularly useful for handling cross-cutting concerns that are specific to MVC.<br \/>\n\u7b5b\u9009\u5668\u7ba1\u9053\u63d0\u4f9b MVC \u8bf7\u6c42\u7684\u6302\u94a9\uff0c\u4ee5\u4fbf\u60a8\u53ef\u4ee5\u5728 MVC \u8bf7\u6c42\u4e2d\u7684\u4e0d\u540c\u70b9\u8fd0\u884c\u51fd\u6570\u3002\u4f7f\u7528\u7b5b\u9009\u5668\uff0c\u60a8\u53ef\u4ee5\u5728 MVC \u8fdb\u7a0b\u4e2d\u7684\u7279\u5b9a\u70b9\u8de8\u6240\u6709\u8bf7\u6c42\u6216\u8bf7\u6c42\u5b50\u96c6\u8fd0\u884c\u4ee3\u7801\u3002\u8fd9\u5bf9\u4e8e\u5904\u7406\u7279\u5b9a\u4e8e MVC \u7684\u6a2a\u5207\u5173\u6ce8\u70b9\u7279\u522b\u6709\u7528\u3002<\/p>\n<p>The filter pipeline executes as part of the MVC or Razor Pages execution. It consists of authorization filters, resource filters, action filters, page filters, exception filters, and result filters. Each filter type is grouped in a stage and can be used to achieve effects specific to that stage.<br \/>\n\u7b5b\u9009\u5668\u7ba1\u9053\u4f5c\u4e3a MVC \u6216 Razor Pages \u6267\u884c\u7684\u4e00\u90e8\u5206\u6267\u884c\u3002\u5b83\u7531\u6388\u6743\u7b5b\u9009\u6761\u4ef6\u3001\u8d44\u6e90\u7b5b\u9009\u6761\u4ef6\u3001\u4f5c\u7b5b\u9009\u6761\u4ef6\u3001\u9875\u9762\u7b5b\u9009\u6761\u4ef6\u3001\u5f02\u5e38\u7b5b\u9009\u6761\u4ef6\u548c\u7ed3\u679c\u7b5b\u9009\u6761\u4ef6\u7ec4\u6210\u3002\u6bcf\u79cd\u6ee4\u955c\u7c7b\u578b\u90fd\u5206\u7ec4\u5728\u4e00\u4e2a\u9636\u6bb5\u4e2d\uff0c\u53ef\u7528\u4e8e\u5b9e\u73b0\u7279\u5b9a\u4e8e\u8be5\u9636\u6bb5\u7684\u6548\u679c\u3002<\/p>\n<p>Resource, action, and result filters run twice in the pipeline: an <em>Executing method on the way in and an <\/em>Executed method on the way out. Page filters run three times: after page handler selection, and before and after page handler execution.<br \/>\n\u8d44\u6e90\u3001\u4f5c\u548c\u7ed3\u679c\u7b5b\u9009\u5668\u5728\u7ba1\u9053\u4e2d\u8fd0\u884c\u4e24\u6b21\uff1a\u4e00\u4e2a Executing \u65b9\u6cd5\u5728\u6d41\u5165\u4e2d\uff0c\u4e00\u4e2a Executed \u65b9\u6cd5\u5728\u6d41\u51fa\u3002\u9875\u9762\u8fc7\u6ee4\u5668\u8fd0\u884c\u4e09\u6b21\uff1a\u9009\u62e9\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u4e4b\u540e\uff0c\u4ee5\u53ca\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u6267\u884c\u4e4b\u524d\u548c\u4e4b\u540e\u3002<\/p>\n<p>Authorization and exception filters run only once as part of the pipeline; they don\u2019t run after a response has been generated.<br \/>\n\u6388\u6743\u548c\u5f02\u5e38\u7b5b\u9009\u5668\u4ec5\u4f5c\u4e3a\u7ba1\u9053\u7684\u4e00\u90e8\u5206\u8fd0\u884c\u4e00\u6b21;\u5b83\u4eec\u5728\u751f\u6210\u54cd\u5e94\u540e\u4e0d\u4f1a\u8fd0\u884c\u3002<\/p>\n<p>Each type of filter has both a sync and an async version. For example, resource filters can implement either the IResourceFilter interface or the IAsync-ResourceFilter interface. You should use the synchronous interface unless your filter needs to use asynchronous method calls.<br \/>\n\u6bcf\u79cd\u7c7b\u578b\u7684\u7b5b\u9009\u5668\u90fd\u6709\u540c\u6b65\u7248\u672c\u548c\u5f02\u6b65\u7248\u672c\u3002\u4f8b\u5982\uff0c\u8d44\u6e90\u7b5b\u9009\u5668\u53ef\u4ee5\u5b9e\u73b0 IResourceFilter \u63a5\u53e3\u6216 IAsync-ResourceFilter \u63a5\u53e3\u3002\u9664\u975e filter \u9700\u8981\u4f7f\u7528\u5f02\u6b65\u65b9\u6cd5\u8c03\u7528\uff0c\u5426\u5219\u5e94\u4f7f\u7528 synchronous interface\u3002<\/p>\n<p>You can add filters globally, at the controller level, at the Razor Page level, or at the action level. This is called the scope of the filter. Which scope you should choose depends on how broadly you want to apply the filter.<br \/>\n\u60a8\u53ef\u4ee5\u5728\u63a7\u5236\u5668\u7ea7\u522b\u3001Razor Page \u7ea7\u522b\u6216\u4f5c\u7ea7\u522b\u5168\u5c40\u6dfb\u52a0\u7b5b\u9009\u5668\u3002\u8fd9\u79f0\u4e3a\u7b5b\u9009\u5668\u7684\u8303\u56f4\u3002\u60a8\u5e94\u8be5\u9009\u62e9\u54ea\u4e2a\u8303\u56f4\u53d6\u51b3\u4e8e\u60a8\u8981\u5e94\u7528\u8fc7\u6ee4\u5668\u7684\u8303\u56f4\u3002<\/p>\n<p>Within a given stage, global-scoped filters run first, then controller-scoped, and finally action-scoped. You can also override the default order by implementing the IOrderedFilter interface. Filters run from lowest to highest Order and use scope to break ties.<br \/>\n\u5728\u7ed9\u5b9a\u7684\u9636\u6bb5\u4e2d\uff0c\u5168\u5c40\u8303\u56f4\u7684\u8fc7\u6ee4\u5668\u9996\u5148\u8fd0\u884c\uff0c\u7136\u540e\u662f\u63a7\u5236\u5668\u8303\u56f4\u7684\uff0c\u6700\u540e\u662f\u4f5c\u8303\u56f4\u7684\u3002\u60a8\u8fd8\u53ef\u4ee5\u901a\u8fc7\u5b9e\u73b0 IOrderedFilter \u63a5\u53e3\u6765\u8986\u76d6\u9ed8\u8ba4\u987a\u5e8f\u3002\u7b5b\u9009\u5668\u4ece\u6700\u4f4e\u987a\u5e8f\u5230\u6700\u9ad8\u987a\u5e8f\u8fd0\u884c\uff0c\u5e76\u4f7f\u7528\u8303\u56f4\u6765\u6253\u7834\u5173\u7cfb\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>21 The MVC and Razor Pages filter pipeline 21 MVC \u548c Razor Pages \u7b5b\u9009\u5668\u7ba1\u9053 This chapter covers \u672c\u7ae0\u6db5\u76d6 \u2022 The filter pipeline and how it differs from middleware \u8fc7\u6ee4\u5668\u7ba1\u9053\u53ca\u5176\u4e0e\u4e2d\u95f4\u4ef6\u7684\u533a\u522b \u2022 The different types of filters \u8fc7\u6ee4\u5668\u7684\u4e0d\u540c\u7c7b\u578b\u7684 \u2022 Filter ordering \u8fc7\u6ee4\u5668\u6392\u5e8f Part 3 of this book has covered the Model-View-Controller (MVC) and Razor Pages frameworks of [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[],"class_list":["post-613","post","type-post","status-publish","format-standard","hentry","category-csharp"],"_links":{"self":[{"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts\/613","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=613"}],"version-history":[{"count":0,"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts\/613\/revisions"}],"wp:attachment":[{"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=613"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=613"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=613"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}