{"id":1100,"date":"2025-05-27T14:45:57","date_gmt":"2025-05-27T06:45:57","guid":{"rendered":"https:\/\/www.hyy.net\/?p=1100"},"modified":"2025-05-27T14:45:57","modified_gmt":"2025-05-27T06:45:57","slug":"ultimate-asp-net-core-web-api-1-project-configuration","status":"publish","type":"post","link":"https:\/\/diji.net\/?p=1100","title":{"rendered":"Ultimate ASP.NET Core Web API  1 PROJECT CONFIGURATION"},"content":{"rendered":"<p>Ultimate ASP.NET Core Web API 2nd Premium Edition<\/p>\n<p>Ultimate ASP.NET Core Web API  1 PROJECT CONFIGURATION<br \/>\n1 \u9879\u76ee\u914d\u7f6e<\/p>\n<p>Ultimate ASP.NET Core Web API  2 Creating the Required Projects<br \/>\n2 \u521b\u5efa\u6240\u9700\u7684\u9879\u76ee<\/p>\n<p>Ultimate ASP.NET Core Web API  3 ONION ARCHITECTURE IMPLEMENTATION<br \/>\n3 \u6d0b\u8471\u67b6\u6784\u5b9e\u73b0<\/p>\n<p>Ultimate ASP.NET Core Web API  4 HANDLING GET REQUESTS<br \/>\n4 \u5904\u7406 GET \u8bf7\u6c42<\/p>\n<p>Ultimate ASP.NET Core Web API  5 GLOBAL ERROR HANDLING<br \/>\n5 \u5168\u5c40\u9519\u8bef\u5904\u7406<\/p>\n<p>Ultimate ASP.NET Core Web API  6 GETTING ADDITIONAL RESOURCES<br \/>\n6 \u83b7\u53d6\u8d44\u6e90<\/p>\n<p>Ultimate ASP.NET Core Web API  7 CONTENT NEGOTIATION<br \/>\n7 \u5185\u5bb9\u534f\u5546<\/p>\n<p>Ultimate ASP.NET Core Web API  8 METHOD SAFETY AND METHOD IDEMPOTENCY<br \/>\n8 \u65b9\u6cd5\u5b89\u5168\u548c\u65b9\u6cd5\u5e42\u7b49\u6027<\/p>\n<p>Ultimate ASP.NET Core Web API  9 CREATING RESOURCES<br \/>\n9 \u521b\u5efa\u8d44\u6e90<\/p>\n<p>Ultimate ASP.NET Core Web API 10 WORKING WITH DELETE REQUESTS<br \/>\n10 \u4f7f\u7528 DELETE \u8bf7\u6c42<\/p>\n<p>Ultimate ASP.NET Core Web API 11 WORKING WITH PUT REQUESTS<br \/>\n11 \u4f7f\u7528 PUT \u8bf7\u6c42<\/p>\n<p>Ultimate ASP.NET Core Web API 12 WORKING WITH PATCH REQUESTS<br \/>\n12 \u4f7f\u7528PATCH\u8bf7\u6c42<\/p>\n<p>Ultimate ASP.NET Core Web API 13 VALIDATION<br \/>\n13 \u9a8c\u8bc1<\/p>\n<p>Ultimate ASP.NET Core Web API 14 ASYNCHRONOUS CODE<br \/>\n14 \u5f02\u6b65\u4ee3\u7801<\/p>\n<p>Ultimate ASP.NET Core Web API 15 ACTION FILTERS<br \/>\n15 \u52a8\u4f5c\u8fc7\u6ee4\u5668<\/p>\n<p>Ultimate ASP.NET Core Web API 16 PAGING<br \/>\n16 \u5206\u9875<\/p>\n<p>Ultimate ASP.NET Core Web API 17 FILTERING<br \/>\n17 \u8fc7\u6ee4<\/p>\n<p>Ultimate ASP.NET Core Web API 18 SEARCHING<br \/>\n18 \u641c\u7d22<\/p>\n<p>Ultimate ASP.NET Core Web API 19 SORTING<br \/>\n19 \u6392\u5e8f<\/p>\n<p>Ultimate ASP.NET Core Web API 20 DATA SHAPING<br \/>\n20 \u6570\u636e\u6574\u5f62<\/p>\n<p>Ultimate ASP.NET Core Web API 21 SUPPORTING HATEOAS<br \/>\n21 \u652f\u6301 HATEOAS<\/p>\n<p>Ultimate ASP.NET Core Web API 22 WORKING WITH OPTIONS AND HEAD REQUESTS<br \/>\n22 \u4f7f\u7528 OPTIONS \u548c HEAD \u8bf7\u6c42<\/p>\n<p>Ultimate ASP.NET Core Web API 23 ROOT DOCUMENT<br \/>\n23 \u6839\u6587\u6863<\/p>\n<p>Ultimate ASP.NET Core Web API 24 VERSIONING APIS<br \/>\n24 API\u7248\u672c\u63a7\u5236 <\/p>\n<p>Ultimate ASP.NET Core Web API 25 CACHING<br \/>\n25 \u7f13\u5b58<\/p>\n<p>Ultimate ASP.NET Core Web API 26 RATE LIMITING AND THROTTLING<br \/>\n26 \u901f\u7387\u9650\u5236<\/p>\n<p>Ultimate ASP.NET Core Web API 27 JWT, IDENTITY, AND REFRESH TOKEN<br \/>\n27 \u4e2a JWT\u3001\u8eab\u4efd\u548c\u5237\u65b0\u4ee4\u724c<\/p>\n<p>Ultimate ASP.NET Core Web API 28 REFRESH TOKEN<br \/>\n28 \u5237\u65b0\u4ee4\u724c<\/p>\n<p>Ultimate ASP.NET Core Web API 29 BINDING CONFIGURATION AND OPTIONS PATTERN<br \/>\n29 \u7ed1\u5b9a\u914d\u7f6e\u548c\u9009\u9879\u6a21\u5f0f<\/p>\n<p>Ultimate ASP.NET Core Web API 30 DOCUMENTING API WITH SWAGGER<br \/>\n30 \u4f7f\u7528 SWAGGER \u7f16\u5199 API \u6587\u6863<\/p>\n<p>Ultimate ASP.NET Core Web API 31 DEPLOYMENT TO IIS<br \/>\n31 \u90e8\u7f72\u5230 IIS<\/p>\n<p>Ultimate ASP.NET Core Web API 32 BONUS 1 - RESPONSE PERFORMANCE IMPROVEMENTS<br \/>\n32 \u8d60\u9001\u7ae0\u8282 1 - \u54cd\u5e94\u6027\u80fd\u6539\u8fdb<\/p>\n<p>Ultimate ASP.NET Core Web API 33 BONUS 2 - INTRODUCTION TO CQRS AND MEDIATR WITH ASP.NET CORE WEB API<br \/>\n33 \u8d60\u9001\u7ae0\u8282 2 - \u4f7f\u7528 ASP.NET \u6838\u5fc3 WEB API \u7684 CQRS \u548c MEDIATR \u7b80\u4ecb<\/p>\n<h1>1 Project configuration<\/h1>\n<p>1 \u9879\u76ee\u914d\u7f6e<\/p>\n<p>Configuration in .NET Core is very different from what we\u2019re used to in\u200c .NET Framework projects. We don\u2019t use the web.config file anymore, but instead, use a built-in Configuration framework that comes out of the box in .NET Core.<br \/>\n\u914d\u7f6e.NET Core \u4e0e\u6211\u4eec\u4e60\u60ef\u7684 .NET Framework \u4e0d\u540c\uff0c\u4e0d\u518d\u4f7f\u7528 web.config \u6587\u4ef6\uff0c\u800c\u662f\u4f7f\u7528\u5f00\u7bb1\u5373\u7528\u7684\u5185\u7f6e\u914d\u7f6e\u6846\u67b6\u3002<\/p>\n<p>To be able to develop good applications, we need to understand how to configure our application and its services first.<br \/>\n\u4e3a\u4e86\u80fd\u591f\u5f00\u53d1\u597d\u7684\u5e94\u7528\u7a0b\u5e8f\uff0c\u9700\u8981\u9996\u5148\u4e86\u89e3\u5982\u4f55\u914d\u7f6e\u5e94\u7528\u7a0b\u5e8f\u53ca\u5176\u670d\u52a1\u3002<\/p>\n<p>In this section, we\u2019ll learn about configuration in the Program class and set up our application. We will also learn how to register different services and how to use extension methods to achieve this.<br \/>\n\u5728\u672c\u8282\u4e2d\uff0c\u5c06\u4e86\u89e3 Program \u7c7b\u4e2d\u7684\u914d\u7f6e\u5e76\u8bbe\u7f6e\u5e94\u7528\u7a0b\u5e8f\u3002\u8fd8\u5c06\u5b66\u4e60\u6ce8\u518c\u4e0d\u540c\u7684\u670d\u52a1\uff0c\u4ee5\u53ca\u4f7f\u7528\u6269\u5c55\u65b9\u6cd5\u6765\u5b9e\u73b0\u8fd9\u4e00\u70b9\u3002<\/p>\n<p>Of course, the first thing we need to do is to create a new project, so,let\u2019s dive right into it.<br \/>\n\u5f53\u7136\uff0c\u9700\u8981\u505a\u7684\u7b2c\u4e00\u4ef6\u4e8b\u662f\u521b\u5efa\u4e00\u4e2a\u65b0\u9879\u76ee\uff0c\u6240\u4ee5\uff0c\u76f4\u63a5\u5f00\u59cb\u5427\u3002<\/p>\n<h2>1.1 Creating a New Project<\/h2>\n<p>1.1 \u521b\u5efa\u65b0\u9879\u76ee<\/p>\n<p>Let's open Visual Studio, we are going to use VS 2022, and create a new ASP.NET Core Web API Application:\u200c<br \/>\n\u6253\u5f00Visual Studio\uff0c\u6211\u4eec\u5c06\u4f7f\u7528 VS 2022\uff0c\u521b\u5efa\u4e00\u4e2a\u65b0\u7684 ASP.NET Core Web API \u5e94\u7528\u7a0b\u5e8f\uff1a<\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/0101.jpg\" alt=\"alt text\" \/><\/p>\n<p>Now let\u2019s choose a name and location for our project:<br \/>\n\u7ed9\u9879\u76ee\u9009\u62e9\u4e00\u4e2a\u540d\u79f0\u548c\u4f4d\u7f6e\uff1a<\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/0102.jpg\" alt=\"alt text\" \/><\/p>\n<p>Next, we want to choose a .NET 6.0 from the dropdown list. Also, we don\u2019t want to enable OpenAPI support right now. We\u2019ll do that later in the book on our own. Now we can proceed by clicking the Create button and the project will start initializing:<br \/>\n\u63a5\u4e0b\u6765\uff0c\u6211\u4eec\u8981\u4ece\u4e0b\u62c9\u5217\u8868\u4e2d\u9009\u62e9 .NET 6.0\u3002\u6b64\u5916\uff0c\u6211\u4eec\u73b0\u5728\u4e0d\u60f3\u542f\u7528 OpenAPI \u652f\u6301\u3002\u6211\u4eec\u5c06\u5728\u672c\u4e66\u7684\u540e\u9762\u81ea\u5df1\u505a\u8fd9\u4ef6\u4e8b\u3002\u73b0\u5728\uff0c\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u5355\u51fb Create \u6309\u94ae\u7ee7\u7eed\uff0c\u9879\u76ee\u5c06\u5f00\u59cb\u521d\u59cb\u5316\uff1a<\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/0103.jpg\" alt=\"alt text\" \/><\/p>\n<h2>1.2 launchSettings.json File Configuration<\/h2>\n<p>1.2 launchSettings.json \u6587\u4ef6\u914d\u7f6e<\/p>\n<p>After the project has been created, we are going to modify the launchSettings.json file, which can be found in the Properties section of the Solution Explorer window.\u200c<br \/>\n\u521b\u5efa\u9879\u76ee\u540e\uff0c\u6211\u4eec\u5c06\u4fee\u6539 launchSettings.json \u6587\u4ef6\uff0c\u8be5\u6587\u4ef6\u53ef\u4ee5\u5728 Solution Explorer \u7a97\u53e3\u7684 Properties \u90e8\u5206\u627e\u5230\u3002<\/p>\n<p>This configuration determines the launch behavior of the ASP.NET Core applications. As we can see, it contains both configurations to launch settings for IIS and self-hosted applications (Kestrel).<br \/>\n\u6b64\u914d\u7f6e\u51b3\u5b9a\u4e86 ASP.NET Core \u5e94\u7528\u7a0b\u5e8f\u7684\u542f\u52a8\u884c\u4e3a\u3002\u6b63\u5982\u6211\u4eec\u6240\u770b\u5230\u7684\uff0c\u5b83\u5305\u542b\u7528\u4e8e\u542f\u52a8 IIS \u8bbe\u7f6e\u7684\u914d\u7f6e\u548c\u81ea\u6258\u7ba1\u5e94\u7528\u7a0b\u5e8f \uff08Kestrel\uff09\u3002<\/p>\n<p>For now, let\u2019s change the launchBrowser property to false to prevent the web browser from launching on application start.<br \/>\n\u73b0\u5728\uff0c\u8ba9\u6211\u4eec\u5c06 launchBrowser \u5c5e\u6027\u66f4\u6539\u4e3a false\uff0c\u4ee5\u9632\u6b62 Web \u6d4f\u89c8\u5668\u5728\u5e94\u7528\u7a0b\u5e8f\u542f\u52a8\u65f6\u542f\u52a8\u3002<\/p>\n<pre><code>{\n  &quot;$schema&quot;: &quot;http:\/\/json.schemastore.org\/launchsettings.json&quot;,\n  &quot;iisSettings&quot;: {\n    &quot;windowsAuthentication&quot;: false,\n    &quot;anonymousAuthentication&quot;: true,\n    &quot;iisExpress&quot;: {\n      &quot;applicationUrl&quot;: &quot;http:\/\/localhost:1629&quot;,\n      &quot;sslPort&quot;: 44370\n    }\n  },\n  &quot;profiles&quot;: {\n    &quot;CompanyEmployees&quot;: {\n        &quot;commandName&quot;: &quot;Project&quot;,\n        &quot;dotnetRunMessages&quot;: true,\n        &quot;launchBrowser&quot;: false,\n        &quot;launchUrl&quot;: &quot;weatherforecast&quot;,\n        &quot;applicationUrl&quot;: &quot;https:\/\/localhost:5001;http:\/\/localhost:5000&quot;,\n        &quot;environmentVariables&quot;: {\n            &quot;ASPNETCORE_ENVIRONMENT&quot;: &quot;Development&quot;\n        }\n    },\n    &quot;IIS Express&quot;: {\n      &quot;commandName&quot;: &quot;IISExpress&quot;,\n      &quot;launchBrowser&quot;: true,\n      &quot;launchUrl&quot;: &quot;weatherforecast&quot;,\n      &quot;environmentVariables&quot;: {\n        &quot;ASPNETCORE_ENVIRONMENT&quot;: &quot;Development&quot;\n      }\n    }\n  }\n}<\/code><\/pre>\n<p>This is convenient since we are developing a Web API project and we don\u2019t need a browser to check our API out. We will use Postman (described later) for this purpose.<br \/>\n\u8fd9\u5f88\u65b9\u4fbf\uff0c\u56e0\u4e3a\u6211\u4eec\u6b63\u5728\u5f00\u53d1\u4e00\u4e2a Web API \u9879\u76ee\uff0c\u6211\u4eec\u4e0d\u9700\u8981\u6d4f\u89c8\u5668\u6765\u68c0\u67e5\u6211\u4eec\u7684 API\u3002\u4e3a\u6b64\uff0c\u6211\u4eec\u5c06\u4f7f\u7528 Postman\uff08\u7a0d\u540e\u4ecb\u7ecd\uff09\u3002<\/p>\n<p>If you\u2019ve checked Configure for HTTPS checkbox earlier in the setup phase, you will end up with two URLs in the applicationUrl section \u2014 one for HTTPS (localhost:5001), and one for HTTP (localhost:5000).<br \/>\n\u5982\u679c\u60a8\u5728\u521b\u5efa\u9879\u76ee\u65f6\u9009\u4e2d\u4e86 Configure for HTTPS \u590d\u9009\u6846\uff0c\u5219 applicationUrl \u90e8\u5206\u6700\u7ec8\u4f1a\u6709\u4e24\u4e2a URL\u2014\u2014\u4e00\u4e2a\u7528\u4e8e HTTPS \uff08localhost\uff1a5001\uff09\uff0c\u4e00\u4e2a\u7528\u4e8e HTTP \uff08localhost\uff1a5000\uff09\u3002<\/p>\n<p>You\u2019ll also notice the sslPort property which indicates that our application, when running in IISExpress, will be configured for HTTPS (port 44370), too.<br \/>\n\u60a8\u8fd8\u4f1a\u6ce8\u610f\u5230 sslPort \u5c5e\u6027\uff0c\u8be5\u5c5e\u6027\u6307\u793a\u6211\u4eec\u7684\u5e94\u7528\u7a0b\u5e8f\u5728 IISExpress \u4e2d\u8fd0\u884c\u65f6\uff0c\u4e5f\u5c06\u914d\u7f6e\u4e3a HTTPS\uff08\u7aef\u53e3 44370\uff09\u3002<\/p>\n<p><b>NOTE:<\/b> This HTTPS configuration is only valid in the local environment. You will have to configure a valid certificate and HTTPS redirection once you deploy the application.<br \/>\n\u6ce8\u610f\uff1a\u6b64 HTTPS \u914d\u7f6e\u4ec5\u5728\u672c\u5730\u73af\u5883\u4e2d\u6709\u6548\u3002\u90e8\u7f72\u5e94\u7528\u7a0b\u5e8f\u540e\uff0c\u60a8\u5fc5\u987b\u914d\u7f6e\u6709\u6548\u7684\u8bc1\u4e66\u548c HTTPS \u91cd\u5b9a\u5411\u3002<\/p>\n<p>There is one more useful property for developing applications locally and that\u2019s the launchUrl property. This property determines which URL will the application navigate to initially. For launchUrl property to work, we need to set the launchBrowser property to true. So, for example, if we set the launchUrl property to weatherforecast, we will be redirected to <a href=\"https:\/\/localhost:5001\/weatherforecast\">https:\/\/localhost:5001\/weatherforecast<\/a> when we launch our application.<br \/>\n\u8fd8\u6709\u4e00\u4e2a\u7528\u4e8e\u5728\u672c\u5730\u5f00\u53d1\u5e94\u7528\u7a0b\u5e8f\u7684\u6709\u7528\u5c5e\u6027\uff0c\u5373 launchUrl \u5c5e\u6027\u3002\u6b64\u5c5e\u6027\u786e\u5b9a\u5e94\u7528\u7a0b\u5e8f\u6700\u521d\u5c06\u5bfc\u822a\u5230\u54ea\u4e2a URL\u3002\u8981\u4f7f launchUrl \u5c5e\u6027\u6b63\u5e38\u5de5\u4f5c\uff0c\u6211\u4eec\u9700\u8981\u5c06 launchBrowser \u5c5e\u6027\u8bbe\u7f6e\u4e3a true\u3002\u56e0\u6b64\uff0c\u4f8b\u5982\uff0c\u5982\u679c\u6211\u4eec\u5c06 launchUrl \u5c5e\u6027\u8bbe\u7f6e\u4e3a weatherforecast\uff0c\u5219\u5f53\u6211\u4eec\u542f\u52a8\u5e94\u7528\u7a0b\u5e8f\u65f6\uff0c\u6211\u4eec\u5c06\u91cd\u5b9a\u5411\u5230 <a href=\"https:\/\/localhost:5001\/weatherforecast\">https:\/\/localhost:5001\/weatherforecast<\/a>\u3002<\/p>\n<h2>1.3 Program.cs Class Explanations<\/h2>\n<p>1.3 Program.cs \u7c7b\u8bf4\u660e<\/p>\n<p>Program.cs is the entry point to our application and it looks like this:\u200c<br \/>\nProgram.cs \u662f\u6211\u4eec\u5e94\u7528\u7a0b\u5e8f\u7684\u5165\u53e3\u70b9\uff0c\u5b83\u770b\u8d77\u6765\u50cf\u8fd9\u6837\uff1a<\/p>\n<pre><code>var builder = WebApplication.CreateBuilder(args);\n\n\/\/ Add services to the container.\n\nbuilder.Services.AddControllers();\n\nvar app = builder.Build();\n\n\/\/ Configure the HTTP request pipeline.\n\napp.UseHttpsRedirection();\n\napp.UseAuthorization();\n\napp.MapControllers();\n\napp.Run();\n<\/code><\/pre>\n<p>Compared to the Program.cs class from .NET 5, there are some major changes. Some of the most obvious are:<br \/>\n\u4e0e .NET 5 \u4e2d\u7684 Program.cs \u7c7b\u76f8\u6bd4\uff0c\u6709\u4e00\u4e9b\u91cd\u5927\u53d8\u5316\u3002\u4e00\u4e9b\u6700\u660e\u663e\u7684\u662f\uff1a<\/p>\n<p>\u2022 Top-level statements<br \/>\n\u2022 \u9876\u7ea7\u8bed\u53e5<\/p>\n<p>\u2022 Implicit using directives<br \/>\n\u2022 \u9690\u5f0f using \u6307\u4ee4<\/p>\n<p>\u2022 No Startup class (on the project level)<br \/>\n\u2022 \u65e0 Startup \u7c7b\uff08\u5728\u9879\u76ee\u7ea7\u522b\uff09<\/p>\n<p>\u201cTop-level statements\u201d means the compiler generates the namespace, class, and method elements for the main program in our application. We can see that we don\u2019t have the class block in the code nor the Main method. All of that is generated for us by the compiler. Of course, we can add other functions to the Program class and those will be created as the local functions nested inside the generated Main method. Top-level statements are meant to simplify the entry point to the application and remove the extra \u201cfluff\u201d so we can focus on the important stuff instead.<br \/>\n\u201c\u9876\u7ea7\u8bed\u53e5\u201d\u662f\u6307\u7f16\u8bd1\u5668\u4e3a\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u4e3b\u7a0b\u5e8f\u751f\u6210\u547d\u540d\u7a7a\u95f4\u3001\u7c7b\u548c\u65b9\u6cd5\u5143\u7d20\u3002\u6211\u4eec\u53ef\u4ee5\u770b\u5230\uff0c\u4ee3\u7801\u4e2d\u6ca1\u6709 class \u5757\uff0c\u4e5f\u6ca1\u6709 Main \u65b9\u6cd5\u3002\u6240\u6709\u8fd9\u4e9b\u90fd\u662f\u7531\u7f16\u8bd1\u5668\u4e3a\u6211\u4eec\u751f\u6210\u7684\u3002\u5f53\u7136\uff0c\u6211\u4eec\u53ef\u4ee5\u5411 Program \u7c7b\u6dfb\u52a0\u5176\u4ed6\u51fd\u6570\uff0c\u8fd9\u4e9b\u51fd\u6570\u5c06\u521b\u5efa\u4e3a\u5d4c\u5957\u5728\u751f\u6210\u7684 Main \u65b9\u6cd5\u4e2d\u7684\u672c\u5730\u51fd\u6570\u3002\u9876\u7ea7\u8bed\u53e5\u65e8\u5728\u7b80\u5316\u5e94\u7528\u7a0b\u5e8f\u7684\u5165\u53e3\u70b9\u5e76\u5220\u9664\u989d\u5916\u7684 \u201c\u7ed2\u6bdb\u201d\uff0c\u4ee5\u4fbf\u6211\u4eec\u53ef\u4ee5\u4e13\u6ce8\u4e8e\u91cd\u8981\u7684\u4e1c\u897f\u3002<\/p>\n<p>\u201cImplicit using directives\u201d mean the compiler automatically adds a different set of using directives based on a project type, so we don\u2019t have to do that manually. These using directives are stored in the obj\/Debug\/net6.0 folder of our project under the name CompanyEmployees.GlobalUsings.g.cs:<br \/>\n\u201c\u9690\u5f0f using \u6307\u4ee4\u201d\u610f\u5473\u7740\u7f16\u8bd1\u5668\u4f1a\u6839\u636e\u9879\u76ee\u7c7b\u578b\u81ea\u52a8\u6dfb\u52a0\u4e00\u7ec4\u4e0d\u540c\u7684 using \u6307\u4ee4\uff0c\u56e0\u6b64\u6211\u4eec\u4e0d\u5fc5\u624b\u52a8\u6267\u884c\u6b64\u4f5c\u3002\u8fd9\u4e9b using \u6307\u4ee4\u5b58\u50a8\u5728\u9879\u76ee\u7684 obj\/Debug\/net6.0 \u6587\u4ef6\u5939\u4e2d\uff0c\u540d\u79f0\u4e3a CompanyEmployees.GlobalUsings.g.cs\uff1a<\/p>\n<pre><code>\/\/ &lt;auto-generated\/&gt;\nglobal using global::Microsoft.AspNetCore.Builder;\nglobal using global::Microsoft.AspNetCore.Hosting;\nglobal using global::Microsoft.AspNetCore.Http;\nglobal using global::Microsoft.AspNetCore.Routing;\nglobal using global::Microsoft.Extensions.Configuration;\nglobal using global::Microsoft.Extensions.DependencyInjection;\nglobal using global::Microsoft.Extensions.Hosting;\nglobal using global::Microsoft.Extensions.Logging;\nglobal using global::System;\nglobal using global::System.Collections.Generic;\nglobal using global::System.IO;\nglobal using global::System.Linq;\nglobal using global::System.Net.Http;\nglobal using global::System.Net.Http.Json;\nglobal using global::System.Threading;\nglobal using global::System.Threading.Tasks;<\/code><\/pre>\n<p>This means that we can use different classes from these namespaces in our project without adding using directives explicitly in our project files. Of course, if you don\u2019t want this type of behavior, you can turn it off by visiting the project file and disabling the ImplicitUsings tag:<br \/>\n\u8fd9\u610f\u5473\u7740\u6211\u4eec\u53ef\u4ee5\u5728\u9879\u76ee\u4e2d\u4f7f\u7528\u6765\u81ea\u8fd9\u4e9b\u547d\u540d\u7a7a\u95f4\u7684\u4e0d\u540c\u7c7b\uff0c\u800c\u65e0\u9700\u5728\u9879\u76ee\u6587\u4ef6\u4e2d\u663e\u5f0f\u6dfb\u52a0 using \u6307\u4ee4\u3002\u5f53\u7136\uff0c\u5982\u679c\u60a8\u4e0d\u5e0c\u671b\u51fa\u73b0\u6b64\u7c7b\u884c\u4e3a\uff0c\u53ef\u4ee5\u901a\u8fc7\u8bbf\u95ee\u9879\u76ee\u6587\u4ef6\u5e76\u7981\u7528 ImplicitUsings \u6807\u7b7e\u6765\u5173\u95ed\u5b83\uff1a<\/p>\n<pre><code>&lt;ImplicitUsings&gt;disable&lt;\/ImplicitUsings&gt;<\/code><\/pre>\n<p>By default, this is enabled in the .csproj file, and we are going to keep it like that.<br \/>\n\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u8fd9\u5728 .csproj \u6587\u4ef6\u4e2d\u5904\u4e8e\u542f\u7528\u72b6\u6001\uff0c\u6211\u4eec\u5c06\u4fdd\u6301\u8fd9\u79cd\u72b6\u6001\uff08\u4e0d\u8981\u53bb\u4fee\u6539\u5b83\uff09\u3002<\/p>\n<p>Now, let\u2019s take a look at the code inside the Program class. With this line of code:<br \/>\n\u73b0\u5728\uff0c\u8ba9\u6211\u4eec\u770b\u770b Program \u7c7b\u4e2d\u7684\u4ee3\u7801\u3002\u4f7f\u7528\u8fd9\u884c\u4ee3\u7801\uff1a<\/p>\n<pre><code>var builder = WebApplication.CreateBuilder(args);<\/code><\/pre>\n<p>The application creates a builder variable of the type WebApplicationBuilder. The WebApplicationBuilder class is responsible for four main things:<br \/>\n\u5e94\u7528\u7a0b\u5e8f\u5c06\u521b\u5efa\u4e00\u4e2a WebApplicationBuilder \u7c7b\u578b\u7684 builder \u53d8\u91cf\u3002WebApplicationBuilder \u7c7b\u8d1f\u8d23\u56db\u4e2a\u4e3b\u8981\u4efb\u52a1\uff1a<\/p>\n<p>\u2022 Adding Configuration to the project by using the builder.Configuration property<br \/>\n\u2022 \u4f7f\u7528builder.Configuration\u6784\u5efa\u5668\u5c06\u914d\u7f6e\u6dfb\u52a0\u5230\u9879\u76ee\u4e2d<\/p>\n<p>\u2022 Registering services in our app with the builder.Services property<br \/>\n\u2022 \u4f7f\u7528builder.Services\u6784\u5efa\u5668\u5728\u6211\u4eec\u7684\u5e94\u7528\u7a0b\u5e8f\u4e2d\u6ce8\u518c\u670d\u52a1<\/p>\n<p>\u2022 Logging configuration with the builder.Logging property<br \/>\n\u2022 \u4f7f\u7528builder.Logging\u751f\u6210\u5668\u8fdb\u884c\u65e5\u5fd7\u8bb0\u5f55\u914d\u7f6e<\/p>\n<p>\u2022 Other IHostBuilder and IWebHostBuilder configuration<br \/>\n\u2022 \u5176\u4ed6 IHostBuilder \u548c IWebHostBuilder \u914d\u7f6e<\/p>\n<p>Compared to .NET 5 where we had a static CreateDefaultBuilder class, which returned the IHostBuilder type, now we have the static CreateBuilder method, which returns WebApplicationBuilder type.<br \/>\n\u4e0e .NET 5 \u76f8\u6bd4\uff0c\u6211\u4eec\u6709\u4e00\u4e2a\u9759\u6001 CreateDefaultBuilder \u7c7b\uff0c\u5b83\u8fd4\u56de IHostBuilder \u7c7b\u578b\uff0c\u73b0\u5728\u6211\u4eec\u6709\u9759\u6001 CreateBuilder \u65b9\u6cd5\uff0c\u5b83\u8fd4\u56de WebApplicationBuilder \u7c7b\u578b\u3002<\/p>\n<p>Of course, as we see it, we don\u2019t have the Startup class with two familiar methods: ConfigureServices and Configure. Now, all this is replaced by the code inside the Program.cs file.<br \/>\n\u5f53\u7136\uff0c\u6b63\u5982\u6211\u4eec\u6240\u770b\u5230\u7684\uff0c\u6211\u4eec\u6ca1\u6709\u5305\u542b\u4e24\u4e2a\u719f\u6089\u65b9\u6cd5\u7684 Startup \u7c7b\uff1aConfigureServices \u548c Configure\u3002\u73b0\u5728\uff0c\u6240\u6709\u8fd9\u4e9b\u90fd\u88ab Program.cs \u6587\u4ef6\u4e2d\u7684\u4ee3\u7801\u66ff\u6362\u4e86\u3002<\/p>\n<p>Since we don\u2019t have the ConfigureServices method to configure our services, we can do that right below the builder variable declaration. In the new template, there\u2019s even a comment section suggesting where we should start with service registration. A service is a reusable part of the code that adds some functionality to our application, but we\u2019ll talk about services more later on.<br \/>\n\u7531\u4e8e\u6211\u4eec\u6ca1\u6709 ConfigureServices \u65b9\u6cd5\u6765\u914d\u7f6e\u6211\u4eec\u7684\u670d\u52a1\uff0c\u56e0\u6b64\u6211\u4eec\u53ef\u4ee5\u5728 builder \u53d8\u91cf\u58f0\u660e\u7684\u6b63\u4e0b\u65b9\u6267\u884c\u6b64\u4f5c\u3002\u5728\u65b0\u6a21\u677f\u4e2d\uff0c\u751a\u81f3\u8fd8\u6709\u4e00\u4e2a\u6ce8\u91ca\u90e8\u5206\uff0c\u5efa\u8bae\u6211\u4eec\u5e94\u8be5\u4ece\u54ea\u91cc\u5f00\u59cb\u670d\u52a1\u6ce8\u518c\u3002\u670d\u52a1\u662f\u4ee3\u7801\u7684\u53ef\u91cd\u7528\u90e8\u5206\uff0c\u5b83\u4e3a\u5e94\u7528\u7a0b\u5e8f\u6dfb\u52a0\u4e86\u4e00\u4e9b\u529f\u80fd\uff0c\u4f46\u6211\u4eec\u7a0d\u540e\u5c06\u66f4\u591a\u5730\u8ba8\u8bba\u670d\u52a1\u3002<\/p>\n<p>In .NET 5, we would use the Configure method to add different middleware components to the application\u2019s request pipeline. But since we don\u2019t have that method anymore, we can use the section below the var app = builder.Build(); part to do that. Again, this is marked with the comment section as well:<br \/>\n\u5728 .NET 5 \u4e2d\uff0c\u6211\u4eec\u5c06\u4f7f\u7528 Configure \u65b9\u6cd5\u5c06\u4e0d\u540c\u7684\u4e2d\u95f4\u4ef6\u7ec4\u4ef6\u6dfb\u52a0\u5230\u5e94\u7528\u7a0b\u5e8f\u7684\u8bf7\u6c42\u7ba1\u9053\u4e2d\u3002\u4f46\u662f\u7531\u4e8e\u6211\u4eec\u4e0d\u518d\u6709\u8be5\u65b9\u6cd5\uff0c\u56e0\u6b64\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528 var app = builder.Build(); \u90e8\u5206\u6765\u505a\u5230\u8fd9\u4e00\u70b9\u3002\u540c\u6837\uff0c\u8fd9\u4e5f\u7528\u8bc4\u8bba\u90e8\u5206\u6807\u8bb0\uff1a<\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/0104.jpg\" alt=\"alt text\" \/><\/p>\n<p><b>NOTE:<\/b>  If you still want to create your application using the .NET 5 way, with Program and Startup classes, you can do that, .NET 6 supports it as well. The easiest way is to create a .NET 5 project, copy the Startup and Program classes and paste it into the .NET 6 project.<br \/>\n\u6ce8\u610f\uff1a\u5982\u679c\u60a8\u4ecd\u5e0c\u671b\u4f7f\u7528 .NET 5 \u65b9\u5f0f\u521b\u5efa\u5e94\u7528\u7a0b\u5e8f\uff0c\u4f7f\u7528 Program \u548c Startup \u7c7b\uff0c\u60a8\u53ef\u4ee5\u8fd9\u6837\u505a\uff0c.NET 6 \u4e5f\u652f\u6301\u5b83\u3002\u6700\u7b80\u5355\u7684\u65b9\u6cd5\u662f\u521b\u5efa\u4e00\u4e2a .NET 5 \u9879\u76ee\uff0c\u590d\u5236 Startup \u548c Program \u7c7b\u5e76\u5c06\u5176\u7c98\u8d34\u5230 .NET 6 \u9879\u76ee\u4e2d\u3002<\/p>\n<p>Since larger applications could potentially contain a lot of different services, we can end up with a lot of clutter and unreadable code in the Program class. To make it more readable for the next person and ourselves, we can structure the code into logical blocks and separate those blocks into extension methods.<br \/>\n\u7531\u4e8e\u8f83\u5927\u7684\u5e94\u7528\u7a0b\u5e8f\u53ef\u80fd\u5305\u542b\u8bb8\u591a\u4e0d\u540c\u7684\u670d\u52a1\uff0c\u56e0\u6b64\u6211\u4eec\u6700\u7ec8\u4f1a\u5728 Program \u7c7b\u4e2d\u5f97\u5230\u5f88\u591a\u6742\u4e71\u548c\u4e0d\u53ef\u8bfb\u7684\u4ee3\u7801\u3002\u4e3a\u4e86\u8ba9\u4e0b\u4e00\u4e2a\u4eba\u548c\u6211\u4eec\u81ea\u5df1\u66f4\u5177\u53ef\u8bfb\u6027\uff0c\u6211\u4eec\u53ef\u4ee5\u5c06\u4ee3\u7801\u6784\u5efa\u6210\u903b\u8f91\u5757\uff0c\u5e76\u5c06\u8fd9\u4e9b\u5757\u5206\u79bb\u5230\u6269\u5c55\u65b9\u6cd5\u4e2d\u3002<\/p>\n<h2>1.4 Extension Methods and CORS Configuration<\/h2>\n<p>1.4 \u6269\u5c55\u65b9\u6cd5\u548c CORS \u914d\u7f6e<\/p>\n<p>An extension method is inherently a static method. What makes it different from other static methods is that it accepts this as the first parameter, and this represents the data type of the object which will be using that extension method. We\u2019ll see what that means in a moment.\u200c<br \/>\n\u6269\u5c55\u65b9\u6cd5\u672c\u8d28\u4e0a\u662f\u4e00\u79cd\u9759\u6001\u65b9\u6cd5\u3002\u5b83\u4e0e\u5176\u4ed6\u9759\u6001\u65b9\u6cd5\u7684\u4e0d\u540c\u4e4b\u5904\u5728\u4e8e\uff0c\u5b83\u63a5\u53d7 this \u4f5c\u4e3a\u7b2c\u4e00\u4e2a\u53c2\u6570\uff0c\u8fd9\u8868\u793a\u5c06\u4f7f\u7528\u8be5\u6269\u5c55\u65b9\u6cd5\u7684\u5bf9\u8c61\u7684\u6570\u636e\u7c7b\u578b\u3002\u6211\u4eec\u7a0d\u540e\u4f1a\u770b\u770b\u8fd9\u610f\u5473\u7740\u4ec0\u4e48\u3002<\/p>\n<p>An extension method must be defined inside a static class. This kind of method extends the behavior of a type in .NET. Once we define an extension method, it can be chained multiple times on the same type of object.<br \/>\n\u5fc5\u987b\u5728 static \u7c7b\u4e2d\u5b9a\u4e49\u6269\u5c55\u65b9\u6cd5\u3002\u6b64\u65b9\u6cd5\u6269\u5c55\u4e86 .NET \u4e2d\u7c7b\u578b\u7684\u884c\u4e3a\u3002\u4e00\u65e6\u6211\u4eec\u5b9a\u4e49\u4e86\u4e00\u4e2a\u6269\u5c55\u65b9\u6cd5\uff0c\u5b83\u5c31\u53ef\u4ee5\u5728\u540c\u4e00\u7c7b\u578b\u7684\u5bf9\u8c61\u4e0a\u88ab\u591a\u6b21\u94fe\u63a5\u3002<\/p>\n<p>So, let\u2019s start writing some code to see how it all adds up.<br \/>\n\u90a3\u4e48\uff0c\u8ba9\u6211\u4eec\u5f00\u59cb\u7f16\u5199\u4e00\u4e9b\u4ee3\u7801\uff0c\u770b\u770b\u8fd9\u4e00\u5207\u662f\u5982\u4f55\u52a0\u8d77\u6765\u7684\u3002<\/p>\n<p>We are going to create a new folder Extensions in the project and create a new class inside that folder named ServiceExtensions. The ServiceExtensions class should be static.<br \/>\n\u6211\u4eec\u5c06\u5728\u9879\u76ee\u4e2d\u521b\u5efa\u4e00\u4e2a\u65b0\u6587\u4ef6\u5939 Extensions\uff0c\u5e76\u5728\u8be5\u6587\u4ef6\u5939\u4e2d\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a ServiceExtensions \u7684\u65b0\u7c7b\u3002ServiceExtensions \u7c7b\u5e94\u8be5\u662f static \u7c7b\u3002<\/p>\n<pre><code>namespace CompanyEmployees.Extensions\n{\n    public static class ServiceExtensions\n    {\n    }\n}<\/code><\/pre>\n<p>Let\u2019s start by implementing something we need for our project immediately so we can see how extensions work.<br \/>\n\u8ba9\u6211\u4eec\u7acb\u5373\u5f00\u59cb\u5b9e\u73b0\u9879\u76ee\u6240\u9700\u7684\u5185\u5bb9\uff0c\u4ee5\u4fbf\u4e86\u89e3\u6269\u5c55\u7684\u5de5\u4f5c\u539f\u7406\u3002<\/p>\n<p>The first thing we are going to do is to configure CORS in our application. CORS (Cross-Origin Resource Sharing) is a mechanism to give or restrict access rights to applications from different domains.<br \/>\n\u6211\u4eec\u8981\u505a\u7684\u7b2c\u4e00\u4ef6\u4e8b\u662f\u5728\u6211\u4eec\u7684\u5e94\u7528\u7a0b\u5e8f\u4e2d\u914d\u7f6e CORS\u3002CORS\uff08\u8de8\u57df\u8d44\u6e90\u5171\u4eab\uff09\u662f\u4e00\u79cd\u673a\u5236\uff0c\u7528\u4e8e\u6388\u4e88\u6216\u9650\u5236\u6765\u81ea\u4e0d\u540c\u57df\u7684\u5e94\u7528\u7a0b\u5e8f\u7684\u8bbf\u95ee\u6743\u9650\u3002<\/p>\n<p>If we want to send requests from a different domain to our application, configuring CORS is mandatory. So, to start, we\u2019ll add a code that allows all requests from all origins to be sent to our API:<br \/>\n\u5982\u679c\u6211\u4eec\u60f3\u5c06\u8bf7\u6c42\u4ece\u5176\u4ed6\u57df\u53d1\u9001\u5230\u6211\u4eec\u7684\u5e94\u7528\u7a0b\u5e8f\uff0c\u5219\u5fc5\u987b\u914d\u7f6e CORS\u3002\u56e0\u6b64\uff0c\u9996\u5148\uff0c\u6211\u4eec\u5c06\u6dfb\u52a0\u4e00\u4e2a\u4ee3\u7801\uff0c\u5141\u8bb8\u6765\u81ea\u6240\u6709\u6765\u6e90\u7684\u6240\u6709\u8bf7\u6c42\u90fd\u53d1\u9001\u5230\u6211\u4eec\u7684 API\uff1a<\/p>\n<pre><code>namespace CompanyEmployees.Extensions\n{\n    public static class ServiceExtensions\n    {\n        public static void ConfigureCors(this IServiceCollection services) =&gt;\n            services.AddCors(options =&gt;\n            {\n                options.AddPolicy(&quot;CorsPolicy&quot;, builder =&gt;\n                builder.AllowAnyOrigin()\n                       .AllowAnyMethod()\n                       .AllowAnyHeader());\n            });\n    }\n}<\/code><\/pre>\n<p>We are using basic CORS policy settings because allowing any origin, method, and header is okay for now. But we should be more restrictive with those settings in the production environment. More precisely, as restrictive as possible.<br \/>\n\u6211\u4eec\u4f7f\u7528\u7684\u662f\u57fa\u672c\u7684 CORS \u7b56\u7565\u8bbe\u7f6e\uff0c\u56e0\u4e3a\u5141\u8bb8\u4efb\u4f55\u6e90\u3001\u65b9\u6cd5\u548c\u6807\u5934\u76ee\u524d\u662f\u53ef\u4ee5\u7684\u3002\u4f46\u662f\u6211\u4eec\u5e94\u8be5\u5728\u751f\u4ea7\u73af\u5883\u4e2d\u5bf9\u8fd9\u4e9b\u8bbe\u7f6e\u8fdb\u884c\u66f4\u591a\u9650\u5236\u3002\u66f4\u51c6\u786e\u5730\u8bf4\uff0c\u5c3d\u53ef\u80fd\u4e25\u683c\u3002<\/p>\n<p>Instead of the AllowAnyOrigin() method which allows requests from any source, we can use the WithOrigins(&quot;<a href=\"https:\/\/example.com\">https:\/\/example.com<\/a>&quot;) which will allow requests only from that concrete source. Also, instead of AllowAnyMethod() that allows all HTTP methods, we can use WithMethods(&quot;POST&quot;, &quot;GET&quot;) that will allow only specific HTTP methods. Furthermore, you can make the same changes for the AllowAnyHeader() method by using, for example, the WithHeaders(&quot;accept&quot;, &quot;content-type&quot;) method to allow only specific headers.<br \/>\n\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528 WithOrigins(&quot;<a href=\"https:\/\/example.com\">https:\/\/example.com<\/a>&quot;) \u65b9\u6cd5\uff0c\u800c\u4e0d\u662f\u5141\u8bb8\u6765\u81ea\u4efb\u4f55\u6e90\u7684\u8bf7\u6c42\u7684 AllowAnyOrigin() \u65b9\u6cd5\uff0c\u5b83\u5c06\u4ec5\u5141\u8bb8\u6765\u81ea\u8be5\u5177\u4f53\u6e90\u7684\u8bf7\u6c42\u3002\u6b64\u5916\uff0c\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528 WithMethods(&quot;POST&quot;, &quot;GET&quot;) \u6765\u53ea\u5141\u8bb8\u7279\u5b9a\u7684 HTTP \u65b9\u6cd5\uff0c\u800c\u4e0d\u662f\u5141\u8bb8\u6240\u6709 HTTP \u65b9\u6cd5\u7684 AllowAnyMethod()\u3002\u6b64\u5916\uff0c\u60a8\u53ef\u4ee5\u5bf9 AllowAnyHeader() \u65b9\u6cd5\u8fdb\u884c\u76f8\u540c\u7684\u66f4\u6539\uff0c\u4f8b\u5982\uff0c\u4f7f\u7528 WithHeaders(&quot;accept&quot;, &quot;content-type&quot;)\u65b9\u6cd5\u4ec5\u5141\u8bb8\u7279\u5b9a\u6807\u5934\u3002<\/p>\n<h2>1.5 IIS Configuration<\/h2>\n<p>1.5 IIS \u914d\u7f6e<\/p>\n<p>ASP.NET Core applications are by default self-hosted, and if we want to host our application on IIS, we need to configure an IIS integration which will eventually help us with the deployment to IIS. To do that, we need to add the following code to the ServiceExtensions class:\u200c<br \/>\n\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cASP.NET Core \u5e94\u7528\u7a0b\u5e8f\u662f\u81ea\u6258\u7ba1\u7684\uff0c\u5982\u679c\u6211\u4eec\u60f3\u5728 IIS \u4e0a\u6258\u7ba1\u5e94\u7528\u7a0b\u5e8f\uff0c\u5219\u9700\u8981\u914d\u7f6e IIS \u96c6\u6210\uff0c\u8fd9\u6700\u7ec8\u5c06\u5e2e\u52a9\u6211\u4eec\u90e8\u7f72\u5230 IIS\u3002\u4e3a\u6b64\uff0c\u6211\u4eec\u9700\u8981\u5c06\u4ee5\u4e0b\u4ee3\u7801\u6dfb\u52a0\u5230 ServiceExtensions \u7c7b\u4e2d\uff1a<\/p>\n<pre><code>namespace CompanyEmployees.Extensions\n{\n    public static class ServiceExtensions\n    {\n        public static void ConfigureCors(this IServiceCollection services) =&gt;\n            services.AddCors(options =&gt;\n            {\n                options.AddPolicy(&quot;CorsPolicy&quot;, builder =&gt;\n                builder.AllowAnyOrigin()\n                       .AllowAnyMethod()\n                       .AllowAnyHeader());\n            });\n\n        public static void ConfigureIISIntegration(this IServiceCollection services) =&gt;\n            services.Configure&lt;IISOptions&gt;(options =&gt;\n            {\n\n            });\n    }\n}<\/code><\/pre>\n<p>We do not initialize any of the properties inside the options because we are fine with the default values for now. But if you need to fine-tune the configuration right away, you might want to take a look at the possible options:<br \/>\n\u6211\u4eec\u6ca1\u6709\u521d\u59cb\u5316\u9009\u9879\u4e2d\u7684\u4efb\u4f55\u5c5e\u6027\uff0c\u56e0\u4e3a\u6211\u4eec\u73b0\u5728\u5bf9\u9ed8\u8ba4\u503c\u6ca1\u6709\u95ee\u9898\u3002\u4f46\u662f\uff0c\u5982\u679c\u60a8\u9700\u8981\u7acb\u5373\u5fae\u8c03\u914d\u7f6e\uff0c\u5219\u53ef\u80fd\u9700\u8981\u67e5\u770b\u53ef\u80fd\u7684\u9009\u9879\uff1a<\/p>\n<table>\n<thead>\n<tr>\n<th>Option<\/th>\n<th>Default<\/th>\n<th>Setting<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>AutomaticAuthentication<\/td>\n<td>true<\/td>\n<td>if true,the authentication middleware sets the HttpContext.User and responds to generic challenges,if false,the authentication middleware only provides an identity(HttpContext.User ) and responds to challenges when explicitly requested by the AuthenticationScheme . Windows Authentication must be enabled in IIS for AutomaticAuthentication to function. <\/br> \u5982\u679c\u4e3a true\uff0c\u5219\u8eab\u4efd\u9a8c\u8bc1\u4e2d\u95f4\u4ef6\u8bbe\u7f6e HttpContext.User \u5e76\u54cd\u5e94\u4e00\u822c\u8d28\u8be2\uff0c\u5982\u679c\u4e3a false\uff0c\u5219\u8eab\u4efd\u9a8c\u8bc1\u4e2d\u95f4\u4ef6\u4ec5\u63d0\u4f9b identity\uff08HttpContext.User \uff09\uff0c\u5e76\u5728 AuthenticationScheme \u663e\u5f0f\u8bf7\u6c42\u65f6\u54cd\u5e94\u8d28\u8be2\u3002\u5fc5\u987b\u5728 IIS \u4e2d\u542f\u7528 Windows \u8eab\u4efd\u9a8c\u8bc1\uff0cAutomaticAuthentication \u624d\u80fd\u6b63\u5e38\u5de5\u4f5c\u3002<\/td>\n<\/tr>\n<tr>\n<td>AuthenticationDisplayName<\/td>\n<td>null<\/td>\n<td>Sets the display name shown to users on login pages  <\/br> \u8bbe\u7f6e\u5728\u767b\u5f55\u9875\u9762\u4e0a\u5411\u7528\u6237\u663e\u793a\u7684\u663e\u793a\u540d\u79f0<\/td>\n<\/tr>\n<tr>\n<td>ForwardClientCertificate<\/td>\n<td>true<\/td>\n<td>if true and the MS-ASPNETCORE-CLIENTCERT request header is present,the HttpContext.Connection.ClientCertificate is populated.  <\/br> \u5982\u679c true \u4e14\u5b58\u5728 MS-ASPNETCORE-CLIENTCERT \u8bf7\u6c42\u6807\u5934\uff0c\u5219\u586b\u5145 HttpContext.Connection.ClientCertificate\u3002<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Now, we mentioned extension methods are great for organizing your code and extending functionalities. Let\u2019s go back to our Program class and modify it to support CORS and IIS integration now that we\u2019ve written extension methods for those functionalities. We are going to remove the first comment and write our code over it:<br \/>\n\u73b0\u5728\uff0c\u6211\u4eec\u63d0\u5230\u4e86\u6269\u5c55\u65b9\u6cd5\u975e\u5e38\u9002\u5408\u7ec4\u7ec7\u4ee3\u7801\u548c\u6269\u5c55\u529f\u80fd\u3002\u8ba9\u6211\u4eec\u56de\u5230\u6211\u4eec\u7684 Program \u7c7b\u5e76\u5bf9\u5176\u8fdb\u884c\u4fee\u6539\u4ee5\u652f\u6301 CORS \u548c IIS \u96c6\u6210\uff0c\u56e0\u4e3a\u6211\u4eec\u5df2\u7ecf\u4e3a\u8fd9\u4e9b\u529f\u80fd\u7f16\u5199\u4e86\u6269\u5c55\u65b9\u6cd5\u3002\u6211\u4eec\u5c06\u5220\u9664\u7b2c\u4e00\u4e2a\u6ce8\u91ca\u5e76\u5728\u5176\u4e0a\u7f16\u5199\u6211\u4eec\u7684\u4ee3\u7801\uff1a<\/p>\n<pre><code>using CompanyEmployees.Extensions;\n\nvar builder = WebApplication.CreateBuilder(args);\n\n\/\/ Add services to the container.\n\nbuilder.Services.ConfigureCors();\nbuilder.Services.ConfigureIISIntegration();\n\nbuilder.Services.AddControllers();\n\nvar app = builder.Build();\n\n\/\/ Configure the HTTP request pipeline.\n\napp.UseHttpsRedirection();\n\napp.UseAuthorization();\n\napp.MapControllers();\n\napp.Run();<\/code><\/pre>\n<p>And let's add a few mandatory methods to the second part of the Program class (the one for the request pipeline configuration):<br \/>\n\u8ba9\u6211\u4eec\u5411 Program \u7c7b\u7684\u7b2c\u4e8c\u90e8\u5206\uff08\u7528\u4e8e\u8bf7\u6c42\u7ba1\u9053\u914d\u7f6e\u7684\u90a3\u4e2a\uff09\u6dfb\u52a0\u4e00\u4e9b\u5f3a\u5236\u6027\u65b9\u6cd5\uff1a<\/p>\n<pre><code>using CompanyEmployees.Extensions;\nusing Microsoft.AspNetCore.HttpOverrides;\n\nvar builder = WebApplication.CreateBuilder(args);\n\n\/\/ Add services to the container.\n\nbuilder.Services.ConfigureCors();\nbuilder.Services.ConfigureIISIntegration();\n\nbuilder.Services.AddControllers();\n\nvar app = builder.Build();\n\n\/\/ Configure the HTTP request pipeline.\n\nif (app.Environment.IsDevelopment())\n{\n    app.UseDeveloperExceptionPage();\n}\nelse\n{\n    app.UseHsts();\n}\n\napp.UseHttpsRedirection();\n\napp.UseStaticFiles();\n\napp.UseForwardedHeaders(new ForwardedHeadersOptions\n{\n    ForwardedHeaders = ForwardedHeaders.All\n});\n\napp.UseCors(&quot;CorsPolicy&quot;);\n\napp.UseAuthorization();\n\napp.MapControllers();\n\napp.Run();\n<\/code><\/pre>\n<p>We\u2019ve added CORS and IIS configuration to the section where we need to configure our services. Furthermore, CORS configuration has been added to the application\u2019s pipeline inside the second part of the Program class.But as you can see, there are some additional methods unrelated to IIS configuration. Let\u2019s go through those and learn what they do.<br \/>\n\u6211\u4eec\u5df2\u5c06 CORS \u548c IIS \u914d\u7f6e\u6dfb\u52a0\u5230\u9700\u8981\u914d\u7f6e\u670d\u52a1\u7684\u90e8\u5206\u3002\u6b64\u5916\uff0cCORS \u914d\u7f6e\u5df2\u6dfb\u52a0\u5230 Program \u7c7b\u7684\u7b2c\u4e8c\u90e8\u5206\u5185\u7684\u5e94\u7528\u7a0b\u5e8f\u7ba1\u9053\u4e2d\u3002\u4f46\u6b63\u5982\u4f60\u6240\u770b\u5230\u7684\uff0c\u8fd8\u6709\u4e00\u4e9b\u4e0e IIS \u914d\u7f6e\u65e0\u5173\u7684\u5176\u4ed6\u65b9\u6cd5\u3002\u8ba9\u6211\u4eec\u6765\u4e86\u89e3\u4e00\u4e0b\u8fd9\u4e9b\u5e76\u4e86\u89e3\u5b83\u4eec\u7684\u4f5c\u7528\u3002<\/p>\n<p>\u2022 app.UseForwardedHeaders() will forward proxy headers to the current request. This will help us during application deployment. Pay attention that we require Microsoft.AspNetCore.HttpOverrides using directive to introduce the ForwardedHeaders enumeration<br \/>\n\u2022app.UseForwardedHeaders()\u4f1a\u5c06\u4ee3\u7406\u6807\u5934\u8f6c\u53d1\u5230\u5f53\u524d\u8bf7\u6c42\u3002\u8fd9\u5c06\u5728\u5e94\u7528\u7a0b\u5e8f\u90e8\u7f72\u671f\u95f4\u5e2e\u52a9\u6211\u4eec\u3002\u8bf7\u6ce8\u610f\uff0c\u6211\u4eec\u9700\u8981 Microsoft.AspNetCore.HttpOverrides using \u6307\u4ee4\u6765\u5f15\u5165 ForwardedHeaders \u679a\u4e3e<\/p>\n<p>\u2022 app.UseStaticFiles() enables using static files for the request. If we don\u2019t set a path to the static files directory, it will use a wwwroot folder in our project by default.<br \/>\n\u2022app.UseStaticFiles() \u5141\u8bb8\u5bf9\u8bf7\u6c42\u4f7f\u7528\u9759\u6001\u6587\u4ef6\u3002\u5982\u679c\u6211\u4eec\u6ca1\u6709\u8bbe\u7f6e\u9759\u6001\u6587\u4ef6\u76ee\u5f55\u7684\u8def\u5f84\uff0c\u5b83\u5c06\u9ed8\u8ba4\u4f7f\u7528\u6211\u4eec\u9879\u76ee\u4e2d\u7684 wwwroot \u6587\u4ef6\u5939\u3002<\/p>\n<p>\u2022 app.UseHsts() will add middleware for using HSTS, which adds the Strict-Transport-Security header.<br \/>\n\u2022 app.UseHsts() \u5c06\u6dfb\u52a0\u7528\u4e8e\u4f7f\u7528 HSTS \u7684\u4e2d\u95f4\u4ef6\uff0c\u4ece\u800c\u6dfb\u52a0 Strict-Transport-Security \u6807\u5934\u3002<\/p>\n<h2>1.6 Additional Code in the Program Class<\/h2>\n<p>1.6 Program \u7c7b\u4e2d\u7684\u5176\u4ed6\u4ee3\u7801<\/p>\n<p>We have to pay attention to the AddControllers() method. This method registers only the controllers in IServiceCollection and not Views or Pages because they are not required in the Web API project which we are building.\u200c<br \/>\n\u6211\u4eec\u5fc5\u987b\u6ce8\u610f AddControllers() \u65b9\u6cd5\u3002\u6b64\u65b9\u6cd5\u4ec5\u5728 IServiceCollection \u4e2d\u6ce8\u518c\u63a7\u5236\u5668\uff0c\u800c\u4e0d\u5728 Views \u6216 Pages \u4e2d\u6ce8\u518c\u63a7\u5236\u5668\uff0c\u56e0\u4e3a\u6211\u4eec\u6b63\u5728\u6784\u5efa\u7684 Web API \u9879\u76ee\u4e2d\u4e0d\u9700\u8981\u5b83\u4eec\u3002<\/p>\n<p>Right below the controller registration, we have this line of code:<br \/>\n\u5728\u63a7\u5236\u5668\u6ce8\u518c\u7684\u6b63\u4e0b\u65b9\uff0c\u6211\u4eec\u6709\u8fd9\u884c\u4ee3\u7801\uff1a<\/p>\n<pre><code>var app = builder.Build();<\/code><\/pre>\n<p>With the Build method, we are creating the app variable of the type WebApplication. This class (WebApplication) is very important since it implements multiple interfaces like IHost that we can use to start and stop the host, IApplicationBuilder that we use to build the middleware pipeline (as you could\u2019ve seen from our previous custom code), and IEndpointRouteBuilder used to add endpoints in our app.<br \/>\n\u4f7f\u7528 Build \u65b9\u6cd5\uff0c\u6211\u4eec\u5c06\u521b\u5efa WebApplication \u7c7b\u578b\u7684 app \u53d8\u91cf\u3002\u8fd9\u4e2a\u7c7b \uff08WebApplication\uff09 \u975e\u5e38\u91cd\u8981\uff0c\u56e0\u4e3a\u5b83\u5b9e\u73b0\u4e86\u591a\u4e2a\u63a5\u53e3\uff0c\u4f8b\u5982\u6211\u4eec\u53ef\u7528\u4e8e\u542f\u52a8\u548c\u505c\u6b62\u4e3b\u673a\u7684 IHost\u3001\u7528\u4e8e\u6784\u5efa\u4e2d\u95f4\u4ef6\u7ba1\u9053\u7684 IApplicationBuilder\uff08\u6b63\u5982\u60a8\u4ece\u4e4b\u524d\u7684\u81ea\u5b9a\u4e49\u4ee3\u7801\u4e2d\u6240\u770b\u5230\u7684\u90a3\u6837\uff09\uff0c\u4ee5\u53ca\u7528\u4e8e\u5728\u5e94\u7528\u7a0b\u5e8f\u4e2d\u6dfb\u52a0\u7aef\u70b9\u7684 IEndpointRouteBuilder\u3002<\/p>\n<p>The UseHttpRedirection method is used to add the middleware for the redirection from HTTP to HTTPS. Also, we can see the UseAuthorization method that adds the authorization middleware to the specified IApplicationBuilder to enable authorization capabilities.<br \/>\nUseHttpRedirection \u65b9\u6cd5\u7528\u4e8e\u6dfb\u52a0\u4e2d\u95f4\u4ef6\uff0c\u4ee5\u4fbf\u4ece HTTP \u91cd\u5b9a\u5411\u5230 HTTPS\u3002\u6b64\u5916\uff0c\u6211\u4eec\u8fd8\u53ef\u4ee5\u770b\u5230 UseAuthorization \u65b9\u6cd5\uff0c\u8be5\u65b9\u6cd5\u5c06\u6388\u6743\u4e2d\u95f4\u4ef6\u6dfb\u52a0\u5230\u6307\u5b9a\u7684 IApplicationBuilder \u4ee5\u542f\u7528\u6388\u6743\u529f\u80fd\u3002<\/p>\n<p>Finally, we can see the MapControllers method that adds the endpoints from controller actions to the IEndpointRouteBuilder and the Run method that runs the application and block the calling thread until the host shutdown.<br \/>\n\u6700\u540e\uff0c\u6211\u4eec\u53ef\u4ee5\u770b\u5230 MapControllers \u65b9\u6cd5\uff0c\u8be5\u65b9\u6cd5\u5c06\u63a7\u5236\u5668\u4e2d\u7684\u7ec8\u7ed3\u70b9\u6dfb\u52a0\u5230 IEndpointRouteBuilder\uff0c\u4ee5\u53ca Run \u65b9\u6cd5\uff0c\u8be5\u65b9\u6cd5\u8fd0\u884c\u5e94\u7528\u7a0b\u5e8f\u5e76\u963b\u6b62\u8c03\u7528\u7ebf\u7a0b\uff0c\u76f4\u5230\u4e3b\u673a\u5173\u95ed\u3002<\/p>\n<p>Microsoft advises that the order of adding different middlewares to the application builder is very important, and we are going to talk about that in the middleware section of this book.<br \/>\nMicrosoft \u5efa\u8bae\uff0c\u5411\u5e94\u7528\u7a0b\u5e8f\u6784\u5efa\u5668\u6dfb\u52a0\u4e0d\u540c\u4e2d\u95f4\u4ef6\u7684\u987a\u5e8f\u975e\u5e38\u91cd\u8981\uff0c\u6211\u4eec\u5c06\u5728\u672c\u4e66\u7684\u4e2d\u95f4\u4ef6\u90e8\u5206\u8ba8\u8bba\u8fd9\u4e00\u70b9\u3002<\/p>\n<h2>1.7 Environment-Based Settings<\/h2>\n<p>1.7 \u57fa\u4e8e\u73af\u5883\u7684\u8bbe\u7f6e<\/p>\n<p>While we develop our application, we use the \u201cdevelopment\u201d environment. But as soon as we publish our application, it goes to the \u201cproduction\u201d environment. Development and production environments should have different URLs, ports, connection strings, passwords, and other sensitive information.\u200c<br \/>\n\u5f53\u6211\u4eec\u5f00\u53d1\u5e94\u7528\u7a0b\u5e8f\u65f6\uff0c\u6211\u4eec\u4f7f\u7528 \u201cdevelopment\u201d \u73af\u5883\u3002\u4f46\u662f\uff0c\u4e00\u65e6\u6211\u4eec\u53d1\u5e03\u5e94\u7528\u7a0b\u5e8f\uff0c\u5b83\u5c31\u4f1a\u8fdb\u5165 \u201cproduction\u201d \u73af\u5883\uff08\u751f\u4ea7\u73af\u5883\uff09\u3002\u5f00\u53d1\u548c\u751f\u4ea7\u73af\u5883\u5e94\u5177\u6709\u4e0d\u540c\u7684 URL\u3001\u7aef\u53e3\u3001\u8fde\u63a5\u5b57\u7b26\u4e32\u3001\u5bc6\u7801\u548c\u5176\u4ed6\u654f\u611f\u4fe1\u606f\u3002<\/p>\n<p>Therefore, we need to have a separate configuration for each environment and that\u2019s easy to accomplish by using .NET Core-provided mechanisms.<br \/>\n\u56e0\u6b64\uff0c\u6211\u4eec\u9700\u8981\u4e3a\u6bcf\u4e2a\u73af\u5883\u63d0\u4f9b\u5355\u72ec\u7684\u914d\u7f6e\uff0c\u8fd9\u53ef\u4ee5\u901a\u8fc7\u4f7f\u7528 .NET Core \u63d0\u4f9b\u7684\u673a\u5236\u8f7b\u677e\u5b9e\u73b0\u3002<\/p>\n<p>As soon as we create a project, we are going to see the appsettings.json file in the root, which is our main settings file, and when we expand it we are going to see the appsetings.Development.json file by default. These files are separate on the file system, but Visual Studio makes it obvious that they are connected somehow:<br \/>\n\u4e00\u65e6\u6211\u4eec\u521b\u5efa\u4e86\u4e00\u4e2a\u9879\u76ee\uff0c\u6211\u4eec\u5c06\u5728\u6839\u76ee\u5f55\u4e2d\u770b\u5230 appsettings.json \u6587\u4ef6\uff0c\u8fd9\u662f\u6211\u4eec\u7684\u4e3b\u8981\u8bbe\u7f6e\u6587\u4ef6\uff0c\u5f53\u6211\u4eec\u5c55\u5f00\u5b83\u65f6\uff0c\u6211\u4eec\u5c06\u770b\u5230 appsetings\u3002Development.json \u6587\u4ef6\u3002\u8fd9\u4e9b\u6587\u4ef6\u5728\u6587\u4ef6\u7cfb\u7edf\u4e0a\u662f\u72ec\u7acb\u7684\uff0c\u4f46 Visual Studio \u6e05\u695a\u5730\u8868\u660e\u5b83\u4eec\u4ee5\u67d0\u79cd\u65b9\u5f0f\u8fde\u63a5\u5728\u4e00\u8d77\uff1a<\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/0105.gif\" alt=\"alt text\" \/><\/p>\n<p>The apsettings.{EnvironmentSuffix}.json files are used to override the main appsettings.json file. When we use a key-value pair from the original file, we override it. We can also define environment-specific values too.<br \/>\napsettings.{EnvironmentSuffix}.json \u6587\u4ef6\u7528\u4e8e\u8986\u76d6\u4e3b appsettings.json \u6587\u4ef6\u3002\u5f53\u6211\u4eec\u4f7f\u7528\u539f\u59cb\u6587\u4ef6\u4e2d\u7684\u952e\u503c\u5bf9\u65f6\uff0c\u6211\u4eec\u4f1a\u8986\u76d6\u5b83\u3002\u6211\u4eec\u4e5f\u53ef\u4ee5\u5b9a\u4e49\u7279\u5b9a\u4e8e\u73af\u5883\u7684\u503c\u3002<\/p>\n<p>For the production environment, we should add another file: appsettings.Production.json:<br \/>\n\u5bf9\u4e8e\u751f\u4ea7\u73af\u5883\uff0c\u6211\u4eec\u5e94\u8be5\u6dfb\u52a0\u53e6\u4e00\u4e2a\u6587\u4ef6\uff1aappsettings.Production.json\uff1a<\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/0106.gif\" alt=\"alt text\" \/><\/p>\n<p>The appsettings.Production.json file should contain the configuration for the production environment.<br \/>\nappsettings.Production.json\u6587\u4ef6\u5e94\u5305\u542b\u751f\u4ea7\u73af\u5883\u7684\u914d\u7f6e\u3002<\/p>\n<p>To set which environment our application runs on, we need to set up the ASPNETCORE_ENVIRONMENT environment variable. For example, to run the application in production, we need to set it to the Production value on the machine we do the deployment to.<br \/>\n\u8981\u8bbe\u7f6e\u5e94\u7528\u7a0b\u5e8f\u5728\u54ea\u4e2a\u73af\u5883\u4e0a\u8fd0\u884c\uff0c\u6211\u4eec\u9700\u8981\u8bbe\u7f6e ASPNETCORE_ENVIRONMENT \u73af\u5883\u53d8\u91cf\u3002\u4f8b\u5982\uff0c\u8981\u5728\u751f\u4ea7\u73af\u5883\u4e2d\u8fd0\u884c\u5e94\u7528\u7a0b\u5e8f\uff0c\u6211\u4eec\u9700\u8981\u5728\u6267\u884c\u90e8\u7f72\u7684\u673a\u5668\u4e0a\u5c06\u5176\u8bbe\u7f6e\u4e3a Production \u503c\u3002<\/p>\n<p>We can set the variable through the command prompt by typing set ASPNETCORE_ENVIRONMENT=Production in Windows or export ASPNET_CORE_ENVIRONMENT=Production in Linux.<br \/>\n\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u547d\u4ee4\u63d0\u793a\u7b26\u8bbe\u7f6e\u53d8\u91cf\uff0c\u65b9\u6cd5\u662f\u5728 Windows \u4e2d\u952e\u5165 set ASPNETCORE_ENVIRONMENT=Production \u6216\u5728 Linux \u4e2d\u952e\u5165 export ASPNET_CORE_ENVIRONMENT=Production\u3002<\/p>\n<p>ASP.NET Core applications use the value of that environment variable to decide which appsettings file to use accordingly. In this case, that will be appsettings.Production.json.<br \/>\nASP.NET Core \u5e94\u7528\u7a0b\u5e8f\u4f7f\u7528\u8be5\u73af\u5883\u53d8\u91cf\u7684\u503c\u6765\u51b3\u5b9a\u76f8\u5e94\u5730\u4f7f\u7528\u54ea\u4e2a appsettings \u6587\u4ef6\u3002\u5728\u672c\u4f8b\u4e2d\uff0c\u8fd9\u5c06\u662f appsettings.Production.json\u3002<\/p>\n<p>If we take a look at our launchSettings.json file, we are going to see that this variable is currently set to Development.<br \/>\n\u5982\u679c\u6211\u4eec\u67e5\u770b launchSettings.json \u6587\u4ef6\uff0c\u6211\u4eec\u5c06\u770b\u5230\u6b64\u53d8\u91cf\u5f53\u524d\u8bbe\u7f6e\u4e3a Development\u3002<\/p>\n<p>Now, let\u2019s talk a bit more about the middleware in ASP.NET Core applications.<br \/>\n\u73b0\u5728\uff0c\u8ba9\u6211\u4eec\u66f4\u591a\u5730\u8ba8\u8bba\u4e00\u4e0b ASP.NET Core \u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u4e2d\u95f4\u4ef6\u3002<\/p>\n<h2>1.8 ASP.NET Core Middleware<\/h2>\n<p>1.8 ASP.NET Core \u4e2d\u95f4\u4ef6<\/p>\n<p>As we already used some middleware code to modify the application\u2019s pipeline (CORS, Authorization...), and we are going to use the middleware throughout the rest of the book, we should be more familiar with the ASP.NET Core middleware.\u200c<br \/>\n\u7531\u4e8e\u6211\u4eec\u5df2\u7ecf\u4f7f\u7528\u4e86\u4e00\u4e9b\u4e2d\u95f4\u4ef6\u4ee3\u7801\u6765\u4fee\u6539\u5e94\u7528\u7a0b\u5e8f\u7684\u7ba1\u9053\uff08CORS\u3001Authorization...\uff09\uff0c\u5e76\u4e14\u6211\u4eec\u5c06\u5728\u672c\u4e66\u7684\u5176\u4f59\u90e8\u5206\u4f7f\u7528\u4e2d\u95f4\u4ef6\uff0c\u56e0\u6b64\u6211\u4eec\u5e94\u8be5\u66f4\u719f\u6089 ASP.NET Core \u4e2d\u95f4\u4ef6\u3002<\/p>\n<p>ASP.NET Core middleware is a piece of code integrated inside the application\u2019s pipeline that we can use to handle requests and responses. When we talk about the ASP.NET Core middleware, we can think of it as a code section that executes with every request.<br \/>\nASP.NET Core \u4e2d\u95f4\u4ef6\u662f\u4e00\u6bb5\u96c6\u6210\u5728\u5e94\u7528\u7a0b\u5e8f\u7ba1\u9053\u4e2d\u7684\u4ee3\u7801\uff0c\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528\u5b83\u6765\u5904\u7406\u8bf7\u6c42\u548c\u54cd\u5e94\u3002\u5f53\u6211\u4eec\u8c08\u8bba ASP.NET Core \u4e2d\u95f4\u4ef6\u65f6\uff0c\u6211\u4eec\u53ef\u4ee5\u5c06\u5176\u89c6\u4e3a\u968f\u6bcf\u4e2a\u8bf7\u6c42\u4e00\u8d77\u6267\u884c\u7684\u4ee3\u7801\u90e8\u5206\u3002<\/p>\n<p>Usually, we have more than a single middleware component in our application. Each component can:<br \/>\n\u901a\u5e38\uff0c\u6211\u4eec\u7684\u5e94\u7528\u7a0b\u5e8f\u4e2d\u6709\u591a\u4e2a\u4e2d\u95f4\u4ef6\u7ec4\u4ef6\u3002\u6bcf\u4e2a\u7ec4\u4ef6\u90fd\u53ef\u4ee5\uff1a<\/p>\n<p>\u2022  Pass the request to the next middleware component in the pipeline and also<br \/>\n\u2022 \u5c06\u8bf7\u6c42\u4f20\u9012\u7ed9\u7ba1\u9053\u4e2d\u7684\u4e0b\u4e00\u4e2a\u4e2d\u95f4\u4ef6\u7ec4\u4ef6\uff0c\u4ee5\u53ca<\/p>\n<p>\u2022 It can execute some work before and after the next component in the pipeline<br \/>\n\u2022 \u5b83\u53ef\u4ee5\u5728\u7ba1\u9053\u4e2d\u7684\u4e0b\u4e00\u4e2a\u5143\u4ef6\u4e4b\u524d\u548c\u4e4b\u540e\u6267\u884c\u4e00\u4e9b\u5de5\u4f5c<\/p>\n<p>To build a pipeline, we are using request delegates, which handle each HTTP request. To configure request delegates, we use the Run, Map, and Use extension methods. Inside the request pipeline, an application executes each component in the same order they are placed in the code- top to bottom:<br \/>\n\u4e3a\u4e86\u6784\u5efa\u7ba1\u9053\uff0c\u6211\u4eec\u4f7f\u7528\u8bf7\u6c42\u59d4\u6258\u6765\u5904\u7406\u6bcf\u4e2a HTTP \u8bf7\u6c42\u3002\u8981\u914d\u7f6e\u8bf7\u6c42\u59d4\u6258\uff0c\u6211\u4eec\u4f7f\u7528 Run\u3001Map \u548c Use \u6269\u5c55\u65b9\u6cd5\u3002\u5728\u8bf7\u6c42\u7ba1\u9053\u4e2d\uff0c\u5e94\u7528\u7a0b\u5e8f\u6309\u7167\u5b83\u4eec\u5728\u4ee3\u7801\u4e2d\u7684\u653e\u7f6e\u987a\u5e8f\uff08\u4ece\u4e0a\u5230\u4e0b\uff09\u6267\u884c\u6bcf\u4e2a\u7ec4\u4ef6\uff1a<\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/0107.jpg\" alt=\"alt text\" \/><\/p>\n<p>Additionally, we can see that each component can execute custom logic before using the next delegate to pass the execution to another component. The last middleware component doesn\u2019t call the next delegate, which means that this component is short-circuiting the pipeline. This is a terminal middleware because it stops further middleware from processing the request. It executes the additional logic and then returns the execution to the previous middleware components.<br \/>\n\u6b64\u5916\uff0c\u6211\u4eec\u53ef\u4ee5\u770b\u5230\uff0c\u5728\u4f7f\u7528 next()\u5c06\u6267\u884c\u4f20\u9012\u7ed9\u53e6\u4e00\u4e2a\u7ec4\u4ef6\u4e4b\u524d\uff0c\u6bcf\u4e2a\u7ec4\u4ef6\u90fd\u53ef\u4ee5\u6267\u884c\u81ea\u5b9a\u4e49 logic\u3002\u6700\u540e\u4e00\u4e2a\u4e2d\u95f4\u4ef6\u7ec4\u4ef6\u4e0d\u8c03\u7528\u4e0b\u4e00\u4e2a\u59d4\u6258\uff0c\u8fd9\u610f\u5473\u7740\u8be5\u7ec4\u4ef6\u6b63\u5728\u4f7f\u7ba1\u9053\u77ed\u8def\u3002\u8fd9\u662f\u4e00\u4e2a\u7ec8\u7aef\u4e2d\u95f4\u4ef6\uff0c\u56e0\u4e3a\u5b83\u4f1a\u963b\u6b62\u8fdb\u4e00\u6b65\u7684\u4e2d\u95f4\u4ef6\u5904\u7406\u8bf7\u6c42\u3002\u5b83\u6267\u884c\u989d\u5916\u7684 logic\uff0c\u7136\u540e\u5c06\u6267\u884c\u8fd4\u56de\u7ed9\u524d\u9762\u7684\u4e2d\u95f4\u4ef6\u7ec4\u4ef6\u3002<\/p>\n<p>Before we start with examples, it is quite important to know about the order in which we should register our middleware components. The order is important for the security, performance, and functionality of our applications:<br \/>\n\u5728\u6211\u4eec\u5f00\u59cb\u793a\u4f8b\u4e4b\u524d\uff0c\u4e86\u89e3\u6211\u4eec\u5e94\u8be5\u6ce8\u518c\u4e2d\u95f4\u4ef6\u7ec4\u4ef6\u7684\u987a\u5e8f\u975e\u5e38\u91cd\u8981\u3002\u8be5\u987a\u5e8f\u5bf9\u4e8e\u6211\u4eec\u5e94\u7528\u7a0b\u5e8f\u7684\u5b89\u5168\u6027\u3001\u6027\u80fd\u548c\u529f\u80fd\u975e\u5e38\u91cd\u8981\uff1a<\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/0108.jpg\" alt=\"alt text\" \/><\/p>\n<p>As we can see, we should register the exception handler in the early stage of the pipeline flow so it could catch all the exceptions that can happen in the later stages of the pipeline. When we create a new ASP.NET Core app, many of the middleware components are already registered in the order from the diagram. We have to pay attention when registering additional existing components or the custom ones to fit this recommendation.<br \/>\n\u6b63\u5982\u6211\u4eec\u6240\u770b\u5230\u7684\uff0c\u6211\u4eec\u5e94\u8be5\u5728\u7ba1\u9053\u6d41\u7684\u65e9\u671f\u9636\u6bb5\u6ce8\u518c\u5f02\u5e38\u5904\u7406\u7a0b\u5e8f\uff0c\u4ee5\u4fbf\u5b83\u53ef\u4ee5\u6355\u83b7\u7ba1\u9053\u540e\u671f\u53ef\u80fd\u53d1\u751f\u7684\u6240\u6709\u5f02\u5e38\u3002\u5f53\u6211\u4eec\u521b\u5efa\u65b0\u7684 ASP.NET Core \u5e94\u7528\u7a0b\u5e8f\u65f6\uff0c\u8bb8\u591a\u4e2d\u95f4\u4ef6\u7ec4\u4ef6\u5df2\u7ecf\u6309\u7167\u56fe\u4e2d\u7684\u987a\u5e8f\u6ce8\u518c\u4e86\u3002\u5728\u6ce8\u518c\u5176\u4ed6\u73b0\u6709\u7ec4\u4ef6\u6216\u81ea\u5b9a\u4e49\u7ec4\u4ef6\u4ee5\u9002\u5e94\u6b64\u5efa\u8bae\u65f6\uff0c\u6211\u4eec\u5fc5\u987b\u6ce8\u610f\u3002<\/p>\n<p>For example, when adding CORS to the pipeline, the app in the development environment will work just fine if you don\u2019t add it in this order. But we\u2019ve received several questions from our readers stating that they face the CORS problem once they deploy the app. But once we suggested moving the CORS registration to the required place, the problem disappeared.<br \/>\n\u4f8b\u5982\uff0c\u5728\u5c06 CORS \u6dfb\u52a0\u5230\u7ba1\u9053\u65f6\uff0c\u5982\u679c\u4e0d\u6309\u6b64\u987a\u5e8f\u6dfb\u52a0\uff0c\u5f00\u53d1\u73af\u5883\u4e2d\u7684\u5e94\u7528\u7a0b\u5e8f\u5c06\u6b63\u5e38\u5de5\u4f5c\u3002\u4f46\u662f\u6211\u4eec\u6536\u5230\u4e86\u8bfb\u8005\u7684\u51e0\u4e2a\u95ee\u9898\uff0c\u4ed6\u4eec\u6307\u51fa\uff0c\u4e00\u65e6\u90e8\u7f72\u4e86\u5e94\u7528\u7a0b\u5e8f\uff0c\u4ed6\u4eec\u5c31\u4f1a\u9762\u4e34 CORS \u95ee\u9898\u3002\u4f46\u662f\uff0c\u4e00\u65e6\u6211\u4eec\u5efa\u8bae\u5c06 CORS \u6ce8\u518c\u79fb\u52a8\u5230\u6240\u9700\u4f4d\u7f6e\uff0c\u95ee\u9898\u5c31\u6d88\u5931\u4e86\u3002<\/p>\n<p>Now, we can use some examples to see how we can manipulate the application\u2019s pipeline. For this section\u2019s purpose, we are going to create a separate application that will be dedicated only to this section of the book. The later sections will continue from the previous project, that we\u2019ve already created.<br \/>\n\u73b0\u5728\uff0c\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528\u4e00\u4e9b\u793a\u4f8b\u6765\u4e86\u89e3\u5982\u4f55\u4f5c\u5e94\u7528\u7a0b\u5e8f\u7684\u7ba1\u9053\u3002\u51fa\u4e8e\u672c\u8282\u7684\u76ee\u7684\uff0c\u6211\u4eec\u5c06\u521b\u5efa\u4e00\u4e2a\u5355\u72ec\u7684\u5e94\u7528\u7a0b\u5e8f\uff0c\u8be5\u5e94\u7528\u7a0b\u5e8f\u5c06\u4e13\u95e8\u7528\u4e8e\u672c\u4e66\u7684\u8fd9\u4e00\u90e8\u5206\u3002\u540e\u9762\u7684\u90e8\u5206\u5c06\u4ece\u6211\u4eec\u5df2\u7ecf\u521b\u5efa\u7684\u4e0a\u4e00\u4e2a\u9879\u76ee\u7ee7\u7eed\u3002<\/p>\n<h3>1.8.1 Creating a First Middleware Component\u200c<\/h3>\n<p>1.8.1 \u521b\u5efa\u7b2c\u4e00\u4e2a Middleware \u7ec4\u4ef6<\/p>\n<p>Let\u2019s start by creating a new ASP.NET Core Web API project, and name it MiddlewareExample.<br \/>\n\u8ba9\u6211\u4eec\u9996\u5148\u521b\u5efa\u4e00\u4e2a\u65b0\u7684 ASP.NET Core Web API \u9879\u76ee\uff0c\u5e76\u5c06\u5176\u547d\u540d\u4e3a MiddlewareExample\u3002<\/p>\n<p>In the launchSettings.json file, we are going to add some changes regarding the launch profiles:<br \/>\n\u5728 launchSettings.json \u6587\u4ef6\u4e2d\uff0c\u6211\u4eec\u5c06\u6dfb\u52a0\u4e00\u4e9b\u6709\u5173\u542f\u52a8\u914d\u7f6e\u6587\u4ef6\u7684\u66f4\u6539\uff1a<\/p>\n<pre><code>{\n    &quot;profiles&quot;: {\n        &quot;MiddlewareExample&quot;: {\n            &quot;commandName&quot;: &quot;Project&quot;,\n            &quot;dotnetRunMessages&quot;: true,\n            &quot;launchBrowser&quot;: true,\n            &quot;launchUrl&quot;: &quot;weatherforecast&quot;,\n            &quot;applicationUrl&quot;: &quot;https:\/\/localhost:5001;http:\/\/localhost:5000&quot;,\n            &quot;environmentVariables&quot;: { &quot;ASPNETCORE_ENVIRONMENT&quot;: &quot;Development&quot; }\n        }\n    }\n}<\/code><\/pre>\n<p>Now, inside the Program class, right below the UseAuthorization part, we are going to use an anonymous method to create a first middleware component:<br \/>\n\u73b0\u5728\uff0c\u5728 Program \u7c7b\u4e2d\uff0c\u5728 UseAuthorization \u90e8\u5206\u7684\u6b63\u4e0b\u65b9\uff0c\u6211\u4eec\u5c06\u4f7f\u7528\u533f\u540d\u65b9\u6cd5\u521b\u5efa\u7b2c\u4e00\u4e2a\u4e2d\u95f4\u4ef6\u7ec4\u4ef6\uff1a<\/p>\n<pre><code>app.UseAuthorization();\napp.Run(async context =&gt; { await context.Response.WriteAsync(&quot;Hello from the middleware component.&quot;); });\napp.MapControllers();<\/code><\/pre>\n<p>We use the Run method, which adds a terminal component to the app pipeline. We can see we are not using the next delegate because the Run method is always terminal and terminates the pipeline. This method accepts a single parameter of the RequestDelegate type. If we inspect this delegate we are going to see that it accepts a single HttpContext parameter:<br \/>\n\u6211\u4eec\u4f7f\u7528 Run \u65b9\u6cd5\uff0c\u8be5\u65b9\u6cd5\u5c06\u7ec8\u7aef\u7ec4\u4ef6\u6dfb\u52a0\u5230\u5e94\u7528\u7a0b\u5e8f\u7ba1\u9053\u4e2d\u3002\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u6211\u4eec\u6ca1\u6709\u4f7f\u7528 next() \u59d4\u6258\uff0c\u56e0\u4e3a Run \u65b9\u6cd5\u59cb\u7ec8\u662f terminal \u5e76\u7ec8\u6b62\u7ba1\u9053\u3002\u6b64\u65b9\u6cd5\u63a5\u53d7 RequestDelegate \u7c7b\u578b\u7684\u5355\u4e2a\u53c2\u6570\u3002\u5982\u679c\u6211\u4eec\u68c0\u67e5\u8fd9\u4e2a\u59d4\u6258\uff0c\u6211\u4eec\u5c06\u770b\u5230\u5b83\u63a5\u53d7\u4e00\u4e2a HttpContext \u53c2\u6570\uff1a<\/p>\n<pre><code>namespace Microsoft.AspNetCore.Http { \n    public delegate Task RequestDelegate(HttpContext context); \n}<\/code><\/pre>\n<p>So, we are using that context parameter to modify our requests and responses inside the middleware component. In this specific example, we are modifying the response by using the WriteAsync method. For this method, we need Microsoft.AspNetCore.Http namespace.<br \/>\n\u56e0\u6b64\uff0c\u6211\u4eec\u4f7f\u7528\u8be5 context \u53c2\u6570\u6765\u4fee\u6539\u4e2d\u95f4\u4ef6\u7ec4\u4ef6\u5185\u7684\u8bf7\u6c42\u548c\u54cd\u5e94\u3002\u5728\u6b64\u7279\u5b9a\u793a\u4f8b\u4e2d\uff0c\u6211\u4eec\u5c06\u4f7f\u7528 WriteAsync \u65b9\u6cd5\u4fee\u6539\u54cd\u5e94\u3002\u5bf9\u4e8e\u6b64\u65b9\u6cd5\uff0c\u6211\u4eec\u9700\u8981 Microsoft.AspNetCore.Http \u547d\u540d\u7a7a\u95f4\u3002<\/p>\n<p>Let\u2019s start the app, and inspect the result:<br \/>\n\u8ba9\u6211\u4eec\u542f\u52a8\u5e94\u7528\u7a0b\u5e8f\uff0c\u5e76\u68c0\u67e5\u7ed3\u679c\uff1a<\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/0109.jpg\" alt=\"alt text\" \/><\/p>\n<p>There we go. We can see a result from our middleware.<br \/>\n\u597d\u4e86\u3002\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u4e2d\u95f4\u4ef6\u7684\u7ed3\u679c\u3002<\/p>\n<h3>1.8.2 Working with the Use Method\u200c<\/h3>\n<p>1.8.2 \u4f7f\u7528 Use \u65b9\u6cd5<\/p>\n<p>To chain multiple request delegates in our code, we can use the Use method. This method accepts a Func delegate as a parameter and returns a Task as a result:<br \/>\n\u8981\u5728\u4ee3\u7801\u4e2d\u94fe\u63a5\u591a\u4e2a\u8bf7\u6c42\u59d4\u6258\uff0c\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528 Use \u65b9\u6cd5\u3002\u6b64\u65b9\u6cd5\u63a5\u53d7 Func \u59d4\u6258\u4f5c\u4e3a\u53c2\u6570\uff0c\u5e76\u8fd4\u56de Task \u4f5c\u4e3a\u7ed3\u679c\uff1a<\/p>\n<pre><code>public static IApplicationBuilder Use(this IApplicationBuilder app, Func&lt;HttpContext, Func&lt;Task&gt;, Task&gt; middleware);<\/code><\/pre>\n<p>So, this means when we use it, we can make use of two parameters, context and next:<br \/>\n\u6240\u4ee5\uff0c\u8fd9\u610f\u5473\u7740\u5f53\u6211\u4eec\u4f7f\u7528\u5b83\u65f6\uff0c\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528\u4e24\u4e2a\u53c2\u6570\uff0ccontext \u548c next\uff1a<\/p>\n<pre><code>app.UseAuthorization();\napp.Use(async (context, next) =&gt;\n{\n    Console.WriteLine($&quot;Logic before executing the next delegate in the Use method&quot;);\n    await next.Invoke();\n    Console.WriteLine($&quot;Logic after executing the next delegate in the Use method&quot;);\n});\napp.Run(async context =&gt;\n{\n    Console.WriteLine($&quot;Writing the response to the client in the Run method&quot;);\n    await context.Response.WriteAsync(&quot;Hello from the middleware component.&quot;);\n});\napp.MapControllers();<\/code><\/pre>\n<p>As you can see, we add several logging messages to be sure what the order of executions inside middleware components is. First, we write to a console window, then we invoke the next delegate passing the execution to another component in the pipeline. In the Run method, we write a second message to the console window and write a response to the client. After that, the execution is returned to the Use method and we write the third message (the one below the next delegate invocation) to the console window.<br \/>\n\u5982\u4f60\u6240\u89c1\uff0c\u6211\u4eec\u6dfb\u52a0\u4e86\u51e0\u4e2a\u65e5\u5fd7\u8bb0\u5f55\u6d88\u606f\uff0c\u4ee5\u786e\u4fdd\u4e2d\u95f4\u4ef6\u7ec4\u4ef6\u5185\u7684\u6267\u884c\u987a\u5e8f\u662f\u4ec0\u4e48\u3002\u9996\u5148\uff0c\u6211\u4eec\u5199\u5165\u63a7\u5236\u53f0\u7a97\u53e3\uff0c\u7136\u540e\u8c03\u7528\u4e0b\u4e00\u4e2a\u59d4\u6258\uff0c\u5c06\u6267\u884c\u4f20\u9012\u7ed9\u7ba1\u9053\u4e2d\u7684\u53e6\u4e00\u4e2a\u7ec4\u4ef6\u3002\u5728 Run \u65b9\u6cd5\u4e2d\uff0c\u6211\u4eec\u5c06\u7b2c\u4e8c\u6761\u6d88\u606f\u5199\u5165\u63a7\u5236\u53f0\u7a97\u53e3\uff0c\u5e76\u5c06\u54cd\u5e94\u5199\u5165\u5ba2\u6237\u7aef\u3002\u4e4b\u540e\uff0c\u6267\u884c\u5c06\u8fd4\u56de\u5230 Use \u65b9\u6cd5\uff0c\u6211\u4eec\u5c06\u7b2c\u4e09\u6761\u6d88\u606f\uff08\u4e0b\u4e00\u4e2a\u59d4\u6258\u8c03\u7528\u4e0b\u9762\u7684\u6d88\u606f\uff09\u5199\u5165\u63a7\u5236\u53f0\u7a97\u53e3\u3002<\/p>\n<p>The Run method doesn\u2019t accept the next delegate as a parameter, so without it to send the execution to another component, this component short-circuits the request pipeline.<br \/>\nRun \u65b9\u6cd5\u4e0d\u63a5\u53d7\u4e0b\u4e00\u4e2a\u59d4\u6258\u4f5c\u4e3a\u53c2\u6570\uff0c\u56e0\u6b64\u5982\u679c\u6ca1\u6709\u5b83\u5c06\u6267\u884c\u53d1\u9001\u5230\u53e6\u4e00\u4e2a\u7ec4\u4ef6\uff0c\u6b64\u7ec4\u4ef6\u4f1a\u4f7f\u8bf7\u6c42\u7ba1\u9053\u77ed\u8def\u3002<\/p>\n<p>Now, let\u2019s start the app and inspect the result, which proves our execution order:<br \/>\n\u73b0\u5728\uff0c\u8ba9\u6211\u4eec\u542f\u52a8\u5e94\u7528\u7a0b\u5e8f\u5e76\u68c0\u67e5\u7ed3\u679c\uff0c\u5b83\u8bc1\u660e\u4e86\u6211\u4eec\u7684\u6267\u884c\u987a\u5e8f\uff1a<\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/0110.jpg\" alt=\"alt text\" \/><\/p>\n<p>Maybe you will see two sets of messages but don\u2019t worry, that\u2019s because the browser sends two sets of requests, one for the \/weatherforecast and another for the favicon.ico. If you, for example, use Postman to test this, you will see only one set of messages.<br \/>\n\u4e5f\u8bb8\u4f60\u4f1a\u770b\u5230\u4e24\u7ec4\u6d88\u606f\uff0c\u4f46\u4e0d\u8981\u62c5\u5fc3\uff0c\u90a3\u662f\u56e0\u4e3a\u6d4f\u89c8\u5668\u53d1\u9001\u4e86\u4e24\u7ec4\u8bf7\u6c42\uff0c\u4e00\u7ec4\u7528\u4e8e \/weatherforecast\uff0c\u53e6\u4e00\u7ec4\u7528\u4e8e favicon.ico\u3002\u4f8b\u5982\uff0c\u5982\u679c\u60a8\u4f7f\u7528 Postman \u5bf9\u6b64\u8fdb\u884c\u6d4b\u8bd5\uff0c\u60a8\u5c06\u53ea\u770b\u5230\u4e00\u7ec4\u6d88\u606f\u3002<\/p>\n<p>One more thing to mention. We shouldn\u2019t call the next.Invoke after we send the response to the client. This can cause exceptions if we try to set the status code or modify the headers of the response.<br \/>\n\u8fd8\u6709\u4e00\u4ef6\u4e8b\u8981\u63d0\u3002\u6211\u4eec\u4e0d\u5e94\u8be5\u8c03\u7528\u4e0b\u4e00\u4e2a\u3002\u5728\u5c06\u54cd\u5e94\u53d1\u9001\u5230\u5ba2\u6237\u7aef\u540e\u8c03\u7528\u3002\u5982\u679c\u6211\u4eec\u5c1d\u8bd5\u8bbe\u7f6e\u72b6\u6001\u4ee3\u7801\u6216\u4fee\u6539\u54cd\u5e94\u7684\u6807\u5934\uff0c\u8fd9\u53ef\u80fd\u4f1a\u5bfc\u81f4\u5f02\u5e38\u3002<\/p>\n<p>For example:<br \/>\n\u4f8b\u5982\uff1a<\/p>\n<pre><code>app.Use(async (context, next) =&gt;\n{\n    await context.Response.WriteAsync(&quot;Hello from the middleware component.&quot;); \n    await next.Invoke();\n    Console.WriteLine($&quot;Logic after executing the next delegate in the Use method&quot;);\n});\napp.Run(async context =&gt;\n{\n    Console.WriteLine($&quot;Writing the response to the client in the Run method&quot;);\n    context.Response.StatusCode = 200; \n    await context.Response.WriteAsync(&quot;Hello from the middleware component.&quot;);\n});<\/code><\/pre>\n<p>Here we write a response to the client and then call next.Invoke. Of course, this passes the execution to the next component in the pipeline. There, we try to set the status code of the response and write another one. But let\u2019s inspect the result:<br \/>\n\u5728\u8fd9\u91cc\uff0c\u6211\u4eec\u5411\u5ba2\u6237\u7aef\u5199\u5165\u54cd\u5e94\uff0c\u7136\u540e\u8c03\u7528 next\u3002\u8c03\u7528\u3002\u5f53\u7136\uff0c\u8fd9\u4f1a\u5c06\u6267\u884c\u4f20\u9012\u7ed9\u7ba1\u9053\u4e2d\u7684\u4e0b\u4e00\u4e2a\u7ec4\u4ef6\u3002\u5728\u90a3\u91cc\uff0c\u6211\u4eec\u5c1d\u8bd5\u8bbe\u7f6e\u54cd\u5e94\u7684\u72b6\u6001\u4ee3\u7801\u5e76\u7f16\u5199\u53e6\u4e00\u4e2a\u72b6\u6001\u4ee3\u7801\u3002\u4f46\u8ba9\u6211\u4eec\u68c0\u67e5\u4e00\u4e0b\u7ed3\u679c\uff1a<\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/0111.jpg\" alt=\"alt text\" \/><\/p>\n<p>We can see the error message, which is pretty self-explanatory.<br \/>\n\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u9519\u8bef\u6d88\u606f\uff0c\u8fd9\u662f\u4e0d\u8a00\u81ea\u660e\u7684\u3002<\/p>\n<h3>1.8.3 Using the Map and MapWhen Methods\u200c<\/h3>\n<p>1.8.3 \u4f7f\u7528 Map \u548c MapWhen \u65b9\u6cd5<\/p>\n<p>To branch the middleware pipeline, we can use both Map and MapWhen methods. The Map method is an extension method that accepts a path string as one of the parameters:<br \/>\n\u8981\u5bf9\u4e2d\u95f4\u4ef6\u7ba1\u9053\u8fdb\u884c\u5206\u652f\uff0c\u6211\u4eec\u53ef\u4ee5\u540c\u65f6\u4f7f\u7528 Map \u548c MapWhen \u65b9\u6cd5\u3002\u8be5\u65b9\u6cd5 Map \u662f\u4e00\u79cd\u6269\u5c55\u65b9\u6cd5\uff0c\u5b83\u63a5\u53d7\u8def\u5f84\u5b57\u7b26\u4e32\u4f5c\u4e3a\u53c2\u6570\u4e4b\u4e00\uff1a<\/p>\n<pre><code>public static IApplicationBuilder Map(this IApplicationBuilder app, PathString pathMatch, Action&lt;IApplicationBuilder&gt; configuration)<\/code><\/pre>\n<p>When we provide the pathMatch string, the Map method will compare it to the start of the request path. If they match, the app will execute the branch.<br \/>\n\u5f53\u6211\u4eec\u63d0\u4f9b pathMatch \u5b57\u7b26\u4e32\u65f6\uff0cMap \u65b9\u6cd5\u4f1a\u5c06\u5176\u4e0e\u8bf7\u6c42\u8def\u5f84\u7684\u5f00\u5934\u8fdb\u884c\u6bd4\u8f83\u3002\u5982\u679c\u5b83\u4eec\u5339\u914d\uff0c\u5e94\u7528\u7a0b\u5e8f\u5c06\u6267\u884c\u5206\u652f\u3002<\/p>\n<p>So, let\u2019s see how we can use this method by modifying the Program class:<br \/>\n\u90a3\u4e48\uff0c\u8ba9\u6211\u4eec\u770b\u770b\u5982\u4f55\u901a\u8fc7\u4fee\u6539 Program \u7c7b\u6765\u4f7f\u7528\u6b64\u65b9\u6cd5\uff1a<\/p>\n<pre><code>app.Use(async (context, next) =&gt;\n{\n    Console.WriteLine($&quot;Logic before executing the next delegate in the Use method&quot;);\n    await next.Invoke();\n    Console.WriteLine($&quot;Logic after executing the next delegate in the Use method&quot;);\n}); \napp.Map(&quot;\/usingmapbranch&quot;, builder =&gt;\n{\n    builder.Use(async (context, next) =&gt;\n    {\n        Console.WriteLine(&quot;Map branch logic in the Use method before the next delegate&quot;); \n        await next.Invoke();\n        Console.WriteLine(&quot;Map branch logic in the Use method after the next delegate&quot;);\n    });\n    builder.Run(async context =&gt;\n    {\n        Console.WriteLine($&quot;Map branch response to the client in the Run method&quot;);\n        await context.Response.WriteAsync(&quot;Hello from the map branch.&quot;);\n    });\n});\napp.Run(async context =&gt;\n{\n    Console.WriteLine($&quot;Writing the response to the client in the Run method&quot;);\n    await context.Response.WriteAsync(&quot;Hello from the middleware component.&quot;);\n});<\/code><\/pre>\n<p>By using the Map method, we provide the path match, and then in the delegate, we use our well-known Use and Run methods to execute middleware components.<br \/>\n\u901a\u8fc7\u4f7f\u7528 Map \u65b9\u6cd5\uff0c\u6211\u4eec\u63d0\u4f9b\u8def\u5f84\u5339\u914d\uff0c\u7136\u540e\u5728\u59d4\u6258\u4e2d\uff0c\u6211\u4eec\u4f7f\u7528\u6211\u4eec\u8457\u540d\u7684 Use \u548c Run \u65b9\u6cd5\u6765\u6267\u884c\u4e2d\u95f4\u4ef6\u7ec4\u4ef6\u3002<\/p>\n<p>Now, if we start the app and navigate to \/usingmapbranch, we are going to see the response in the browser:<br \/>\n\u73b0\u5728\uff0c\u5982\u679c\u6211\u4eec\u542f\u52a8\u5e94\u7528\u7a0b\u5e8f\u5e76\u5bfc\u822a\u5230 \/usingmapbranch\uff0c\u6211\u4eec\u5c06\u5728\u6d4f\u89c8\u5668\u4e2d\u770b\u5230\u54cd\u5e94\uff1a<\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/0112.jpg\" alt=\"alt text\" \/><\/p>\n<p>But also, if we inspect console logs, we are going to see our new messages:<br \/>\n\u4f46\u662f\uff0c\u5982\u679c\u6211\u4eec\u68c0\u67e5\u63a7\u5236\u53f0\u65e5\u5fd7\uff0c\u6211\u4eec\u5c06\u770b\u5230\u6211\u4eec\u7684\u65b0\u6d88\u606f\uff1a<\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/0113.jpg\" alt=\"alt text\" \/><\/p>\n<p>Here, we can see the messages from the Use method before the branch, and the messages from the Use and Run methods inside the Map branch. We are not seeing any message from the Run method outside the branch. It is important to know that any middleware component that we add after the Map method in the pipeline won\u2019t be executed. This is true even if we don\u2019t use the Run middleware inside the branch.<br \/>\n\u5728\u8fd9\u91cc\uff0c\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u5206\u652f\u4e4b\u524d\u6765\u81ea Use \u65b9\u6cd5\u7684\u6d88\u606f\uff0c\u4ee5\u53ca\u6765\u81ea Map \u5206\u652f\u5185\u7684 Use \u548c Run \u65b9\u6cd5\u7684\u6d88\u606f\u3002\u6211\u4eec\u6ca1\u6709\u770b\u5230\u6765\u81ea\u5206\u652f\u5916\u90e8\u7684 Run \u65b9\u6cd5\u7684\u4efb\u4f55\u6d88\u606f\u3002\u8bf7\u52a1\u5fc5\u77e5\u9053\uff0c\u6211\u4eec\u5728\u7ba1\u9053\u4e2d\u7684 Map \u65b9\u6cd5\u4e4b\u540e\u6dfb\u52a0\u7684\u4efb\u4f55\u4e2d\u95f4\u4ef6\u7ec4\u4ef6\u90fd\u4e0d\u4f1a\u88ab\u6267\u884c\u3002\u5373\u4f7f\u6211\u4eec\u4e0d\u5728\u5206\u652f\u4e2d\u4f7f\u7528 Run \u4e2d\u95f4\u4ef6\uff0c\u4e5f\u662f\u5982\u6b64\u3002<\/p>\n<h3>1.8.4 Using MapWhen Method\u200c<\/h3>\n<p>1.8.4 \u4f7f\u7528 MapWhen \u65b9\u6cd5<\/p>\n<p>If we inspect the MapWhen method, we are going to see that it accepts two parameters:<br \/>\n\u5982\u679c\u6211\u4eec\u68c0\u67e5 MapWhen \u65b9\u6cd5\uff0c\u6211\u4eec\u5c06\u770b\u5230\u5b83\u63a5\u53d7\u4e24\u4e2a\u53c2\u6570\uff1a<\/p>\n<pre><code>public static IApplicationBuilder MapWhen(this IApplicationBuilder app, Func&lt;HttpContext, bool&gt; predicate, Action&lt;IApplicationBuilder&gt; configuration)<\/code><\/pre>\n<p>This method uses the result of the given predicate to branch the request pipeline.<br \/>\n\u6b64\u65b9\u6cd5\u4f7f\u7528\u7ed9\u5b9a\u8c13\u8bcd\u7684\u7ed3\u679c\u5bf9\u8bf7\u6c42\u7ba1\u9053\u8fdb\u884c\u5206\u652f\u3002<\/p>\n<p>So, let\u2019s see it in action:<br \/>\n\u90a3\u4e48\uff0c\u8ba9\u6211\u4eec\u770b\u770b\u5b83\u7684\u5b9e\u9645\u6548\u679c\uff1a<\/p>\n<pre><code>app.Map(&quot;\/usingmapbranch&quot;, builder =&gt;\n{\n    ...\n});\napp.MapWhen(context =&gt; context.Request.Query.ContainsKey(&quot;testquerystring&quot;), builder =&gt;\n{\n    builder.Run(async context =&gt;\n    {\n        await context.Response.WriteAsync(&quot;Hello from the MapWhen branch.&quot;);\n    });\n});\napp.Run(async context =&gt;\n{\n    ...\n});<\/code><\/pre>\n<p>Here, if our request contains the provided query string, we execute the Run method by writing the response to the client. So, as we said, based on the predicate\u2019s result the MapWhen method branch the request pipeline.<br \/>\n\u5728\u8fd9\u91cc\uff0c\u5982\u679c\u6211\u4eec\u7684\u8bf7\u6c42\u5305\u542b\u63d0\u4f9b\u7684\u67e5\u8be2\u5b57\u7b26\u4e32\uff0c\u6211\u4eec\u5c06\u901a\u8fc7\u5c06\u54cd\u5e94\u5199\u5165\u5ba2\u6237\u7aef\u6765\u6267\u884c Run \u65b9\u6cd5\u3002\u56e0\u6b64\uff0c\u6b63\u5982\u6211\u4eec\u6240\u8bf4\uff0c\u6839\u636e\u8c13\u8bcd\u7684\u7ed3\u679c\uff0cMapWhen \u65b9\u6cd5\u5bf9\u8bf7\u6c42\u7ba1\u9053\u8fdb\u884c\u5206\u652f\u3002<\/p>\n<p>Now, we can start the app and navigate to:<br \/>\n\u73b0\u5728\uff0c\u6211\u4eec\u53ef\u4ee5\u542f\u52a8\u5e94\u7528\u7a0b\u5e8f\u5e76\u5bfc\u822a\u5230:<br \/>\n<a href=\"https:\/\/localhost:5001?testquerystring=test\">https:\/\/localhost:5001?testquerystring=test<\/a><\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/0114.jpg\" alt=\"alt text\" \/><\/p>\n<p>And there we go. We can see our expected message. Of course, we can chain multiple middleware components inside this method as well.<br \/>\n\u597d\u4e86\u3002\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u9884\u671f\u7684\u6d88\u606f\u3002\u5f53\u7136\uff0c\u6211\u4eec\u4e5f\u53ef\u4ee5\u5728\u6b64\u65b9\u6cd5\u4e2d\u94fe\u63a5\u591a\u4e2a\u4e2d\u95f4\u4ef6\u7ec4\u4ef6\u3002<\/p>\n<p>So, now we have a good understanding of using middleware and its order of invocation in the ASP.NET Core application. This knowledge is going to be very useful to us once we start working on a custom error handling middleware (a few sections later).<br \/>\n\u56e0\u6b64\uff0c\u73b0\u5728\u6211\u4eec\u5df2\u7ecf\u5f88\u597d\u5730\u4e86\u89e3\u4e86\u4e2d\u95f4\u4ef6\u7684\u4f7f\u7528\u53ca\u5176\u5728 ASP.NET Core \u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u8c03\u7528\u987a\u5e8f\u3002\u4e00\u65e6\u6211\u4eec\u5f00\u59cb\u5f00\u53d1\u81ea\u5b9a\u4e49\u9519\u8bef\u5904\u7406\u4e2d\u95f4\u4ef6\uff0c\u8fd9\u4e9b\u77e5\u8bc6\u5c06\u5bf9\u6211\u4eec\u975e\u5e38\u6709\u7528\uff08\u7a0d\u540e\u5c06\u4ecb\u7ecd\u51e0\u8282\uff09\u3002<\/p>\n<p>In the next chapter, we\u2019ll learn how to configure a Logger service because it\u2019s really important to have it configured as early in the project as possible. We can close this app, and continue with the CompanyEmployees app.<br \/>\n\u5728\u4e0b\u4e00\u7ae0\u4e2d\uff0c\u6211\u4eec\u5c06\u5b66\u4e60\u5982\u4f55\u914d\u7f6e Logger \u670d\u52a1\uff0c\u56e0\u4e3a\u5728\u9879\u76ee\u7684\u65e9\u671f\u914d\u7f6e\u5b83\u975e\u5e38\u91cd\u8981\u3002\u6211\u4eec\u53ef\u4ee5\u5173\u95ed\u6b64\u5e94\u7528\u7a0b\u5e8f\uff0c\u5e76\u7ee7\u7eed\u4f7f\u7528 CompanyEmployees \u5e94\u7528\u7a0b\u5e8f\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Ultimate ASP.NET Core Web API 2nd Premium Edition Ultimate ASP.NET Core Web API 1 PROJECT CONFIGURATION 1 \u9879\u76ee\u914d\u7f6e Ultimate ASP.NET Core Web API 2 Creating the Required Projects 2 \u521b\u5efa\u6240\u9700\u7684\u9879\u76ee Ultimate ASP.NET Core Web API 3 ONION ARCHITECTURE IMPLEMENTATION 3 \u6d0b\u8471\u67b6\u6784\u5b9e\u73b0 Ultimate ASP.NET Core Web API 4 HANDLING GET REQUESTS 4 \u5904\u7406 GET \u8bf7\u6c42 Ultimate [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1100","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts\/1100","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=1100"}],"version-history":[{"count":0,"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts\/1100\/revisions"}],"wp:attachment":[{"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1100"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1100"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1100"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}