{"id":591,"date":"2025-04-05T11:37:37","date_gmt":"2025-04-05T03:37:37","guid":{"rendered":"https:\/\/www.hyy.net\/?p=591"},"modified":"2025-04-05T11:37:37","modified_gmt":"2025-04-05T03:37:37","slug":"asp-net-core-in-action-10-con%ef%ac%81guring-an-asp-net-core-application","status":"publish","type":"post","link":"https:\/\/diji.net\/?p=591","title":{"rendered":"ASP.NET Core in Action 10 Con\ufb01guring an ASP.NET Core application"},"content":{"rendered":"<p>10 Configuring an ASP.NET Core application<br \/>\n10 \u914d\u7f6e ASP.NET Core \u5e94\u7528\u7a0b\u5e8f<\/p>\n<h2>This chapter covers<\/h2>\n<h2>\u672c\u7ae0\u6db5\u76d6<\/h2>\n<ul>\n<li>\n<p>Loading settings from multiple configuration providers<br \/>\n\u4ece\u591a\u4e2a\u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\u52a0\u8f7d\u8bbe\u7f6e<\/p>\n<\/li>\n<li>\n<p>Storing sensitive settings safely<br \/>\n\u5b89\u5168\u5730\u5b58\u50a8\u654f\u611f\u8bbe\u7f6e<\/p>\n<\/li>\n<li>\n<p>Using strongly typed settings objects<br \/>\n\u4f7f\u7528\u5f3a\u7c7b\u578b\u8bbe\u7f6e\u5bf9\u8c61<\/p>\n<\/li>\n<li>\n<p>Using different settings in different hosting environments<br \/>\n\u5728\u4e0d\u540c\u7684\u6258\u7ba1\u73af\u5883\u4e2d\u4f7f\u7528\u4e0d\u540c\u7684\u8bbe\u7f6e<\/p>\n<\/li>\n<\/ul>\n<p>In part 1 of this book, you learned the basics of getting an ASP.NET Core app up and running, and how to use minimal API endpoints to create an HTTP API. When you start building real applications, you\u2019ll quickly find that you want to tweak various settings at deploy time without necessarily having to recompile your application. This chapter looks at how you can achieve this task in ASP.NET Core by using configuration.<\/p>\n<p>\u5728\u672c\u4e66\u7684\u7b2c 1 \u90e8\u5206\u4e2d\uff0c\u60a8\u5b66\u4e60\u4e86\u542f\u52a8\u548c\u8fd0\u884c ASP.NET Core \u5e94\u7528\u7a0b\u5e8f\u7684\u57fa\u7840\u77e5\u8bc6\uff0c\u4ee5\u53ca\u5982\u4f55\u4f7f\u7528\u6700\u5c11\u7684 API \u7aef\u70b9\u6765\u521b\u5efa HTTP API\u3002\u5f53\u60a8\u5f00\u59cb\u6784\u5efa\u771f\u6b63\u7684\u5e94\u7528\u7a0b\u5e8f\u65f6\uff0c\u60a8\u5f88\u5feb\u5c31\u4f1a\u53d1\u73b0\u60a8\u5e0c\u671b\u5728\u90e8\u7f72\u65f6\u8c03\u6574\u5404\u79cd\u8bbe\u7f6e\uff0c\u800c\u4e0d\u5fc5\u91cd\u65b0\u7f16\u8bd1\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u3002\u672c\u7ae0\u4ecb\u7ecd\u5982\u4f55\u4f7f\u7528 configuration \u5728 ASP.NET Core \u4e2d\u5b8c\u6210\u6b64\u4efb\u52a1\u3002<\/p>\n<p>I know. Configuration sounds boring, right? But I have to confess that the configuration model is one of my favorite parts of ASP.NET Core; it\u2019s so easy to use and so much more elegant than some approaches in old versions of .NET Framework. In section 10.2 you\u2019ll learn how to load values from a plethora of sources\u2014JavaScript Object Notation (JSON) files, environment variables, and command-line arguments\u2014and combine them into a unified configuration object.<\/p>\n<p>\u6211\u77e5\u9053\u3002\u914d\u7f6e\u542c\u8d77\u6765\u5f88\u65e0\u804a\uff0c\u5bf9\u5427\uff1f\u4f46\u6211\u4e0d\u5f97\u4e0d\u627f\u8ba4\uff0c\u914d\u7f6e\u6a21\u578b\u662f ASP.NET Core \u4e2d\u6211\u6700\u559c\u6b22\u7684\u90e8\u5206\u4e4b\u4e00;\u5b83\u975e\u5e38\u6613\u4e8e\u4f7f\u7528\uff0c\u5e76\u4e14\u6bd4\u65e7\u7248\u672c\u7684 .NET Framework \u4e2d\u7684\u67d0\u4e9b\u65b9\u6cd5\u8981\u4f18\u96c5\u5f97\u591a\u3002\u5728\u7b2c 10.2 \u8282\u4e2d\uff0c\u60a8\u5c06\u5b66\u4e60\u5982\u4f55\u4ece\u5927\u91cf\u6765\u6e90\uff08JavaScript \u5bf9\u8c61\u8868\u793a\u6cd5 \uff08JSON\uff09 \u6587\u4ef6\u3001\u73af\u5883\u53d8\u91cf\u548c\u547d\u4ee4\u884c\u53c2\u6570\uff09\u52a0\u8f7d\u503c\uff0c\u5e76\u5c06\u5b83\u4eec\u7ec4\u5408\u5230\u4e00\u4e2a\u7edf\u4e00\u7684\u914d\u7f6e\u5bf9\u8c61\u4e2d\u3002<\/p>\n<p>On top of that, ASP.NET Core makes it easy to bind this configuration to strongly typed options objects\u2014simple plain old CLR object (POCO) classes that are populated from the configuration object, which you can inject into your services, as you\u2019ll see in section 10.3. Binding to strongly typed options objects lets you nicely encapsulate settings for different features in your app.<\/p>\n<p>\u6700\u91cd\u8981\u7684\u662f\uff0cASP.NET Core \u53ef\u4ee5\u8f7b\u677e\u5730\u5c06\u6b64\u914d\u7f6e\u7ed1\u5b9a\u5230\u5f3a\u7c7b\u578b\u9009\u9879\u5bf9\u8c61 \u2014 \u4ece\u914d\u7f6e\u5bf9\u8c61\u586b\u5145\u7684\u7b80\u5355\u666e\u901a\u65e7 CLR \u5bf9\u8c61 \uff08POCO\uff09 \u7c7b\uff0c\u60a8\u53ef\u4ee5\u5c06\u5176\u6ce8\u5165\u5230\u60a8\u7684\u670d\u52a1\u4e2d\uff0c\u5982\u7b2c 10.3 \u8282\u6240\u793a\u3002\u7ed1\u5b9a\u5230\u5f3a\u7c7b\u578b\u9009\u9879\u5bf9\u8c61\u53ef\u4ee5\u8ba9\u60a8\u5f88\u597d\u5730\u5c01\u88c5\u5e94\u7528\u7a0b\u5e8f\u4e2d\u4e0d\u540c\u529f\u80fd\u7684\u8bbe\u7f6e\u3002<\/p>\n<p>In the final section of this chapter, you\u2019ll learn about the ASP.NET Core hosting environments. You often want your app to run differently in different situations, such as running it on your developer machine compared with deploying it to a production server. These situations are known as environments. When the app knows the environment in which it\u2019s running, it can load a different configuration and vary its behavior accordingly.<\/p>\n<p>\u5728\u672c\u7ae0\u7684\u6700\u540e\u4e00\u8282\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3 ASP.NET Core \u6258\u7ba1\u73af\u5883\u3002\u60a8\u901a\u5e38\u5e0c\u671b\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u5728\u4e0d\u540c\u60c5\u51b5\u4e0b\u4ee5\u4e0d\u540c\u7684\u65b9\u5f0f\u8fd0\u884c\uff0c\u4f8b\u5982\u5728\u5f00\u53d1\u4eba\u5458\u8ba1\u7b97\u673a\u4e0a\u8fd0\u884c\u5b83\u4e0e\u5c06\u5176\u90e8\u7f72\u5230\u751f\u4ea7\u670d\u52a1\u5668\u3002\u8fd9\u4e9b\u60c5\u51b5\u79f0\u4e3a\u73af\u5883\u3002\u5f53\u5e94\u7528\u7a0b\u5e8f\u77e5\u9053\u5b83\u8fd0\u884c\u7684\u73af\u5883\u65f6\uff0c\u5b83\u53ef\u4ee5\u52a0\u8f7d\u4e0d\u540c\u7684\u914d\u7f6e\u5e76\u76f8\u5e94\u5730\u6539\u53d8\u5176\u884c\u4e3a\u3002<\/p>\n<p>Before we get to that topic, let\u2019s cover the basics. What is configuration, why do we need it, and how does ASP.NET Core handle these requirements?<\/p>\n<p>\u5728\u6211\u4eec\u8fdb\u5165\u8be5\u4e3b\u9898\u4e4b\u524d\uff0c\u8ba9\u6211\u4eec\u5148\u4e86\u89e3\u4e00\u4e0b\u57fa\u7840\u77e5\u8bc6\u3002\u4ec0\u4e48\u662f\u914d\u7f6e\uff0c\u6211\u4eec\u4e3a\u4ec0\u4e48\u9700\u8981\u5b83\uff0c\u4ee5\u53ca ASP.NET Core \u5982\u4f55\u5904\u7406\u8fd9\u4e9b\u8981\u6c42\uff1f<\/p>\n<h2>10.1 Introducing the ASP.NET Core configuration model<\/h2>\n<h2>10.1 ASP.NET Core \u914d\u7f6e\u6a21\u578b\u7b80\u4ecb<\/h2>\n<p>In this section I provide a brief description of configuration and what you can use it for in ASP.NET Core applications. Configuration is the set of external parameters provided to an application that controls the application\u2019s behavior in some way. It typically consists of a mixture of settings and secrets that the application loads at runtime.<\/p>\n<p>\u5728\u672c\u8282\u4e2d\uff0c\u6211\u5c06\u7b80\u8981\u4ecb\u7ecd\u914d\u7f6e\u4ee5\u53ca\u60a8\u53ef\u4ee5\u5728 ASP.NET Core \u5e94\u7528\u7a0b\u5e8f\u4e2d\u4f7f\u7528\u5b83\u7684\u7528\u9014\u3002Configuration \u662f\u63d0\u4f9b\u7ed9\u5e94\u7528\u7a0b\u5e8f\u7684\u4e00\u7ec4\u5916\u90e8\u53c2\u6570\uff0c\u5b83\u4ee5\u67d0\u79cd\u65b9\u5f0f\u63a7\u5236\u5e94\u7528\u7a0b\u5e8f\u7684\u884c\u4e3a\u3002\u5b83\u901a\u5e38\u7531\u5e94\u7528\u7a0b\u5e8f\u5728\u8fd0\u884c\u65f6\u52a0\u8f7d\u7684\u8bbe\u7f6e\u548c\u5bc6\u94a5\u7684\u6df7\u5408\u7ec4\u6210\u3002<\/p>\n<p><strong>Definition<\/strong> A setting is any value that changes the behavior of your application. A secret is a special type of setting that contains sensitive data, such as a password, an API key for a third-party service, or a connection string.<br \/>\n<strong>\u5b9a\u4e49<\/strong> \u8bbe\u7f6e\u662f\u66f4\u6539\u5e94\u7528\u7a0b\u5e8f\u884c\u4e3a\u7684\u4efb\u4f55\u503c\u3002\u5bc6\u94a5\u662f\u4e00\u79cd\u7279\u6b8a\u7c7b\u578b\u7684\u8bbe\u7f6e\uff0c\u5176\u4e2d\u5305\u542b\u654f\u611f\u6570\u636e\uff0c\u4f8b\u5982\u5bc6\u7801\u3001\u7b2c\u4e09\u65b9\u670d\u52a1\u7684 API \u5bc6\u94a5\u6216\u8fde\u63a5\u5b57\u7b26\u4e32\u3002<\/p>\n<p>The obvious things to consider before we get started are why we need app configuration and what sort of things we need to configure. Normally, you move anything that you can consider to be a setting or a secret out of your application code. That way, you can change these values at deploy time easily without having to recompile your application.<\/p>\n<p>\u5728\u5f00\u59cb\u4e4b\u524d\uff0c\u8981\u8003\u8651\u7684\u660e\u663e\u4e8b\u9879\u662f\u4e3a\u4ec0\u4e48\u9700\u8981\u5e94\u7528\u7a0b\u5e8f\u914d\u7f6e\u4ee5\u53ca\u9700\u8981\u914d\u7f6e\u54ea\u4e9b\u7c7b\u578b\u7684\u5185\u5bb9\u3002\u901a\u5e38\uff0c\u60a8\u5c06\u4efb\u4f55\u53ef\u4ee5\u89c6\u4e3a\u8bbe\u7f6e\u6216\u5bc6\u94a5\u7684\u5185\u5bb9\u4ece\u5e94\u7528\u7a0b\u5e8f\u4ee3\u7801\u4e2d\u79fb\u51fa\u3002\u8fd9\u6837\uff0c\u60a8\u5c31\u53ef\u4ee5\u5728\u90e8\u7f72\u65f6\u8f7b\u677e\u66f4\u6539\u8fd9\u4e9b\u503c\uff0c\u800c\u65e0\u9700\u91cd\u65b0\u7f16\u8bd1\u5e94\u7528\u7a0b\u5e8f\u3002<\/p>\n<p>You might have an application that shows the locations of your bricks-and-mortar stores. You could have a setting for the connection string to the database in which you store the details on the stores, but also settings such as the default location to display on a map, the default zoom level to use, and the API key for accessing the Google Maps API (figure 10.1). Storing these settings and secrets outside your compiled code is good practice, as it makes it easy to tweak them without having to recompile your code.<\/p>\n<p>\u60a8\u53ef\u80fd\u6709\u4e00\u4e2a\u663e\u793a\u5b9e\u4f53\u5e97\u4f4d\u7f6e\u7684\u5e94\u7528\u7a0b\u5e8f\u3002\u4f60\u53ef\u4ee5\u8bbe\u7f6e\u5b58\u50a8\u5546\u5e97\u8be6\u7ec6\u4fe1\u606f\u7684\u6570\u636e\u5e93\u7684\u8fde\u63a5\u5b57\u7b26\u4e32\uff0c\u4e5f\u53ef\u4ee5\u8bbe\u7f6e\u5730\u56fe\u4e0a\u663e\u793a\u7684\u9ed8\u8ba4\u4f4d\u7f6e\u3001\u8981\u4f7f\u7528\u7684\u9ed8\u8ba4\u7f29\u653e\u7ea7\u522b\u4ee5\u53ca\u7528\u4e8e\u8bbf\u95ee Google Maps API \u7684 API \u5bc6\u94a5\u7b49\u8bbe\u7f6e\uff08\u56fe 10.1\uff09\u3002\u5c06\u8fd9\u4e9b\u8bbe\u7f6e\u548c\u5bc6\u94a5\u5b58\u50a8\u5728\u5df2\u7f16\u8bd1\u4ee3\u7801\u4e4b\u5916\u662f\u4e00\u79cd\u5f88\u597d\u7684\u505a\u6cd5\uff0c\u56e0\u4e3a\u5b83\u53ef\u4ee5\u8f7b\u677e\u8c03\u6574\u5b83\u4eec\uff0c\u800c\u65e0\u9700\u91cd\u65b0\u7f16\u8bd1\u4ee3\u7801\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1001.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 10.1 You can store the default map location, zoom level, and mapping API Key in configuration and load them at runtime. It\u2019s important to keep secrets such as API keys in configuration out of your code.<br \/>\n\u56fe 10.1 \u60a8\u53ef\u4ee5\u5728\u914d\u7f6e\u4e2d\u5b58\u50a8\u9ed8\u8ba4\u5730\u56fe\u4f4d\u7f6e\u3001\u7f29\u653e\u7ea7\u522b\u548c\u5730\u56fe API Key\uff0c\u5e76\u5728\u8fd0\u884c\u65f6\u52a0\u8f7d\u5b83\u4eec\u3002\u8bf7\u52a1\u5fc5\u5c06 configuration \u4e2d\u7684 API \u5bc6\u94a5\u7b49\u673a\u5bc6\u4fe1\u606f\u4fdd\u7559\u5728\u4ee3\u7801\u4e4b\u5916\u3002<\/p>\n<p>There\u2019s also a security aspect: you don\u2019t want to hardcode secret values such as API keys or passwords into your code, where they could be committed to source control and made publicly available. Even values embedded in your compiled application can be extracted, so it\u2019s best to externalize them whenever possible.<\/p>\n<p>\u8fd8\u6709\u4e00\u4e2a\u5b89\u5168\u65b9\u9762\uff1a\u60a8\u4e0d\u5e0c\u671b\u5c06 API \u5bc6\u94a5\u6216\u5bc6\u7801\u7b49\u79d8\u5bc6\u503c\u786c\u7f16\u7801\u5230\u4ee3\u7801\u4e2d\uff0c\u56e0\u4e3a\u8fd9\u4e9b\u503c\u53ef\u4ee5\u63d0\u4ea4\u5230\u6e90\u4ee3\u7801\u7ba1\u7406\u4e2d\u5e76\u516c\u5f00\u53ef\u7528\u3002\u751a\u81f3\u53ef\u4ee5\u63d0\u53d6\u5d4c\u5165\u5728\u5df2\u7f16\u8bd1\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u503c\uff0c\u56e0\u6b64\u6700\u597d\u5c3d\u53ef\u80fd\u5c06\u5b83\u4eec\u5916\u90e8\u5316\u3002<\/p>\n<p>Virtually every web framework provides a mechanism for loading configuration, and the old .NET Framework version of ASP.NET was no different. It used the <appsettings> element in a web.config file to store key-value configuration pairs. At runtime you\u2019d use the static (<em>wince<\/em>) ConfigurationManager to load the value for a given key from the file. You could do more advanced things using custom configuration sections, but doing more advanced things using custom configuration sections was painful and so was rarely used, in my experience.<\/p>\n<p>\u5b9e\u9645\u4e0a\uff0c\u6bcf\u4e2a Web \u6846\u67b6\u90fd\u63d0\u4f9b\u4e86\u52a0\u8f7d\u914d\u7f6e\u7684\u673a\u5236\uff0c\u65e7\u7248 ASP.NET \u4e5f\u4e0d\u4f8b\u5916\u3002\u5b83\u4f7f\u7528 web.config \u6587\u4ef6\u4e2d\u7684 <appsettings> \u5143\u7d20\u6765\u5b58\u50a8\u952e\u503c\u914d\u7f6e\u5bf9\u3002\u5728\u8fd0\u884c\u65f6\uff0c\u60a8\u5c06\u4f7f\u7528\u9759\u6001 \uff08<em>wince<\/em>\uff09 ConfigurationManager \u4ece\u6587\u4ef6\u4e2d\u52a0\u8f7d\u7ed9\u5b9a\u952e\u7684\u503c\u3002\u60a8\u53ef\u4ee5\u4f7f\u7528\u81ea\u5b9a\u4e49\u914d\u7f6e\u90e8\u5206\u6267\u884c\u66f4\u9ad8\u7ea7\u7684\u4f5c\uff0c\u4f46\u6839\u636e\u6211\u7684\u7ecf\u9a8c\uff0c\u8fd9\u6837\u505a\u5f88\u75db\u82e6\uff0c\u56e0\u6b64\u5f88\u5c11\u4f7f\u7528\u3002<\/p>\n<p>ASP.NET Core gives you a totally revamped experience. At the most basic level, you\u2019re still specifying key-value pairs as strings, but instead of getting those values from a single file, now you can load them from multiple sources. You can load values from files, but now they can be in any format you like: JSON, XML, YAML, and so on. Further, you can load values from environment variables, from command-line arguments, from a database, or from a remote service. Or you can create your own custom configuration provider.<\/p>\n<p>ASP.NET Core \u4e3a\u60a8\u63d0\u4f9b\u5168\u65b0\u7684\u4f53\u9a8c\u3002\u5728\u6700\u57fa\u672c\u7684\u5c42\u9762\u4e0a\uff0c\u60a8\u4ecd\u7136\u5c06\u952e\u503c\u5bf9\u6307\u5b9a\u4e3a\u5b57\u7b26\u4e32\uff0c\u4f46\u73b0\u5728\u60a8\u53ef\u4ee5\u4ece\u591a\u4e2a\u6e90\u52a0\u8f7d\u5b83\u4eec\uff0c\u800c\u4e0d\u662f\u4ece\u5355\u4e2a\u6587\u4ef6\u4e2d\u83b7\u53d6\u8fd9\u4e9b\u503c\u3002\u60a8\u53ef\u4ee5\u4ece\u6587\u4ef6\u4e2d\u52a0\u8f7d\u503c\uff0c\u4f46\u73b0\u5728\u5b83\u4eec\u53ef\u4ee5\u91c7\u7528\u60a8\u559c\u6b22\u7684\u4efb\u4f55\u683c\u5f0f\uff1aJSON\u3001XML\u3001YAML \u7b49\u3002\u6b64\u5916\uff0c\u8fd8\u53ef\u4ee5\u4ece\u73af\u5883\u53d8\u91cf\u3001\u547d\u4ee4\u884c\u53c2\u6570\u3001\u6570\u636e\u5e93\u6216\u8fdc\u7a0b\u670d\u52a1\u52a0\u8f7d\u503c\u3002\u6216\u8005\uff0c\u60a8\u53ef\u4ee5\u521b\u5efa\u81ea\u5df1\u7684\u81ea\u5b9a\u4e49\u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\u3002<\/p>\n<p><strong>Definition<\/strong> ASP.NET Core uses configuration providers to load key-value pairs from a variety of sources. Applications can use multiple configuration providers.<br \/>\n<strong>\u5b9a\u4e49<\/strong> ASP.NET Core \u4f7f\u7528\u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\u4ece\u5404\u79cd\u6765\u6e90\u52a0\u8f7d\u952e\u503c\u5bf9\u3002\u5e94\u7528\u7a0b\u5e8f\u53ef\u4ee5\u4f7f\u7528\u591a\u4e2a\u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\u3002ASP.NET Core \u914d\u7f6e\u6a21\u578b\u8fd8\u5177\u6709\u8986\u76d6\u8bbe\u7f6e\u7684\u6982\u5ff5\u3002\u6bcf\u4e2a\u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\u90fd\u53ef\u4ee5\u5b9a\u4e49\u81ea\u5df1\u7684\u8bbe\u7f6e\uff0c\u4e5f\u53ef\u4ee5\u8986\u76d6\u5148\u524d\u63d0\u4f9b\u7a0b\u5e8f\u7684\u8bbe\u7f6e\u3002\u60a8\u5c06\u5728 10.2 \u8282\u4e2d\u770b\u5230\u8fd9\u4e2a\u975e\u5e38\u6709\u7528\u7684\u529f\u80fd\u3002<\/p>\n<p>The ASP.NET Core configuration model also has the concept of overriding settings. Each configuration provider can define its own settings, or it can overwrite settings from a previous provider. You\u2019ll see this incredibly useful feature in action in section 10.2.<\/p>\n<p>ASP.NET Core \u4e3a\u60a8\u63d0\u4f9b\u5168\u65b0\u7684\u4f53\u9a8c\u3002\u5728\u6700\u57fa\u672c\u7684\u5c42\u9762\u4e0a\uff0c\u60a8\u4ecd\u7136\u5c06\u952e\u503c\u5bf9\u6307\u5b9a\u4e3a\u5b57\u7b26\u4e32\uff0c\u4f46\u73b0\u5728\u60a8\u53ef\u4ee5\u4ece\u591a\u4e2a\u6e90\u52a0\u8f7d\u5b83\u4eec\uff0c\u800c\u4e0d\u662f\u4ece\u5355\u4e2a\u6587\u4ef6\u4e2d\u83b7\u53d6\u8fd9\u4e9b\u503c\u3002\u60a8\u53ef\u4ee5\u4ece\u6587\u4ef6\u4e2d\u52a0\u8f7d\u503c\uff0c\u4f46\u73b0\u5728\u5b83\u4eec\u53ef\u4ee5\u91c7\u7528\u60a8\u559c\u6b22\u7684\u4efb\u4f55\u683c\u5f0f\uff1aJSON\u3001XML\u3001YAML \u7b49\u3002\u6b64\u5916\uff0c\u8fd8\u53ef\u4ee5\u4ece\u73af\u5883\u53d8\u91cf\u3001\u547d\u4ee4\u884c\u53c2\u6570\u3001\u6570\u636e\u5e93\u6216\u8fdc\u7a0b\u670d\u52a1\u52a0\u8f7d\u503c\u3002\u6216\u8005\uff0c\u60a8\u53ef\u4ee5\u521b\u5efa\u81ea\u5df1\u7684\u81ea\u5b9a\u4e49\u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\u3002<\/p>\n<p>ASP.NET Core makes it simple to bind these key-value pairs, which are defined as strings, to POCO-setting classes that you define in your code. This model of strongly typed configuration, described in section 10.3, makes it easy to group settings logically around a given feature and lends itself well to unit testing.<\/p>\n<p>ASP.NET Core \u4f7f\u5c06\u8fd9\u4e9b\u5b9a\u4e49\u4e3a\u5b57\u7b26\u4e32\u7684\u952e\u503c\u5bf9\u7ed1\u5b9a\u5230\u60a8\u5728\u4ee3\u7801\u4e2d\u5b9a\u4e49\u7684 POCO \u8bbe\u7f6e\u7c7b\u53d8\u5f97\u7b80\u5355\u3002\u8fd9\u79cd\u5f3a\u7c7b\u578b\u914d\u7f6e\u6a21\u578b\uff08\u5728 Section 10.3 \u4e2d\u63cf\u8ff0\uff09\u53ef\u4ee5\u5f88\u5bb9\u6613\u5730\u56f4\u7ed5\u7ed9\u5b9a\u529f\u80fd\u5bf9\u8bbe\u7f6e\u8fdb\u884c\u903b\u8f91\u5206\u7ec4\uff0c\u5e76\u4e14\u975e\u5e38\u9002\u5408 unit testing\u3002<\/p>\n<p>Before we get to strongly typed settings, we\u2019ll look at how you load the settings and secrets for your app, whether they\u2019re stored in JSON files, environment variables, or command-line arguments.<\/p>\n<p>\u5728\u5f00\u59cb\u5f3a\u7c7b\u578b\u8bbe\u7f6e\u4e4b\u524d\uff0c\u6211\u4eec\u5c06\u4e86\u89e3\u5982\u4f55\u52a0\u8f7d\u5e94\u7528\u7a0b\u5e8f\u7684\u8bbe\u7f6e\u548c Secret\uff0c\u65e0\u8bba\u5b83\u4eec\u662f\u5b58\u50a8\u5728 JSON \u6587\u4ef6\u3001\u73af\u5883\u53d8\u91cf\u8fd8\u662f\u547d\u4ee4\u884c\u53c2\u6570\u4e2d\u3002<\/p>\n<h2>10.2 Building a configuration object for your app<\/h2>\n<h2>10.2 \u4e3a\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u6784\u5efa\u914d\u7f6e\u5bf9\u8c61<\/h2>\n<p>In this section we\u2019ll get into the meat of the configuration system. You\u2019ll learn how to load settings from multiple sources, how they\u2019re stored internally in ASP.NET Core, and how settings can override other values to produce layers of configuration. You\u2019ll also learn how to store secrets securely while ensuring that they\u2019re still available when you run your app.<\/p>\n<p>\u5728\u672c\u8282\u4e2d\uff0c\u6211\u4eec\u5c06\u6df1\u5165\u4ecb\u7ecd\u914d\u7f6e\u7cfb\u7edf\u7684\u6838\u5fc3\u5185\u5bb9\u3002\u60a8\u5c06\u5b66\u4e60\u5982\u4f55\u4ece\u591a\u4e2a\u6765\u6e90\u52a0\u8f7d\u8bbe\u7f6e\uff0c\u5982\u4f55\u5c06\u5b83\u4eec\u5185\u90e8\u5b58\u50a8\u5728 ASP.NET Core \u4e2d\uff0c\u4ee5\u53ca\u8bbe\u7f6e\u5982\u4f55\u8986\u76d6\u5176\u4ed6\u503c\u4ee5\u751f\u6210\u914d\u7f6e\u5c42\u3002\u60a8\u8fd8\u5c06\u5b66\u4e60\u5982\u4f55\u5b89\u5168\u5730\u5b58\u50a8\u5bc6\u94a5\uff0c\u540c\u65f6\u786e\u4fdd\u5728\u8fd0\u884c\u5e94\u7528\u7a0b\u5e8f\u65f6\u5b83\u4eec\u4ecd\u7136\u53ef\u7528\u3002<\/p>\n<p>ASP.NET Core\u2019s configuration model has been essentially the same since .NET Core 1.0, but in .NET 6, ASP.NET Core introduced the ConfigurationManager class. ConfigurationManager simplifies common patterns for working with configuration by implementing both of the two main configuration-related interfaces: IConfigurationBuilder and IConfigurationRoot.<\/p>\n<p>\u81ea .NET Core 1.0 \u4ee5\u6765\uff0cASP.NET Core \u7684\u914d\u7f6e\u6a21\u578b\u57fa\u672c\u76f8\u540c\uff0c\u4f46\u5728 .NET 6 \u4e2d\uff0cASP.NET Core \u5f15\u5165\u4e86 ConfigurationManager \u7c7b\u3002ConfigurationManager \u7b80\u5316\u4e86\u901a\u8fc7\u5b9e\u73b0\u4e24\u4e2a\u4e3b\u8981\u7684\u4e0e\u914d\u7f6e\u76f8\u5173\u7684\u63a5\u53e3\u6765\u5904\u7406\u914d\u7f6e\uff1aIConfigurationBuilder \u548cIConfigurationRoot\u3002<\/p>\n<p><strong>Note<\/strong> IConfigurationBuilder describes how to construct the final configuration representation for your app, and IConfigurationRoot holds the configuration values themselves.<br \/>\n<strong>\u6ce8\u610f<\/strong> IConfigurationBuilder \u63cf\u8ff0\u4e86\u5982\u4f55\u4e3a\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u6784\u5efa\u6700\u7ec8\u7684\u914d\u7f6e\u8868\u793a\u5f62\u5f0f\uff0c\u800c IConfigurationRoot \u672c\u8eab\u4fdd\u5b58\u4e86\u914d\u7f6e\u503c\u3002<\/p>\n<p>You describe your configuration by adding IConfigurationProviders to the ConfigurationManager. Configuration providers describe how to load the key-value pairs from a particular source, such as a JSON file or environment variables (figure 10.2). When you add a provider, the ConfigurationManager queries it and adds all the values returned to the IConfigurationRoot implementation.<\/p>\n<p>\u60a8\u53ef\u4ee5\u901a\u8fc7\u5c06 IConfigurationProvider\u6dfb\u52a0\u5230 ConfigurationManager \u6765\u63cf\u8ff0\u60a8\u7684\u914d\u7f6e\u3002\u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\u63cf\u8ff0\u4e86\u5982\u4f55\u4ece\u7279\u5b9a\u6e90\uff08\u4f8b\u5982 JSON \u6587\u4ef6\u6216\u73af\u5883\u53d8\u91cf\uff09\u52a0\u8f7d\u952e\u503c\u5bf9\uff08\u56fe 10.2\uff09\u3002\u5f53\u60a8\u6dfb\u52a0\u63d0\u4f9b\u7a0b\u5e8f\u65f6\uff0cConfigurationManager \u4f1a\u67e5\u8be2\u5b83\uff0c\u5e76\u5c06\u8fd4\u56de\u7ed9 IConfigurationRoot \u5b9e\u73b0\u7684\u6240\u6709\u503c\u6dfb\u52a0\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1002.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 10.2 Using ConfigurationManager to populate IConfiguration. Configuration providers are added to the ConfigurationManager with extension methods. The manager queries the provider and adds all the returned values to the IConfigurationRoot, which implements IConfiguration.<br \/>\n\u56fe 10.2 \u4f7f\u7528 ConfigurationManager \u586b\u5145 IConfiguration\u3002\u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\u4f7f\u7528\u6269\u5c55\u65b9\u6cd5\u6dfb\u52a0\u5230 ConfigurationManager\u3002\u7ecf\u7406\u67e5\u8be2\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u5e76\u5c06\u6240\u6709\u8fd4\u56de\u7684\u503c\u6dfb\u52a0\u5230\u5b9e\u73b0 IConfiguration \u7684 IConfigurationRoot\u3002<\/p>\n<p><strong>Note<\/strong> Adding a provider to the ConfigurationManager adds the configuration values to the IConfigurationRoot instance, which implements IConfiguration. You\u2019ll generally work with the IConfiguration interface in your code.<br \/>\n<strong>\u6ce8\u610f<\/strong> \u5c06\u63d0\u4f9b\u7a0b\u5e8f\u6dfb\u52a0\u5230 ConfigurationManager \u4f1a\u5c06\u914d\u7f6e\u503c\u6dfb\u52a0\u5230\u5b9e\u73b0 IConfiguration \u7684 IConfigurationRoot \u5b9e\u4f8b\u3002\u60a8\u901a\u5e38\u4f1a\u5728\u4ee3\u7801\u4e2d\u4f7f\u7528IConfiguration \u63a5\u53e3\u3002<\/p>\n<p>ASP.NET Core ships with configuration providers for loading data from common locations:<br \/>\nASP.NET Core \u9644\u5e26\u4e86\u7528\u4e8e\u4ece\u5e38\u89c1\u4f4d\u7f6e\u52a0\u8f7d\u6570\u636e\u7684\u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\uff1a<\/p>\n<ul>\n<li>\n<p>JSON files<br \/>\nJSON \u6587\u4ef6<\/p>\n<\/li>\n<li>\n<p>Extensible Markup Language (XML) files<br \/>\n\u53ef\u6269\u5c55\u6807\u8bb0\u8bed\u8a00 \uff08XML\uff09 \u6587\u4ef6<\/p>\n<\/li>\n<li>\n<p>Environment variables<br \/>\n\u73af\u5883\u53d8\u91cf<\/p>\n<\/li>\n<li>\n<p>Command-line arguments<br \/>\n\u547d\u4ee4\u884c\u53c2\u6570<\/p>\n<\/li>\n<li>\n<p>Initialization (INI) files<br \/>\n\u521d\u59cb\u5316 \uff08INI\uff09 \u6587\u4ef6<\/p>\n<\/li>\n<\/ul>\n<p>If these providers don\u2019t fit your requirements, you can find a host of alternatives on GitHub and NuGet, and it\u2019s not difficult to create your own custom provider. You could use the official Microsoft Azure Key Vault provider NuGet package or the YAML file provider I wrote.<\/p>\n<p>\u5982\u679c\u8fd9\u4e9b\u63d0\u4f9b\u7a0b\u5e8f\u4e0d\u7b26\u5408\u60a8\u7684\u8981\u6c42\uff0c\u60a8\u53ef\u4ee5\u5728 GitHub \u548c NuGet \u4e0a\u627e\u5230\u8bb8\u591a\u66ff\u4ee3\u65b9\u6848\uff0c\u5e76\u4e14\u521b\u5efa\u81ea\u5df1\u7684\u81ea\u5b9a\u4e49\u63d0\u4f9b\u7a0b\u5e8f\u5e76\u4e0d\u96be\u3002\u60a8\u53ef\u4ee5\u4f7f\u7528\u5b98\u65b9\u7684 Microsoft Azure Key Vault \u63d0\u4f9b\u7a0b\u5e8f NuGet \u5305\u6216\u6211\u7f16\u5199\u7684 YAML \u6587\u4ef6\u63d0\u4f9b\u7a0b\u5e8f\u3002<\/p>\n<p><strong>Note<\/strong> The Azure Key Vault provider is available on NuGet at <a href=\"http:\/\/mng.bz\/0KrN\">http:\/\/mng.bz\/0KrN<\/a>, and you can find my YAML provider on GitHub at <a href=\"http:\/\/mng.bz\/Yqdj\">http:\/\/mng.bz\/Yqdj<\/a>.<br \/>\n<strong>\u6ce8\u610f\uff1a<\/strong> Azure Key Vault \u63d0\u4f9b\u7a0b\u5e8f\u5728 NuGet \u4e0a\u4ee5 <a href=\"http:\/\/mng.bz\/\">http:\/\/mng.bz\/<\/a> 0KrN \u63d0\u4f9b\uff0c\u60a8\u53ef\u4ee5\u5728 GitHub \u4e0a\u627e\u5230\u6211\u7684 YAML \u63d0\u4f9b\u7a0b\u5e8f\uff0c\u7f51\u5740\u4e3a <a href=\"http:\/\/mng.bz\/Yqdj\">http:\/\/mng.bz\/Yqdj<\/a>\u3002<\/p>\n<p>In many cases, the default providers are sufficient. In particular, most templates start with an appsettings.json file, which contains a variety of settings depending on the template you choose. The following listing shows the default file generated by the ASP.NET Core 7.0 Empty template without authentication.<\/p>\n<p>\u5728\u8bb8\u591a\u60c5\u51b5\u4e0b\uff0c\u9ed8\u8ba4\u63d0\u4f9b\u7a0b\u5e8f\u5c31\u8db3\u591f\u4e86\u3002\u7279\u522b\u662f\uff0c\u5927\u591a\u6570\u6a21\u677f\u90fd\u4ee5 appsettings.json \u6587\u4ef6\u5f00\u5934\uff0c\u8be5\u6587\u4ef6\u5305\u542b\u5404\u79cd\u8bbe\u7f6e\uff0c\u5177\u4f53\u53d6\u51b3\u4e8e\u60a8\u9009\u62e9\u7684\u6a21\u677f\u3002\u4ee5\u4e0b\u6e05\u5355\u663e\u793a\u4e86 ASP.NET Core 7.0 Empty \u6a21\u677f\u751f\u6210\u7684\u9ed8\u8ba4\u6587\u4ef6\uff0c\u65e0\u9700\u8eab\u4efd\u9a8c\u8bc1\u3002<\/p>\n<p>Listing 10.1 Default appsettings.json file created by an ASP.NET Core<br \/>\n\u6e05\u5355 10.1 \u7531 ASP.NET Core Empty \u6a21\u677f\u521b\u5efa\u7684\u9ed8\u8ba4 appsettings.json \u6587\u4ef6<\/p>\n<pre><code>{\n  &quot;Logging&quot;: {\n    &quot;LogLevel&quot;: {\n      &quot;Default&quot;: &quot;Information&quot;,\n      &quot;Microsoft.AspNetCore&quot;: &quot;Warning&quot;\n    }\n  },\n  &quot;AllowedHosts&quot;: &quot;*&quot;\n}<\/code><\/pre>\n<p>As you can see, this file contains mostly settings to control logging, but you can add extra configuration for your app here too.<\/p>\n<p>\u5982\u60a8\u6240\u89c1\uff0c\u6b64\u6587\u4ef6\u4e3b\u8981\u5305\u542b\u7528\u4e8e\u63a7\u5236\u65e5\u5fd7\u8bb0\u5f55\u7684\u8bbe\u7f6e\uff0c\u4f46\u60a8\u4e5f\u53ef\u4ee5\u5728\u6b64\u5904\u4e3a\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u6dfb\u52a0\u989d\u5916\u7684\u914d\u7f6e\u3002<\/p>\n<p><strong>Warning<\/strong> Don\u2019t store sensitive values\u2014such as passwords, API keys, and connection strings\u2014in this file. You\u2019ll see how to store these values securely in section 10.2.3.<br \/>\n<strong>\u8b66\u544a<\/strong> \u4e0d\u8981\u5728\u6b64\u6587\u4ef6\u4e2d\u5b58\u50a8\u654f\u611f\u503c\uff0c\u4f8b\u5982\u5bc6\u7801\u3001API \u5bc6\u94a5\u548c\u8fde\u63a5\u5b57\u7b26\u4e32\u3002\u60a8\u5c06\u5728 Section 10.2.3 \u4e2d\u770b\u5230\u5982\u4f55\u5b89\u5168\u5730\u5b58\u50a8\u8fd9\u4e9b\u503c\u3002<\/p>\n<p>Adding your own configuration values involves adding a key-value pair to the JSON. It\u2019s a good idea to namespace your settings by creating a base object for related settings, as in the MapSettings object shown in the following listing.<\/p>\n<p>\u6dfb\u52a0\u60a8\u81ea\u5df1\u7684\u914d\u7f6e\u503c\u6d89\u53ca\u5411 JSON \u6dfb\u52a0\u952e\u503c\u5bf9\u3002\u901a\u8fc7\u4e3a\u76f8\u5173\u8bbe\u7f6e\u521b\u5efa\u57fa\u672c\u5bf9\u8c61\u6765\u547d\u540d\u8bbe\u7f6e\u662f\u4e00\u4e2a\u597d\u4e3b\u610f\uff0c\u5982\u4e0b\u9762\u7684\u6e05\u5355\u6240\u793a\u7684 MapSettings \u5bf9\u8c61\u3002<\/p>\n<p>Listing 10.2 Adding configuration values to an appsettings.json file<br \/>\n\u793a\u4f8b 10.2 \u5411 appsettings.json \u6587\u4ef6\u6dfb\u52a0\u914d\u7f6e\u503c<\/p>\n<pre><code>{\n    &quot;Logging&quot;: {\n        &quot;LogLevel&quot;: {\n            &quot;Default&quot;: &quot;Information&quot;,\n            &quot;Microsoft&quot;: &quot;Warning&quot;,\n            &quot;Microsoft.Hosting.Lifetime&quot;: &quot;Information&quot;\n        }\n    },\n    &quot;AllowedHosts&quot;: &quot;*&quot;,\n    &quot;MapSettings&quot;: { \u2776\n        &quot;DefaultZoomLevel&quot;: 9, \u2777\n        &quot;DefaultLocation&quot;: { \u2778\n        &quot;latitude&quot;: 50.500, \u2778\n        &quot;longitude&quot;: -4.000 \u2778\n        }\n    }\n}<\/code><\/pre>\n<p>\u2776 Nest all the configuration under the MapSettings key.<br \/>\n\u5c06\u6240\u6709\u914d\u7f6e\u5d4c\u5957\u5728 MapSettings \u952e\u4e0b\u3002<\/p>\n<p>\u2777 Values can be numbers in the JSON file, but they\u2019ll be converted to strings when they\u2019re read.<br \/>\n\u503c\u53ef\u4ee5\u662f JSON \u6587\u4ef6\u4e2d\u7684\u6570\u5b57\uff0c\u4f46\u5728\u8bfb\u53d6\u65f6\u5b83\u4eec\u4f1a\u8f6c\u6362\u4e3a\u5b57\u7b26\u4e32\u3002<\/p>\n<p>\u2778 You can create deeply nested structures to organize your configuration values better.<br \/>\n\u60a8\u53ef\u4ee5\u521b\u5efa\u6df1\u5ea6\u5d4c\u5957\u7684\u7ed3\u6784\u6765\u66f4\u597d\u5730\u7ec4\u7ec7\u60a8\u7684\u914d\u7f6e\u503c\u3002<\/p>\n<p>I\u2019ve nested the new configuration inside the MapSettings parent key to create a section that will be useful later for binding values to a POCO object. I also nested the latitude and longitude keys under the DefaultLocation key. You can create any structure of values you like; the configuration provider will read them fine. Also, you can store the values as any data type\u2014numbers, in this case\u2014but be aware that the provider will read and store them internally as strings.<\/p>\n<p>\u6211\u5df2\u5c06\u65b0\u914d\u7f6e\u5d4c\u5957\u5728 MapSettings \u7236\u952e\u4e2d\uff0c\u4ee5\u521b\u5efa\u4e00\u4e2a\u90e8\u5206\uff0c\u8be5\u90e8\u5206\u7a0d\u540e\u5c06\u7528\u4e8e\u5c06\u503c\u7ed1\u5b9a\u5230 POCO \u5bf9\u8c61\u3002\u6211\u8fd8\u5c06\u7eac\u5ea6\u548c\u7ecf\u5ea6\u952e\u5d4c\u5957\u5728 DefaultLocation \u952e\u4e0b\u3002\u60a8\u53ef\u4ee5\u521b\u5efa\u4efb\u4f55\u60a8\u559c\u6b22\u7684\u503c\u7ed3\u6784;\u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\u5c06\u8bfb\u53d6\u5b83\u4eec\u3002\u6b64\u5916\uff0c\u60a8\u53ef\u4ee5\u5c06\u503c\u5b58\u50a8\u4e3a\u4efb\u4f55\u6570\u636e\u7c7b\u578b\uff08\u5728\u672c\u4f8b\u4e2d\u4e3a\u6570\u5b57\uff09\uff0c\u4f46\u8bf7\u6ce8\u610f\uff0c\u63d0\u4f9b\u7a0b\u5e8f\u5c06\u5728\u5185\u90e8\u5c06\u5b83\u4eec\u8bfb\u53d6\u5e76\u5b58\u50a8\u4e3a\u5b57\u7b26\u4e32\u3002<\/p>\n<p><strong>Tip<\/strong> The configuration keys are not case-sensitive in your app, so bear that fact in mind when loading from providers in which the keys are case-sensitive. If you have a YAML file with keys name and NAME, for example, only one will appear in the final IConfiguration.<br \/>\n<strong>\u63d0\u793a<\/strong> \u914d\u7f6e\u952e\u5728\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u4e2d\u4e0d\u533a\u5206\u5927\u5c0f\u5199\uff0c\u56e0\u6b64\u5728\u4ece\u952e\u533a\u5206\u5927\u5c0f\u5199\u7684\u63d0\u4f9b\u7a0b\u5e8f\u52a0\u8f7d\u65f6\uff0c\u8bf7\u8bb0\u4f4f\u8fd9\u4e00\u4e8b\u5b9e\u3002\u4f8b\u5982\uff0c\u5982\u679c\u60a8\u6709\u4e00\u4e2a\u5177\u6709\u952e name \u548c NAME \u7684 YAML \u6587\u4ef6\uff0c\u5219\u6700\u7ec8\u7684 IConfiguration \u4e2d\u53ea\u4f1a\u663e\u793a\u4e00\u4e2a\u3002<\/p>\n<p>Now that you have a configuration file, it\u2019s time for your app to load it into the ConfigurationManager.<\/p>\n<p>\u73b0\u5728\u4f60\u6709\u4e86\u4e00\u4e2a\u914d\u7f6e\u6587\u4ef6\uff0c\u662f\u65f6\u5019\u8ba9\u4f60\u7684\u5e94\u7528\u7a0b\u5e8f\u5c06\u5176\u52a0\u8f7d\u5230 ConfigurationManager \u4e2d\u4e86\u3002<\/p>\n<h3>10.2.1 Adding a configuration provider in Program.cs<\/h3>\n<h3>10.2.1 \u5728 Program.cs \u4e2d\u6dfb\u52a0\u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f<\/h3>\n<p>As you\u2019ve seen throughout this book, ASP.NET Core (from .NET 6 onward) uses the WebApplicationBuilder class to bootstrap your application. As part of the bootstrap process, WebApplicationBuilder creates a ConfigurationManager instance and exposes it as the property Configuration.<\/p>\n<p>\u6b63\u5982\u60a8\u5728\u672c\u4e66\u4e2d\u6240\u770b\u5230\u7684\uff0cASP.NET Core\uff08\u4ece .NET 6 \u5f00\u59cb\uff09\u4f7f\u7528WebApplicationBuilder \u7c7b\u6765\u5f15\u5bfc\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u3002\u4f5c\u4e3a\u5f15\u5bfc\u8fc7\u7a0b\u7684\u4e00\u90e8\u5206\uff0cWebApplicationBuilder \u521b\u5efa\u4e00\u4e2a ConfigurationManager \u5b9e\u4f8b\uff0c\u5e76\u5c06\u5176\u516c\u5f00\u4e3a\u5c5e\u6027 Configuration\u3002<\/p>\n<p><strong>Tip<\/strong> You can access the ConfigurationManager directly on WebApplicationBuilder.Configuration and WebApplication.Configuration. Both properties reference the same ConfigurationManager instance.<br \/>\n<strong>\u63d0\u793a<\/strong> \u60a8\u53ef\u4ee5\u76f4\u63a5\u5728 WebApplicationBuilder \u4e0a\u8bbf\u95ee ConfigurationManager\u3002Configuration \u548c WebApplication.Configuration \u7684 Configuration\u3002\u8fd9\u4e24\u4e2a\u5c5e\u6027\u5f15\u7528\u540c\u4e00\u4e2a ConfigurationManager \u5b9e\u4f8b\u3002<\/p>\n<p>WebApplicationBuilder adds several default configuration providers to the ConfigurationManager, which we\u2019ll look at in more detail throughout this chapter:<\/p>\n<p>WebApplicationBuilder \u5411 ConfigurationManager \u6dfb\u52a0\u4e86\u51e0\u4e2a\u9ed8\u8ba4\u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u6211\u4eec\u5c06\u5728\u672c\u7ae0\u4e2d\u66f4\u8be6\u7ec6\u5730\u4ecb\u7ecd\u5b83\u4eec\uff1a<\/p>\n<ul>\n<li>\n<p>JSON file provider\u2014Loads settings from an optional JSON file called appsettings.json. It also loads settings from an optional environment-specific JSON file called appsettings.ENVIRONMENT.json. I show how to use environment-specific files in section 10.4.<br \/>\nJSON \u6587\u4ef6\u63d0\u4f9b\u7a0b\u5e8f - \u4ece\u540d\u4e3a appsettings.json \u7684\u53ef\u9009 JSON \u6587\u4ef6\u52a0\u8f7d\u8bbe\u7f6e\u3002\u5b83\u8fd8\u4ece\u540d\u4e3a appsettings \u7684\u53ef\u9009\u7279\u5b9a\u4e8e\u73af\u5883\u7684 JSON \u6587\u4ef6\u52a0\u8f7d\u8bbe\u7f6e\u3002ENVIRONMENT.json \u7684\u3002\u6211\u5728 Section 10.4 \u4e2d\u5c55\u793a\u4e86\u5982\u4f55\u4f7f\u7528\u7279\u5b9a\u4e8e\u73af\u5883\u7684\u6587\u4ef6\u3002<\/p>\n<\/li>\n<li>\n<p>User Secrets\u2014Loads secrets that are stored safely during development.<br \/>\nUser Secrets \uff08\u7528\u6237\u5bc6\u94a5\uff09 - \u52a0\u8f7d\u5728\u5f00\u53d1\u8fc7\u7a0b\u4e2d\u5b89\u5168\u5b58\u50a8\u7684\u5bc6\u94a5\u3002<\/p>\n<\/li>\n<li>\n<p>Environment variables\u2014Loads environment variables as configuration variables, which are great for storing secrets in production.<br \/>\n\u73af\u5883\u53d8\u91cf \u2014 \u5c06\u73af\u5883\u53d8\u91cf\u52a0\u8f7d\u4e3a\u914d\u7f6e\u53d8\u91cf\uff0c\u8fd9\u975e\u5e38\u9002\u5408\u5728\u751f\u4ea7\u4e2d\u5b58\u50a8\u5bc6\u94a5\u3002<\/p>\n<\/li>\n<li>\n<p>Command-line arguments\u2014Uses values passed as arguments when you run your app.<br \/>\n\u547d\u4ee4\u884c\u53c2\u6570 - \u4f7f\u7528\u5728\u8fd0\u884c\u5e94\u7528\u7a0b\u5e8f\u65f6\u4f5c\u4e3a\u53c2\u6570\u4f20\u9012\u7684\u503c\u3002<\/p>\n<\/li>\n<\/ul>\n<p>The ConfigurationManager is configured with all these sources automatically, but you can easily add more providers. You can also start from scratch and clear the default providers as shown in the following listing, which completely customizes where configuration is loaded from.<\/p>\n<p>ConfigurationManager \u4f1a\u81ea\u52a8\u914d\u7f6e\u6240\u6709\u8fd9\u4e9b\u6e90\uff0c\u4f46\u60a8\u53ef\u4ee5\u8f7b\u677e\u6dfb\u52a0\u66f4\u591a\u63d0\u4f9b\u7a0b\u5e8f\u3002\u60a8\u8fd8\u53ef\u4ee5\u4ece\u5934\u5f00\u59cb\u5e76\u6e05\u9664\u9ed8\u8ba4\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u5982\u4e0b\u9762\u7684\u6e05\u5355\u6240\u793a\uff0c\u5b83\u5b8c\u5168\u81ea\u5b9a\u4e49\u4e86\u52a0\u8f7d\u914d\u7f6e\u7684\u4f4d\u7f6e\u3002<\/p>\n<p>Listing 10.3 Loading appsettings.json by clearing the configuration sources<\/p>\n<pre><code>WebApplicationBuilder builder = WebApplication.CreateBuilder(args);\n\nbuilder.Configuration.Sources.Clear(); \u2776\nbuilder.Configuration.AddJsonFile(&quot;appsettings.json&quot;, optional: true); \u2777\n\nWebApplication app = builder.Build();\n\napp.MapGet(&quot;\/&quot;, () =&gt; app.Configuration.AsEnumerable()); \u2778\n\napp.Run();\n<\/code><\/pre>\n<p>\u2776 Clears the providers configured by default in WebApplicationBuilder<br \/>\n\u6e05\u9664 WebApplicationBuilder \u4e2d\u9ed8\u8ba4\u914d\u7f6e\u7684\u63d0\u4f9b\u7a0b\u5e8f<\/p>\n<p>\u2777 Adds a JSON configuration provider, providing the name of the configuration file<br \/>\n\u6dfb\u52a0 JSON \u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u63d0\u4f9b\u914d\u7f6e\u6587\u4ef6\u7684\u540d\u79f0<\/p>\n<p>\u2778 Returns all the configuration key-value pairs for display purposes<br \/>\n\u8fd4\u56de\u6240\u6709\u914d\u7f6e\u952e\u503c\u5bf9\u4ee5\u4f9b\u663e\u793a<\/p>\n<p>This example added a single JSON configuration provider by calling the AddJsonFile() extension method and providing a filename. It also set the value of optional to true, telling the configuration provider to skip files that it can\u2019t find at runtime instead of throwing FileNotFoundException. When the provider is added, the ConfigurationManager requests all the available values from the provider and adds them to the IConfiguration implementation.<\/p>\n<p>\u6b64\u793a\u4f8b\u901a\u8fc7\u8c03\u7528 AddJsonFile\uff08\uff09 \u6269\u5c55\u65b9\u6cd5\u5e76\u63d0\u4f9b\u6587\u4ef6\u540d\u6765\u6dfb\u52a0\u5355\u4e2a JSON \u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\u3002\u5b83\u8fd8\u5c06 optional \u7684\u503c\u8bbe\u7f6e\u4e3a true\uff0c\u544a\u77e5\u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\u8df3\u8fc7\u5728\u8fd0\u884c\u65f6\u627e\u4e0d\u5230\u7684\u6587\u4ef6\uff0c\u800c\u4e0d\u662f\u5f15\u53d1 FileNotFoundException\u3002\u6dfb\u52a0\u63d0\u4f9b\u7a0b\u5e8f\u540e\uff0c ConfigurationManager \u4ece\u63d0\u4f9b\u7a0b\u5e8f\u8bf7\u6c42\u6240\u6709\u53ef\u7528\u503c\uff0c\u5e76\u5c06\u5b83\u4eec\u6dfb\u52a0\u5230 IConfiguration \u5b9e\u73b0\u4e2d\u3002<\/p>\n<blockquote>\n<p>ConfigurationBuilder vs. ConfigurationManager<br \/>\nConfigurationBuilder \u4e0e ConfigurationManager<br \/>\nBefore .NET 6 and the introduction of ConfigurationManager, configuration in ASP.NET Core was implemented with ConfigurationBuilder. You\u2019d add configuration providers to the builder type the same way you do with ConfigurationManager, but the configuration values weren\u2019t loaded until you called Build(), which created the final IConfigurationRoot object.<br \/>\n\u5728 .NET 6 \u548c ConfigurationManager \u5f15\u5165\u4e4b\u524d\uff0cASP.NET Core \u4e2d\u7684\u914d\u7f6e\u662f\u4f7f\u7528 ConfigurationBuilder \u5b9e\u73b0\u7684\u3002\u60a8\u53ef\u4ee5\u50cf\u4f7f\u7528 ConfigurationManager \u4e00\u6837\u5c06\u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\u6dfb\u52a0\u5230\u751f\u6210\u5668\u7c7b\u578b\u4e2d\uff0c\u4f46\u5728\u8c03\u7528 Build\uff08\uff09 \u4e4b\u524d\u4e0d\u4f1a\u52a0\u8f7d\u914d\u7f6e\u503c\uff0c\u8fd9\u5c06\u521b\u5efa\u6700\u7ec8\u7684 IConfigurationRoot \u5bf9\u8c61\u3002<br \/>\nBy contrast, in .NET 6 and .NET 7 ConfigurationManager acts as both the builder and the final IConfigurationRoot. When you add a new configuration provider, the configuration values are added to the IConfigurationRoot immediately, without the need to call Build() first.<br \/>\n\u76f8\u6bd4\u4e4b\u4e0b\uff0c\u5728 .NET 6 \u548c .NET 7 \u4e2d\uff0cConfigurationManager \u65e2\u5145\u5f53\u751f\u6210\u5668\uff0c\u53c8\u5145\u5f53\u6700\u7ec8\u7684 IConfigurationRoot\u3002\u6dfb\u52a0\u65b0\u7684\u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\u65f6\uff0c\u914d\u7f6e\u503c\u4f1a\u7acb\u5373\u6dfb\u52a0\u5230 IConfigurationRoot\uff0c\u800c\u65e0\u9700\u5148\u8c03\u7528 Build\uff08\uff09\u3002<br \/>\nThe ConfigurationBuilder approach using the builder pattern is cleaner in some ways, as it has a clearer separation of concerns, but the common use patterns for configuration mean that the new ConfigurationManager approach is often easier to use.<br \/>\n\u4f7f\u7528 builder \u6a21\u5f0f\u7684 ConfigurationBuilder \u65b9\u6cd5\u5728\u67d0\u4e9b\u65b9\u9762\u66f4\u7b80\u6d01\uff0c\u56e0\u4e3a\u5b83\u5177\u6709\u66f4\u6e05\u6670\u7684\u5173\u6ce8\u70b9\u5206\u79bb\uff0c\u4f46\u914d\u7f6e\u7684\u5e38\u89c1\u4f7f\u7528\u6a21\u5f0f\u610f\u5473\u7740\u65b0\u7684 ConfigurationManager \u65b9\u6cd5\u901a\u5e38\u66f4\u6613\u4e8e\u4f7f\u7528\u3002<br \/>\nIf you prefer, you can still use the builder pattern by accessing WebApplicationBuilder.Host.ConfigureAppConfiguration. You can read about some of these patterns and the differences between the two approaches on my blog at <a href=\"http:\/\/mng.bz\/Ke4j\">http:\/\/mng.bz\/Ke4j<\/a>.<br \/>\n\u5982\u679c\u60a8\u613f\u610f\uff0c\u60a8\u4ecd\u7136\u53ef\u4ee5\u901a\u8fc7\u8bbf\u95ee WebApplicationBuilder.Host.ConfigureAppConfiguration \u6765\u4f7f\u7528\u6784\u5efa\u5668\u6a21\u5f0f\u3002\u60a8\u53ef\u4ee5\u5728\u6211\u7684\u535a\u5ba2 <a href=\"http:\/\/mng.bz\/Ke4j\">http:\/\/mng.bz\/Ke4j<\/a> \u4e0a\u9605\u8bfb\u5176\u4e2d\u4e00\u4e9b\u6a21\u5f0f\u4ee5\u53ca\u4e24\u79cd\u65b9\u6cd5\u4e4b\u95f4\u7684\u5dee\u5f02\u3002<\/p>\n<\/blockquote>\n<p>You can access the IConfiguration object directly in Program.cs, as in listing 10.3, but the ConfigurationManager is also registered as IConfiguration in the dependency injection (DI) container, so you can inject it into your classes and endpoint handlers. You could rewrite the endpoint handler in listing 10.3 as the following, and the IConfiguration object would be injected into the handler using DI:<\/p>\n<p>\u4f60\u53ef\u4ee5\u76f4\u63a5\u5728 Program.cs \u4e2d\u8bbf\u95ee IConfiguration \u5bf9\u8c61\uff0c\u5982\u6e05\u5355 10.3 \u6240\u793a\uff0c\u4f46 ConfigurationManager \u4e5f\u5728\u4f9d\u8d56\u6ce8\u5165 \uff08DI\uff09 \u5bb9\u5668\u4e2d\u6ce8\u518c\u4e3a IConfiguration\uff0c\u56e0\u6b64\u4f60\u53ef\u4ee5\u5c06\u5176\u6ce8\u5165\u5230\u4f60\u7684\u7c7b\u548c\u7aef\u70b9\u5904\u7406\u7a0b\u5e8f\u4e2d\u3002\u60a8\u53ef\u4ee5\u5c06\u6e05\u5355 10.3 \u4e2d\u7684\u7aef\u70b9\u5904\u7406\u7a0b\u5e8f\u91cd\u5199\u4e3a\u4ee5\u4e0b\u5185\u5bb9\uff0c\u5e76\u4e14 IConfiguration \u5bf9\u8c61\u5c06\u4f7f\u7528 DI \u6ce8\u5165\u5230\u5904\u7406\u7a0b\u5e8f\u4e2d\uff1a<\/p>\n<pre><code>app.MapGet(&quot;\/&quot;, (IConfiguration config) =&gt; config.AsEnumerable());<\/code><\/pre>\n<p><strong>Note<\/strong> The ConfigurationManager implements IConfigurationRoot, which also implements IConfiguration. The ConfigurationManager is registered in the DI container as an IConfiguration, not an IConfigurationRoot.<br \/>\n<strong>\u6ce8\u610f<\/strong> ConfigurationManager \u5b9e\u73b0 IConfigurationRoot\uff0c\u540e\u8005\u4e5f\u5b9e\u73b0 IConfiguration\u3002ConfigurationManager \u5728 DI \u5bb9\u5668\u4e2d\u6ce8\u518c\u4e3a IConfiguration\uff0c\u800c\u4e0d\u662f IConfigurationRoot\u3002<\/p>\n<p>You\u2019ve seen how to add values to the ConfigurationManager by using providers such as the JSON file provider. and listing 10.3 showed an example of iterating over every configuration value, but normally you want to retrieve a specific configuration value.<\/p>\n<p>\u60a8\u5df2\u7ecf\u4e86\u89e3\u4e86\u5982\u4f55\u4f7f\u7528\u8bf8\u5982 JSON \u6587\u4ef6\u63d0\u4f9b\u7a0b\u5e8f\u4e4b\u7c7b\u7684\u63d0\u4f9b\u7a0b\u5e8f\u5411 ConfigurationManager \u6dfb\u52a0\u503c\uff0c\u6e05\u5355 10.3 \u663e\u793a\u4e86\u4e00\u4e2a\u8fed\u4ee3\u6bcf\u4e2a\u914d\u7f6e\u503c\u7684\u793a\u4f8b\uff0c\u4f46\u901a\u5e38\u60a8\u5e0c\u671b\u68c0\u7d22\u7279\u5b9a\u7684\u914d\u7f6e\u503c\u3002<\/p>\n<p>IConfiguration stores configuration as a set of key-value string pairs. You can access any value by its key, using standard dictionary syntax. You could use<\/p>\n<p>IConfiguration \u5c06\u914d\u7f6e\u5b58\u50a8\u4e3a\u4e00\u7ec4\u952e\u503c\u5b57\u7b26\u4e32\u5bf9\u3002\u60a8\u53ef\u4ee5\u4f7f\u7528\u6807\u51c6\u5b57\u5178\u8bed\u6cd5\u901a\u8fc7\u5176\u952e\u8bbf\u95ee\u4efb\u4f55\u503c\u3002\u60a8\u53ef\u4ee5\u4f7f\u7528<\/p>\n<pre><code>var zoomLevel = builder.Configuration[&quot;MapSettings:DefaultZoomLevel&quot;];<\/code><\/pre>\n<p>to retrieve the configured zoom level for your application (using the settings shown in listing 10.2). Note that I used a colon (:) to designate a separate section. Similarly, to retrieve the latitude key, you could use<\/p>\n<p>\u68c0\u7d22\u4e3a\u5e94\u7528\u7a0b\u5e8f\u914d\u7f6e\u7684\u7f29\u653e\u7ea7\u522b\uff08\u4f7f\u7528\u6e05\u5355 10.2 \u4e2d\u6240\u793a\u7684\u8bbe\u7f6e\uff09\u3002\u8bf7\u6ce8\u610f\uff0c\u6211\u4f7f\u7528\u5192\u53f7 \uff08\uff1a\uff09 \u6765\u6307\u5b9a\u4e00\u4e2a\u5355\u72ec\u7684\u90e8\u5206\u3002\u540c\u6837\uff0c\u8981\u68c0\u7d22\u7eac\u5ea6\u952e\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528<\/p>\n<pre><code>var lat = builder.Configuration[&quot;MapSettings:DefaultLocation:Latitude&quot;];<\/code><\/pre>\n<p>Note If the requested configuration key doesn\u2019t exist, you get a null value.<br \/>\n\u6ce8\u610f \u5982\u679c\u8bf7\u6c42\u7684\u914d\u7f6e\u952e\u4e0d\u5b58\u5728\uff0c\u60a8\u5c06\u83b7\u5f97\u4e00\u4e2anull \u503c\u3002<\/p>\n<p>You can also grab a whole section of the configuration by using the GetSection(section) method, which returns an IConfigurationSection, which also implements IConfiguration. This method grabs a chunk of the configuration and resets the namespace. Another way to get the latitude key is<\/p>\n<p>\u60a8\u8fd8\u53ef\u4ee5\u4f7f\u7528 GetSection \uff08section\uff09 \u65b9\u6cd5\u83b7\u53d6\u914d\u7f6e\u7684\u6574\u4e2a\u90e8\u5206\uff0c\u8be5\u65b9\u6cd5\u8fd4\u56de IConfigurationSection\uff0c\u8be5\u65b9\u6cd5\u8fd8\u5b9e\u73b0 IConfiguration\u3002\u6b64\u65b9\u6cd5\u83b7\u53d6\u914d\u7f6e\u5757\u5e76\u91cd\u7f6e\u547d\u540d\u7a7a\u95f4\u3002\u83b7\u53d6\u7eac\u5ea6\u952e\u7684\u53e6\u4e00\u79cd\u65b9\u6cd5\u662f<\/p>\n<pre><code>var lat = builder.Configuration\n    .GetSection(&quot;MapSettings&quot;)[&quot;DefaultLocation:Latitude&quot;];<\/code><\/pre>\n<p>Accessing setting values this way is useful in Program.cs when you\u2019re defining your application. When you\u2019re setting up your application to connect to a database, for example, you\u2019ll often load a connection string from the IConfiguration object. You\u2019ll see a concrete example in chapter 12, which looks at Entity Framework Core.<\/p>\n<p>\u4ee5\u8fd9\u79cd\u65b9\u5f0f\u8bbf\u95ee\u8bbe\u7f6e\u503c\u5728 Program.cs \u5b9a\u4e49\u5e94\u7528\u7a0b\u5e8f\u65f6\u975e\u5e38\u6709\u7528\u3002\u4f8b\u5982\uff0c\u5728\u8bbe\u7f6e\u5e94\u7528\u7a0b\u5e8f\u4ee5\u8fde\u63a5\u5230\u6570\u636e\u5e93\u65f6\uff0c\u901a\u5e38\u4f1a\u4ece IConfiguration \u5bf9\u8c61\u52a0\u8f7d\u8fde\u63a5\u5b57\u7b26\u4e32\u3002\u60a8\u5c06\u5728\u7b2c 12 \u7ae0\u4e2d\u770b\u5230\u4e00\u4e2a\u5177\u4f53\u793a\u4f8b\uff0c\u8be5\u793a\u4f8b\u4ecb\u7ecd\u4e86 Entity Framework Core\u3002<\/p>\n<p>If you need to access the configuration object in places other than Program.cs, you can use DI to inject it as a dependency into your service\u2019s constructor. But accessing configuration by using string keys this way isn\u2019t particularly convenient; you should try to use strongly typed configuration instead, as you\u2019ll see in section 10.3.<\/p>\n<p>\u5982\u679c\u60a8\u9700\u8981\u5728 Program.cs \u4ee5\u5916\u7684\u4f4d\u7f6e\u8bbf\u95ee\u914d\u7f6e\u5bf9\u8c61\uff0c\u5219\u53ef\u4ee5\u4f7f\u7528 DI \u5c06\u5176\u4f5c\u4e3a\u4f9d\u8d56\u9879\u6ce8\u5165\u5230\u670d\u52a1\u7684\u6784\u9020\u51fd\u6570\u4e2d\u3002\u4f46\u662f\u4ee5\u8fd9\u79cd\u65b9\u5f0f\u4f7f\u7528\u5b57\u7b26\u4e32\u952e\u8bbf\u95ee\u914d\u7f6e\u5e76\u4e0d\u662f\u7279\u522b\u65b9\u4fbf;\u4f60\u5e94\u8be5\u5c1d\u8bd5\u4f7f\u7528\u5f3a\u7c7b\u578b\u914d\u7f6e\uff0c\u6b63\u5982\u4f60\u5c06\u5728 Section 10.3 \u4e2d\u770b\u5230\u7684\u90a3\u6837\u3002<\/p>\n<p>So far, this process probably feels a bit too convoluted and run-of-the-mill to load settings from a JSON file, and I\u2019ll grant you that it is. Where the ASP.NET Core configuration system shines is when you have multiple providers.<\/p>\n<p>\u5230\u76ee\u524d\u4e3a\u6b62\uff0c\u4ece JSON \u6587\u4ef6\u52a0\u8f7d\u8bbe\u7f6e\uff0c\u8fd9\u4e2a\u8fc7\u7a0b\u53ef\u80fd\u611f\u89c9\u6709\u70b9\u592a\u590d\u6742\u548c\u666e\u901a\u4e86\uff0c\u6211\u627f\u8ba4\u786e\u5b9e\u5982\u6b64\u3002ASP.NET Core \u914d\u7f6e\u7cfb\u7edf\u7684\u4eae\u70b9\u662f\u5f53\u60a8\u62e5\u6709\u591a\u4e2a\u63d0\u4f9b\u5546\u65f6\u3002<\/p>\n<h3>10.2.2 Using multiple providers to override configuration values<\/h3>\n<h3>10.2.2 \u4f7f\u7528\u591a\u4e2a\u63d0\u4f9b\u7a0b\u5e8f\u8986\u76d6\u914d\u7f6e\u503c<\/h3>\n<p>You\u2019ve seen how to add a configuration provider to the ConfigurationManager and retrieve the configuration values, but so far, you\u2019ve configured only a single provider. When you add providers, it\u2019s important to consider the order in which you add them, as that defines the order in which the configuration values will be added to the underlying dictionary. Configuration values from later providers overwrite values with the same key from earlier providers.<\/p>\n<p>\u60a8\u5df2\u7ecf\u4e86\u89e3\u4e86\u5982\u4f55\u5c06\u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\u6dfb\u52a0\u5230 ConfigurationManager \u5e76\u68c0\u7d22\u914d\u7f6e\u503c\uff0c\u4f46\u5230\u76ee\u524d\u4e3a\u6b62\uff0c\u60a8\u53ea\u914d\u7f6e\u4e86\u4e00\u4e2a\u63d0\u4f9b\u7a0b\u5e8f\u3002\u6dfb\u52a0\u63d0\u4f9b\u7a0b\u5e8f\u65f6\uff0c\u8bf7\u52a1\u5fc5\u8003\u8651\u6dfb\u52a0\u5b83\u4eec\u7684\u987a\u5e8f\uff0c\u56e0\u4e3a\u8fd9\u5b9a\u4e49\u4e86\u5c06\u914d\u7f6e\u503c\u6dfb\u52a0\u5230\u5e95\u5c42\u5b57\u5178\u7684\u987a\u5e8f\u3002\u6765\u81ea\u66f4\u9ad8\u63d0\u4f9b\u7a0b\u5e8f\u7684\u914d\u7f6e\u503c\u4f1a\u4f7f\u7528\u6765\u81ea\u65e9\u671f\u63d0\u4f9b\u7a0b\u5e8f\u7684\u76f8\u540c\u952e\u8986\u76d6\u503c\u3002<\/p>\n<p><strong>Note<\/strong> This sentence bears repeating: the order in which you add configuration providers to ConfigurationManager is important. Later configuration providers can overwrite the values of earlier providers.<br \/>\n<strong>\u6ce8\u610f<\/strong> \u8fd9\u53e5\u8bdd\u503c\u5f97\u91cd\u590d\uff1a\u5c06\u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\u6dfb\u52a0\u5230 ConfigurationManager \u7684\u987a\u5e8f\u5f88\u91cd\u8981\u3002\u66f4\u9ad8\u7248\u672c\u7684\u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\u53ef\u4ee5\u8986\u76d6\u65e9\u671f\u63d0\u4f9b\u7a0b\u5e8f\u7684\u503c\u3002<\/p>\n<p>Think of the configuration providers as adding layers of configuration values to a stack, where each layer may overlap some or all of the layers below, as shown in figure 10.3. If the new provider contains any keys that are already known to the ConfigurationManager, they overwrite the old values to create the final set of configuration values stored in IConfiguration.<\/p>\n<p>\u5c06\u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\u89c6\u4e3a\u5411\u5806\u6808\u4e2d\u6dfb\u52a0\u914d\u7f6e\u503c\u5c42\uff0c\u5176\u4e2d\u6bcf\u4e2a\u5c42\u53ef\u80fd\u4e0e\u4e0b\u9762\u7684\u90e8\u5206\u6216\u5168\u90e8\u5c42\u91cd\u53e0\uff0c\u5982\u56fe 10.3 \u6240\u793a\u3002\u5982\u679c\u65b0\u63d0\u4f9b\u7a0b\u5e8f\u5305\u542b\u4efb\u4f55ConfigurationManager \u4e2d\uff0c\u5b83\u4eec\u4f1a\u8986\u76d6\u65e7\u503c\u4ee5\u521b\u5efa\u5b58\u50a8\u5728 IConfiguration \u4e2d\u7684\u6700\u7ec8\u914d\u7f6e\u503c\u96c6\u3002<\/p>\n<p><strong>Tip<\/strong> Instead of thinking in layers, you can think of the ConfigurationManager as a simple dictionary. When you add a provider, you\u2019re setting some key-value pairs. When you add a second provider, the provider can add new keys or overwrite the value of existing keys.<br \/>\n<strong>\u63d0\u793a<\/strong> \u60a8\u53ef\u4ee5\u5c06 ConfigurationManager \u89c6\u4e3a\u4e00\u4e2a\u7b80\u5355\u7684\u5b57\u5178\uff0c\u800c\u4e0d\u662f\u5206\u5c42\u601d\u8003\u3002\u6dfb\u52a0\u63d0\u4f9b\u7a0b\u5e8f\u65f6\uff0c\u60a8\u5c06\u8bbe\u7f6e\u4e00\u4e9b\u952e\u503c\u5bf9\u3002\u5f53\u60a8\u6dfb\u52a0\u7b2c\u4e8c\u4e2a\u63d0\u4f9b\u7a0b\u5e8f\u65f6\uff0c\u8be5\u63d0\u4f9b\u7a0b\u5e8f\u53ef\u4ee5\u6dfb\u52a0\u65b0\u952e\u6216\u8986\u76d6\u73b0\u6709\u952e\u7684\u503c\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1003.png\" alt=\"alt text \" \/><\/p>\n<p>Figure 10.3 Each configuration provider adds a layer of values to ConfigurationBuilder. Calling Build() collapses that configuration. Later providers overwrite configuration values with the same keys from earlier providers.<br \/>\n\u56fe 10.3 \u6bcf\u4e2a\u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\u90fd\u4f1a\u5411 ConfigurationBuilder \u6dfb\u52a0\u4e00\u5c42\u503c\u3002\u8c03\u7528 Build\uff08\uff09 \u4f1a\u6298\u53e0\u8be5\u914d\u7f6e\u3002\u540e\u9762\u7684 provider \u4f1a\u7528\u65e9\u671f providers\u7684\u76f8\u540c\u952e\u8986\u76d6\u914d\u7f6e\u503c\u3002<\/p>\n<p>Update your code to load configuration from three different configuration providers\u2014two JSON providers and an environment variable provider\u2014by adding them to ConfigurationManager as shown in the following listing.<\/p>\n<p>\u66f4\u65b0\u60a8\u7684\u4ee3\u7801\u4ee5\u4ece\u4e09\u4e2a\u4e0d\u540c\u7684\u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\uff08\u4e24\u4e2a JSON \u63d0\u4f9b\u7a0b\u5e8f\u548c\u4e00\u4e2a\u73af\u5883\uff09\u52a0\u8f7d\u914d\u7f6e\u53d8\u91cf\u63d0\u4f9b\u7a0b\u5e8f - \u901a\u8fc7\u5c06\u5b83\u4eec\u6dfb\u52a0\u5230 ConfigurationManager\u5982\u4e0b\u9762\u7684\u6e05\u5355\u6240\u793a\u3002<\/p>\n<p>Listing 10.4 Loading from multiple providers in Program.cs<br \/>\n\u6e05\u5355 10.4 \u5728 Program.cs \u4e2d\u4ece\u591a\u4e2a\u63d0\u4f9b\u5546\u52a0\u8f7d<\/p>\n<pre><code>WebApplicationBuilder builder = WebApplication.CreateBuilder(args);\n\nbuilder.Configuration.Sources.Clear();\nbuilder.Configuration \u2776\n    .AddJsonFile(&quot;sharedSettings.json&quot;, optional: true); \u2776\nbuilder.Configuration.AddJsonFile(&quot;appsettings.json&quot;, optional: true);\nbuilder.Configuration.AddEnvironmentVariables(); \u2777\n\nWebApplication app = builder.Build();\n\napp.MapGet(&quot;\/&quot;, () =&gt; app.Configuration.AsEnumerable());\n\napp.Run();<\/code><\/pre>\n<p>\u2776 Loads configuration from a different JSON configuration file before the<br \/>\nappsettings.json file<br \/>\n\u5728 appsettings.json \u6587\u4ef6\u4e4b\u524d\u4ece\u4e0d\u540c\u7684 JSON \u914d\u7f6e\u6587\u4ef6\u52a0\u8f7d\u914d\u7f6e<\/p>\n<p>\u2777 Adds the machine\u2019s environment variables as a configuration provider<br \/>\n\u5c06\u8ba1\u7b97\u673a\u7684\u73af\u5883\u53d8\u91cf\u6dfb\u52a0\u4e3a\u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f<\/p>\n<p>This layered design can be useful for several things. Fundamentally, it allows you to aggregate configuration values from multiple sources into a single, cohesive object. To cement this design in place, consider the configuration values in figure 10.4.<br \/>\n\u8fd9\u79cd\u5206\u5c42\u8bbe\u8ba1\u53ef\u7528\u4e8e\u591a\u79cd\u7528\u9014\u3002\u4ece\u6839\u672c\u4e0a\u8bf4\uff0c\u5b83\u5141\u8bb8\u60a8\u5c06\u6765\u81ea\u591a\u4e2a\u6e90\u7684\u914d\u7f6e\u503c\u805a\u5408\u5230\u4e00\u4e2a\u5185\u805a\u5bf9\u8c61\u4e2d\u3002\u4e3a\u4e86\u5de9\u56fa\u6b64\u8bbe\u8ba1\uff0c\u8bf7\u8003\u8651\u56fe 10.4 \u4e2d\u7684\u914d\u7f6e\u503c\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1004.png\" alt=\"alt text \" \/><\/p>\n<p>Figure 10.4 The final IConfiguration includes the values from each of the providers. Both appsettings.json and the environment variables include the MyAppConnString key. As the environment variables are added later, that configuration value is used.<\/p>\n<p>\u56fe 10.4 \u6700\u7ec8\u7684 IConfiguration \u5305\u62ec\u6765\u81ea\u6bcf\u4e2a\u63d0\u4f9b\u7a0b\u5e8f\u7684\u503c\u3002appsettings.json \u548c\u73af\u5883\u53d8\u91cf\u90fd\u5305\u542b MyAppConnString \u952e\u3002\u7531\u4e8e\u7a0d\u540e\u6dfb\u52a0\u73af\u5883\u53d8\u91cf\uff0c\u56e0\u6b64\u5c06\u4f7f\u7528\u8be5\u914d\u7f6e\u503c\u3002<\/p>\n<p>Most of the settings in each provider are unique and are added to the final IConfiguration. But the &quot;MyAppConnString&quot; key appears both in appsettings.json and as an environment variable. Because the environment variable provider is added after the JSON providers, the environment variable configuration value is used in IConfiguration.<\/p>\n<p>\u6bcf\u4e2a\u63d0\u4f9b\u7a0b\u5e8f\u4e2d\u7684\u5927\u591a\u6570\u8bbe\u7f6e\u90fd\u662f\u552f\u4e00\u7684\uff0c\u5e76\u6dfb\u52a0\u5230\u6700\u7ec8\u7684 IConfiguration \u4e2d\u3002\u4f46\u662f \u201cMyAppConnString\u201d key \u65e2\u663e\u793a\u5728 appsettings.json \u4e2d\uff0c\u4e5f\u663e\u793a\u4e3a\u73af\u5883\u53d8\u91cf\u3002\u7531\u4e8e\u73af\u5883\u53d8\u91cf\u63d0\u4f9b\u7a0b\u5e8f\u662f\u5728 JSON \u63d0\u4f9b\u7a0b\u5e8f\u4e4b\u540e\u6dfb\u52a0\u7684\uff0c\u56e0\u6b64\u5728 IConfiguration \u4e2d\u4f7f\u7528\u73af\u5883\u53d8\u91cf\u914d\u7f6e\u503c\u3002<\/p>\n<p>The ability to collate configuration from multiple providers is handy on its own, but this design is especially useful for handling sensitive configuration values, such as connection strings and passwords. Section 10.2.3 shows how to deal with this problem, both locally on your development machine and on production servers.<\/p>\n<p>\u6574\u7406\u6765\u81ea\u591a\u4e2a\u63d0\u4f9b\u5546\u7684\u914d\u7f6e\u7684\u80fd\u529b\u672c\u8eab\u5f88\u65b9\u4fbf\uff0c\u4f46\u8fd9\u79cd\u8bbe\u8ba1\u5bf9\u4e8e\u5904\u7406\u654f\u611f\u7684\u914d\u7f6e\u503c\uff08\u4f8b\u5982\u8fde\u63a5\u5b57\u7b26\u4e32\u548c\u5bc6\u7801\uff09\u7279\u522b\u6709\u7528\u3002Section 10.2.3 \u5c55\u793a\u4e86\u5982\u4f55\u5728\u5f00\u53d1\u8ba1\u7b97\u673a\u548c \u751f\u4ea7\u670d\u52a1\u5668\u4e0a\u672c\u5730\u5904\u7406\u6b64\u95ee\u9898\u3002<\/p>\n<h3>10.2.3 Storing configuration secrets safely<\/h3>\n<h3>10.2.3 \u5b89\u5168\u5730\u5b58\u50a8\u914d\u7f6e\u5bc6\u94a5<\/h3>\n<p>As soon as you build a nontrivial app, you\u2019ll find that you need to store some sort of sensitive data as a setting somewhere. This data could be a password, a connection string, or an API key for a remote service, for example.<\/p>\n<p>\u4e00\u65e6\u4f60\u6784\u5efa\u4e86\u4e00\u4e2a\u91cd\u8981\u7684\u5e94\u7528\u7a0b\u5e8f\uff0c\u4f60\u5c31\u4f1a\u53d1\u73b0\u4f60\u9700\u8981\u5728\u67d0\u4e2a\u5730\u65b9\u5b58\u50a8\u67d0\u79cd\u654f\u611f\u6570\u636e\u4f5c\u4e3a\u8bbe\u7f6e\u3002\u4f8b\u5982\uff0c\u6b64\u6570\u636e\u53ef\u4ee5\u662f\u5bc6\u7801\u3001\u8fde\u63a5\u5b57\u7b26\u4e32\u6216\u8fdc\u7a0b\u670d\u52a1\u7684 API \u5bc6\u94a5\u3002<\/p>\n<p>Storing these values in appsettings.json is generally a bad idea, as you should never commit secrets to source control; the number of secret API keys people have committed to GitHub is scary! Instead, it\u2019s much better to store these values outside your project folder, where they won\u2019t get committed accidentally.<\/p>\n<p>\u5c06\u8fd9\u4e9b\u503c\u5b58\u50a8\u5728 appsettings.json \u4e2d\u901a\u5e38\u662f\u4e00\u4e2a\u574f\u4e3b\u610f\uff0c\u56e0\u4e3a\u60a8\u6c38\u8fdc\u4e0d\u5e94\u8be5\u5c06 secret \u63d0\u4ea4\u5230\u6e90\u4ee3\u7801\u7ba1\u7406;\u4eba\u4eec\u63d0\u4ea4\u5230 GitHub \u7684\u79d8\u5bc6 API \u5bc6\u94a5\u7684\u6570\u91cf\u662f\u53ef\u6015\u7684\uff01\u76f8\u53cd\uff0c\u6700\u597d\u5c06\u8fd9\u4e9b\u503c\u5b58\u50a8\u5728\u9879\u76ee\u6587\u4ef6\u5939\u4e4b\u5916\uff0c\u8fd9\u6837\u5b83\u4eec\u5c31\u4e0d\u4f1a\u610f\u5916\u63d0\u4ea4\u3002<\/p>\n<p>You can do this in a few ways, but the easiest and most common approaches are to use environment variables for secrets on your production server and User Secrets locally. Neither approach is truly secure, in that neither stores values in an encrypted format. If your machine is compromised, attackers will be able to read the stored values because they\u2019re stored in plain text. These approaches are intended mainly to help you avoid committing secrets to source control.<\/p>\n<p>\u60a8\u53ef\u4ee5\u901a\u8fc7\u591a\u79cd\u65b9\u5f0f\u6267\u884c\u6b64\u4f5c\uff0c\u4f46\u6700\u7b80\u5355\u548c\u6700\u5e38\u89c1\u7684\u65b9\u6cd5\u662f\u5c06\u73af\u5883\u53d8\u91cf\u7528\u4e8e\u751f\u4ea7\u670d\u52a1\u5668\u4e0a\u7684\u5bc6\u94a5\u548c\u672c\u5730\u7684 User Secrets\u3002\u8fd9\u4e24\u79cd\u65b9\u6cd5\u90fd\u4e0d\u662f\u771f\u6b63\u5b89\u5168\u7684\uff0c\u56e0\u4e3a\u4e24\u8005\u90fd\u4e0d\u4f1a\u4ee5\u52a0\u5bc6\u683c\u5f0f\u5b58\u50a8\u503c\u3002\u5982\u679c\u60a8\u7684\u8ba1\u7b97\u673a\u906d\u5230\u5165\u4fb5\uff0c\u653b\u51fb\u8005\u5c06\u80fd\u591f\u8bfb\u53d6\u5b58\u50a8\u7684\u503c\uff0c\u56e0\u4e3a\u5b83\u4eec\u4ee5\u7eaf\u6587\u672c\u5f62\u5f0f\u5b58\u50a8\u3002\u8fd9\u4e9b\u65b9\u6cd5\u4e3b\u8981\u662f\u4e3a\u4e86\u5e2e\u52a9\u60a8\u907f\u514d\u5c06\u5bc6\u94a5\u63d0\u4ea4\u5230\u6e90\u4ee3\u7801\u7ba1\u7406\u3002<\/p>\n<p><strong>Tip<\/strong> Azure Key Vault is a secure alternative, in that it stores the values encrypted in Azure, but you still need to use User Secrets and environment variables to store the Azure Key Vault connection details. See the documentation for instructions on using Azure Key Vault in your apps <a href=\"http:\/\/mng.bz\/BR7v\">http:\/\/mng.bz\/BR7v<\/a>. Another popular option is Vault by Hashicorp (www.vaultproject.io), which can be run on-premises or in the cloud.<br \/>\n<strong>\u63d0\u793a<\/strong> Azure Key Vault \u662f\u4e00\u79cd\u5b89\u5168\u7684\u66ff\u4ee3\u65b9\u6848\uff0c\u56e0\u4e3a\u5b83\u5c06\u52a0\u5bc6\u7684\u503c\u5b58\u50a8\u5728 Azure \u4e2d\uff0c\u4f46\u60a8\u4ecd\u7136\u9700\u8981\u4f7f\u7528\u7528\u6237\u5bc6\u94a5\u548c\u73af\u5883\u53d8\u91cf\u6765\u5b58\u50a8 Azure Key Vault \u8fde\u63a5\u8be6\u7ec6\u4fe1\u606f\u3002\u6709\u5173\u5728\u5e94\u7528 <a href=\"http:\/\/mng.bz\/BR7v\">http:\/\/mng.bz\/BR7v<\/a> \u4e2d\u4f7f\u7528 Azure Key Vault \u7684\u8bf4\u660e\uff0c\u8bf7\u53c2\u9605\u6587\u6863\u3002\u53e6\u4e00\u4e2a\u6d41\u884c\u7684\u9009\u9879\u662f Hashicorp \u7684 Vault \uff08www.vaultproject.io\uff09\uff0c\u5b83\u53ef\u4ee5\u5728\u672c\u5730\u6216\u4e91\u4e2d\u8fd0\u884c\u3002<\/p>\n<p>Whichever approach you use to store your application secrets, make sure that you aren\u2019t storing them in source control. Even private repositories may not stay private forever, so it\u2019s best to err on the side of caution.<\/p>\n<p>\u65e0\u8bba\u60a8\u4f7f\u7528\u54ea\u79cd\u65b9\u6cd5\u6765\u5b58\u50a8\u5e94\u7528\u7a0b\u5e8f\u5bc6\u94a5\uff0c\u8bf7\u786e\u4fdd\u60a8\u6ca1\u6709\u5c06\u5b83\u4eec\u5b58\u50a8\u5728\u6e90\u4ee3\u7801\u7ba1\u7406\u4e2d\u3002\u5373\u4f7f\u662f\u79c1\u6709\u5b58\u50a8\u5e93\u4e5f\u53ef\u80fd\u4e0d\u4f1a\u6c38\u8fdc\u4fdd\u6301\u79c1\u6709\uff0c\u56e0\u6b64\u6700\u597d\u8c28\u614e\u884c\u4e8b\u3002<\/p>\n<h2>Storing secrets in environment variables in production<\/h2>\n<p>\u5728\u751f\u4ea7\u73af\u5883\u4e2d\u7684\u73af\u5883\u53d8\u91cf\u4e2d\u6267\u884c SECRET<br \/>\nYou can add the environment variable configuration provider by using the AddEnvironmentVariables extension method, as you saw in listing 10.4. This method adds all the environment variables on your machine as key-value pairs to ConfigurationManager.<br \/>\n\u60a8\u53ef\u4ee5\u4f7f\u7528 AddEnvironmentVariables \u6269\u5c55\u65b9\u6cd5\u6dfb\u52a0\u73af\u5883\u53d8\u91cf\u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u5982\u6e05\u5355 10.4 \u6240\u793a\u3002\u6b64\u65b9\u6cd5\u5c06\u8ba1\u7b97\u673a\u4e0a\u7684\u6240\u6709\u73af\u5883\u53d8\u91cf\u4f5c\u4e3a\u952e\u503c\u5bf9\u6dfb\u52a0\u5230 ConfigurationManager\u3002<\/p>\n<p><strong>Note<\/strong> The WebApplicationBuilder adds the environment variable provider to the ConfigurationManager by default.<br \/>\n<strong>\u6ce8\u610f<\/strong> \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cWebApplicationBuilder \u5c06\u73af\u5883\u53d8\u91cf\u63d0\u4f9b\u7a0b\u5e8f\u6dfb\u52a0\u5230 ConfigurationManager\u3002<\/p>\n<p>You can create the same hierarchical sections in environment variables that you typically see in JSON files by using a colon (:) or a double underscore (<strong>) to demarcate a section, as in MapSettings:MaxNumberOfPoints or MapSettings<\/strong>MaxNumberOfPoints.<br \/>\n\u60a8\u53ef\u4ee5\u4f7f\u7528\u5192\u53f7 \uff08\uff1a\uff09 \u6216\u53cc\u4e0b\u5212\u7ebf \uff08 \uff09 \u6765\u5212\u5206\u90e8\u5206\uff0c\u4ece\u800c\u5728\u73af\u5883\u53d8\u91cf\u4e2d\u521b\u5efa\u901a\u5e38\u5728 JSON \u6587\u4ef6\u4e2d\u770b\u5230\u7684\u76f8\u540c\u5206\u5c42\u90e8\u5206\uff0c\u5982\u4e0b\u6240\u793aMapSettings\uff1aMaxNumberOfPoints \u6216MapSettings MaxNumberOfPoints \u7684 MapSettings MaxNumberOfPoints \u7684 Points\u3002<\/p>\n<p><strong>Tip<\/strong> Some environments, such as Linux, don\u2019t allow the colon in environment variables. You must use the double-underscore approach in these environments instead. A double underscore in an environment variable is converted to a colon when it\u2019s imported into the IConfiguration object. You should always use the colon when retrieving values from an IConfiguration in your app.<br \/>\n<strong>\u63d0\u793a<\/strong> \u67d0\u4e9b\u73af\u5883\uff08\u5982 Linux\uff09\u4e0d\u5141\u8bb8\u5728\u73af\u5883\u53d8\u91cf\u4e2d\u4f7f\u7528\u5192\u53f7\u3002\u60a8\u5fc5\u987b\u5728\u8fd9\u4e9b\u73af\u5883\u4e2d\u6539\u7528\u53cc\u4e0b\u5212\u7ebf\u65b9\u6cd5\u3002\u73af\u5883\u53d8\u91cf\u4e2d\u7684\u53cc\u4e0b\u5212\u7ebf\u5728\u5bfc\u5165 IConfiguration \u5bf9\u8c61\u65f6\u5c06\u8f6c\u6362\u4e3a\u5192\u53f7\u3002\u4ece\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684 IConfiguration \u68c0\u7d22\u503c\u65f6\uff0c\u5e94\u59cb\u7ec8\u4f7f\u7528\u5192\u53f7\u3002<\/p>\n<p>The environment-variable approach is particularly useful when you\u2019re publishing your app to a self-contained environment, such as a dedicated server, Azure, or a Docker container. You can set environment variables on your production machine or on your Docker container, and the provider reads them at runtime, overriding the defaults specified in your appsettings.json files.<\/p>\n<p>\u5c06\u5e94\u7528\u53d1\u5e03\u5230\u72ec\u7acb\u73af\u5883\uff08\u5982\u4e13\u7528\u670d\u52a1\u5668\u3001Azure \u6216 Docker \u5bb9\u5668\uff09\u65f6\uff0c\u73af\u5883\u53d8\u91cf\u65b9\u6cd5\u7279\u522b\u6709\u7528\u3002\u60a8\u53ef\u4ee5\u5728\u751f\u4ea7\u8ba1\u7b97\u673a\u6216 Docker \u5bb9\u5668\u4e0a\u8bbe\u7f6e\u73af\u5883\u53d8\u91cf\uff0c\u63d0\u4f9b\u7a0b\u5e8f\u4f1a\u5728\u8fd0\u884c\u65f6\u8bfb\u53d6\u8fd9\u4e9b\u53d8\u91cf\uff0c\u4ece\u800c\u8986\u76d6 appsettings.json \u6587\u4ef6\u4e2d\u6307\u5b9a\u7684\u9ed8\u8ba4\u503c\u3002<\/p>\n<p><strong>Tip<\/strong> For instructions on setting environment variables for your operating system, see Microsoft\u2019s \u201cUse multiple environments in ASP.NET Core\u201d documentation at <a href=\"http:\/\/mng.bz\/d4OD\">http:\/\/mng.bz\/d4OD<\/a>.<br \/>\n<strong>\u63d0\u793a<\/strong> \u6709\u5173\u4e3a\u4f5c\u7cfb\u7edf\u8bbe\u7f6e\u73af\u5883\u53d8\u91cf\u7684\u8bf4\u660e\uff0c\u8bf7\u53c2\u9605 <a href=\"http:\/\/mng.bz\/d4OD\">http:\/\/mng.bz\/d4OD<\/a> Microsoft\u7684\u201c\u5728 ASP.NET Core \u4e2d\u4f7f\u7528\u591a\u4e2a\u73af\u5883\u201d\u6587\u6863\u3002<\/p>\n<p>For a development machine, environment variables are less useful, as all your apps would use the same values. If you set the ConnectionStrings__ DefaultConnection environment variable, for example, that variable would be added to every app you run locally, which sounds like more of a hassle than a benefit!<\/p>\n<p>\u5bf9\u4e8e\u5f00\u53d1\u8ba1\u7b97\u673a\uff0c\u73af\u5883\u53d8\u91cf\u4e0d\u592a\u6709\u7528\uff0c\u56e0\u4e3a\u60a8\u7684\u6240\u6709\u5e94\u7528\u7a0b\u5e8f\u90fd\u5c06\u4f7f\u7528\u76f8\u540c\u7684\u503c\u3002\u4f8b\u5982\uff0c\u5982\u679c\u60a8\u8bbe\u7f6e ConnectionStrings DefaultConnection \u73af\u5883\u53d8\u91cf\uff0c\u5219\u8be5\u53d8\u91cf\u5c06\u88ab\u6dfb\u52a0\u5230\u60a8\u5728\u672c\u5730\u8fd0\u884c\u7684\u6bcf\u4e2a\u5e94\u7528\u7a0b\u5e8f\u4e2d\uff0c\u8fd9\u542c\u8d77\u6765\u66f4\u9ebb\u70e6\u800c\u4e0d\u662f\u597d\u5904\uff01<\/p>\n<p>Tip To avoid collisions, you can add only environment variables that have a given prefix, such as AddEnvironmentVariables(&quot;SomePrefix&quot;). The prefix is removed from the key before it\u2019s added to the ConfigurationManager, so the variable SomePrefix_MyValue is added to configuration as MyValue.<br \/>\n\u63d0\u793a \u4e3a\u907f\u514d\u51b2\u7a81\uff0c\u60a8\u53ef\u4ee5\u4ec5\u6dfb\u52a0\u5177\u6709\u7ed9\u5b9a\u524d\u7f00\u7684\u73af\u5883\u53d8\u91cf\uff0c\u4f8b\u5982 AddEnvironmentVariables\uff08\u201cSomePrefix\u201d\uff09\u3002\u5728\u5c06\u524d\u7f00\u6dfb\u52a0\u5230ConfigurationManager \u4e2d\uff0c\u56e0\u6b64\u53d8\u91cfSomePrefix_MyValue \u5c06\u4f5c\u4e3a MyValue \u6dfb\u52a0\u5230\u914d\u7f6e\u4e2d\u3002<\/p>\n<p>For development scenarios, you can use the User Secrets Manager, which effectively adds per-app environment variables, so you can have different settings for each app but store them in a different location from the app itself.<\/p>\n<p>\u5bf9\u4e8e\u5f00\u53d1\u573a\u666f\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528 User Secrets Manager\uff0c\u5b83\u53ef\u4ee5\u6709\u6548\u5730\u6dfb\u52a0\u6bcf\u4e2a\u5e94\u7528\u7a0b\u5e8f\u7684\u73af\u5883\u53d8\u91cf\uff0c\u56e0\u6b64\u60a8\u53ef\u4ee5\u4e3a\u6bcf\u4e2a\u5e94\u7528\u7a0b\u5e8f\u8bbe\u7f6e\u4e0d\u540c\u7684\u8bbe\u7f6e\uff0c\u4f46\u5c06\u5b83\u4eec\u5b58\u50a8\u5728\u4e0e\u5e94\u7528\u7a0b\u5e8f\u672c\u8eab\u4e0d\u540c\u7684\u4f4d\u7f6e\u3002<\/p>\n<h2>Storing secrets with the User Secrets Manager in development<\/h2>\n<p>STORING SECRETS \u4e0e US\u7cfb\u5217 S ECRETS MANAGER \u5728\u5f00\u53d1\u4e2d<br \/>\nThe idea behind User Secrets is to simplify storing per-app secrets outside your app\u2019s project tree. This approach is similar to environment variables, but you use a unique key for each app to keep the secrets segregated.<br \/>\nUser Secrets \u80cc\u540e\u7684\u7406\u5ff5\u662f\u7b80\u5316\u5728\u5e94\u7528\u7a0b\u5e8f\u9879\u76ee\u6811\u4e4b\u5916\u5b58\u50a8\u6bcf\u4e2a\u5e94\u7528\u7a0b\u5e8f Secret \u7684\u8fc7\u7a0b\u3002\u6b64\u65b9\u6cd5\u7c7b\u4f3c\u4e8e\u73af\u5883\u53d8\u91cf\uff0c\u4f46\u60a8\u53ef\u4ee5\u4e3a\u6bcf\u4e2a\u5e94\u7528\u7a0b\u5e8f\u4f7f\u7528\u552f\u4e00\u7684\u952e\u6765\u4fdd\u6301\u5bc6\u94a5\u9694\u79bb\u3002<\/p>\n<p>Warning The secrets aren\u2019t encrypted, so don\u2019t consider them to be secure. Nevertheless, it\u2019s an improvement on storing them in your project folder.<br \/>\n\u8b66\u544a \u5bc6\u94a5\u672a\u52a0\u5bc6\uff0c\u56e0\u6b64\u4e0d\u8981\u8ba4\u4e3a\u5b83\u4eec\u662f\u5b89\u5168\u7684\u3002\u4e0d\u8fc7\uff0c\u4e0e\u5c06\u5b83\u4eec\u5b58\u50a8\u5728\u9879\u76ee\u6587\u4ef6\u5939\u4e2d\u76f8\u6bd4\uff0c\u8fd9\u662f\u4e00\u4e2a\u6539\u8fdb\u3002<\/p>\n<p>Setting up User Secrets takes a bit more effort than using environment variables, as you need to configure a tool to read and write them, add the User Secrets configuration provider, and define a unique key for your application. To add User Secrets to your app, follow these steps:<\/p>\n<p>\u8bbe\u7f6e\u7528\u6237\u5bc6\u94a5\u6bd4\u4f7f\u7528\u73af\u5883\u53d8\u91cf\u9700\u8981\u66f4\u591a\u7684\u5de5\u4f5c\uff0c\u56e0\u4e3a\u60a8\u9700\u8981\u914d\u7f6e\u4e00\u4e2a\u5de5\u5177\u6765\u8bfb\u53d6\u548c\u5199\u5165\u5b83\u4eec\uff0c\u6dfb\u52a0\u7528\u6237\u5bc6\u94a5\u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u5e76\u4e3a\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u5b9a\u4e49\u552f\u4e00\u5bc6\u94a5\u3002\u8981\u5c06 User Secrets \u6dfb\u52a0\u5230\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\uff0c\u8bf7\u6267\u884c\u4ee5\u4e0b\u6b65\u9aa4\uff1a<\/p>\n<ol>\n<li>\n<p>WebApplicationBuilder adds the User Secrets provider by default. The .NET SDK includes a global tool for working with secrets from the command line.<br \/>\n\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cWebApplicationBuilder \u4f1a\u6dfb\u52a0 User Secrets \u63d0\u4f9b\u7a0b\u5e8f\u3002.NET SDK \u5305\u62ec\u4e00\u4e2a\u5168\u5c40\u5de5\u5177\uff0c\u7528\u4e8e\u4ece\u547d\u4ee4\u884c\u5904\u7406\u673a\u5bc6\u3002<\/p>\n<\/li>\n<li>\n<p>If you\u2019re using Visual Studio, right-click your project and choose Manage User Secrets from the contextual menu. This command opens an editor for a secrets.json file in which you can store your key-value pairs as though it were an appsettings.json file, as shown in figure 10.5.<br \/>\n\u5982\u679c\u60a8\u4f7f\u7528\u7684\u662f Visual Studio\uff0c\u8bf7\u53f3\u952e\u5355\u51fb\u60a8\u7684\u9879\u76ee\uff0c\u7136\u540e\u4ece\u4e0a\u4e0b\u6587\u83dc\u5355\u4e2d\u9009\u62e9 Manage User Secrets \uff08\u7ba1\u7406\u7528\u6237\u5bc6\u94a5\uff09\u3002\u6b64\u547d\u4ee4\u5c06\u6253\u5f00\u4e00\u4e2a secrets.json \u6587\u4ef6\u7684\u7f16\u8f91\u5668\uff0c\u60a8\u53ef\u4ee5\u5728\u5176\u4e2d\u5b58\u50a8\u952e\u503c\u5bf9\uff0c\u5c31\u50cf\u5b83\u662f\u4e00\u4e2a appsettings.json \u6587\u4ef6\u4e00\u6837\uff0c\u5982\u56fe 10.5 \u6240\u793a\u3002<\/p>\n<\/li>\n<\/ol>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1005.png\" alt=\"alt text \" \/><br \/>\nFigure 10.5 Choose Manage User Secrets to open an editor for the User Secrets app. You can use this file to store secrets when developing your app locally. These secrets are stored outside your project folder, so they won\u2019t be committed to source control accidentally.<br \/>\n\u56fe 10.5 \u9009\u62e9 Manage User Secrets\uff08\u7ba1\u7406\u7528\u6237\u5bc6\u94a5\uff09\u4ee5\u6253\u5f00 User Secrets \u5e94\u7528\u7a0b\u5e8f\u7684\u7f16\u8f91\u5668\u3002\u5728\u672c\u5730\u5f00\u53d1\u5e94\u7528\u7a0b\u5e8f\u65f6\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528\u6b64\u6587\u4ef6\u6765\u5b58\u50a8\u5bc6\u94a5\u3002\u8fd9\u4e9b\u5bc6\u94a5\u5b58\u50a8\u5728\u60a8\u7684\u9879\u76ee\u6587\u4ef6\u5939\u4e4b\u5916\uff0c\u56e0\u6b64\u5b83\u4eec\u4e0d\u4f1a\u610f\u5916\u63d0\u4ea4\u5230\u6e90\u4ee3\u7801\u7ba1\u7406\u3002<\/p>\n<ol start=\"3\">\n<li>Add a unique identifier to your .csproj file. Visual Studio does this automatically when you choose Manage User Secrets, but if you\u2019re using the command line, you\u2019ll need to add it yourself. Typically, you\u2019d use a unique ID, such as a globally unique identifier (GUID):<br \/>\n\u5411 .csproj \u6587\u4ef6\u6dfb\u52a0\u552f\u4e00\u6807\u8bc6\u7b26\u3002\u5f53\u60a8\u9009\u62e9 Manage User Secrets \uff08\u7ba1\u7406\u7528\u6237\u5bc6\u7801\uff09 \u65f6\uff0cVisual Studio \u4f1a\u81ea\u52a8\u6267\u884c\u6b64\u4f5c\uff0c\u4f46\u5982\u679c\u60a8\u4f7f\u7528\u7684\u662f\u547d\u4ee4\u884c\uff0c\u5219\u9700\u8981\u81ea\u5df1\u6dfb\u52a0\u5b83\u3002\u901a\u5e38\uff0c\u60a8\u4f1a\u4f7f\u7528\u552f\u4e00 ID\uff0c\u4f8b\u5982\u5168\u5c40\u552f\u4e00\u6807\u8bc6\u7b26 \uff08GUID\uff09\uff1a<\/p>\n<pre><code>&lt;PropertyGroup&gt;\n&lt;UserSecretsId&gt;96eb2a39-1ef9-4d8e-8b20-8e8bd14038aa&lt;\/UserSecretsId&gt;\n&lt;\/PropertyGroup&gt;<\/code><\/pre>\n<\/li>\n<\/ol>\n<p>You can also generate the UserSecretsId property with a random value using the .NET command-line interface (CLI) by running the following command from your project folder:<br \/>\n\u60a8\u8fd8\u53ef\u4ee5\u4f7f\u7528 .NET \u547d\u4ee4\u884c\u754c\u9762 \uff08CLI\uff09 \u751f\u6210\u5177\u6709\u968f\u673a\u503c\u7684 UserSecretsId \u5c5e\u6027\uff0c\u65b9\u6cd5\u662f\u4ece\u9879\u76ee\u6587\u4ef6\u5939\u8fd0\u884c\u4ee5\u4e0b\u547d\u4ee4\uff1a<\/p>\n<pre><code>dotnet user-secrets init<\/code><\/pre>\n<ol start=\"4\">\n<li>Add User Secrets by using the command line<br \/>\n\u4f7f\u7528\u547d\u4ee4\u884c\u6dfb\u52a0\u7528\u6237\u5bc6\u94a5<\/p>\n<pre><code>dotnet user-secrets set &quot;MapSettings:GoogleMapsApiKey&quot; F5RJT9GFHKR7<\/code><\/pre>\n<\/li>\n<\/ol>\n<p>or edit the secret.json file directly by using your favorite editor. The exact location of this file depends on your operating system and may vary. Check the documentation for details at <a href=\"http:\/\/mng.bz\/ryAg\">http:\/\/mng.bz\/ryAg<\/a>.<br \/>\n\u6216\u8005\u4f7f\u7528\u60a8\u6700\u559c\u6b22\u7684\u7f16\u8f91\u5668\u76f4\u63a5\u7f16\u8f91 secret.json \u6587\u4ef6\u3002\u6b64\u6587\u4ef6\u7684\u786e\u5207\u4f4d\u7f6e\u53d6\u51b3\u4e8e\u60a8\u7684\u4f5c\u7cfb\u7edf\uff0c\u5e76\u4e14\u53ef\u80fd\u4f1a\u6709\u6240\u4e0d\u540c\u3002\u6709\u5173\u8be6\u7ec6\u4fe1\u606f\uff0c\u8bf7\u67e5\u770b <a href=\"http:\/\/mng.bz\/ryAg\">http:\/\/mng.bz\/ryAg<\/a> \u4e2d\u7684\u6587\u6863\u3002<\/p>\n<p><strong>Note<\/strong> The Secret Manager tool is included in the .NET CLI, but you can also use the CLI to install additional .NET tools. You can find more about .NET tools in general in Microsoft\u2019s \u201cHow to manage .NET tools\u201d documentation: <a href=\"http:\/\/mng.bz\/VdmX\">http:\/\/mng.bz\/VdmX<\/a>.<br \/>\n<strong>\u6ce8\u610f<\/strong> Secret Manager \u5de5\u5177\u5305\u542b\u5728 .NET CLI \u4e2d\uff0c\u4f46\u60a8\u4e5f\u53ef\u4ee5\u4f7f\u7528 CLI \u5b89\u88c5\u5176\u4ed6 .NET \u5de5\u5177\u3002\u60a8\u53ef\u4ee5\u5728 Microsoft \u7684\u201c\u5982\u4f55\u7ba1\u7406 .NET \u5de5\u5177\u201d\u6587\u6863\u4e2d\u627e\u5230\u6709\u5173 .NET \u5de5\u5177\u7684\u66f4\u591a\u4fe1\u606f\uff1a<a href=\"http:\/\/mng.bz\/VdmX\">http:\/\/mng.bz\/VdmX<\/a>\u3002<\/p>\n<p>Phew! That\u2019s a lot of setup, and if you\u2019re adding providers to ConfigurationManager manually, you\u2019re not done yet! You need to update your app to load the User Secrets at runtime by using the AddUserSecrets extension method:<\/p>\n<p>\u5537\uff01\u8fd9\u9700\u8981\u5927\u91cf\u7684\u8bbe\u7f6e\uff0c\u5982\u679c\u60a8\u624b\u52a8\u5c06\u63d0\u4f9b\u7a0b\u5e8f\u6dfb\u52a0\u5230 ConfigurationManager\uff0c\u90a3\u4e48\u60a8\u8fd8\u6ca1\u6709\u5b8c\u6210\uff01\u60a8\u9700\u8981\u4f7f\u7528 AddUserSecrets \u6269\u5c55\u65b9\u6cd5\u66f4\u65b0\u5e94\u7528\u7a0b\u5e8f\u4ee5\u5728\u8fd0\u884c\u65f6\u52a0\u8f7d\u7528\u6237\u5bc6\u94a5\uff1a<\/p>\n<pre><code>if (builder.Environment.IsDevelopment())\n{\n    builder.Configuration.AddUserSecrets&lt;Program&gt;();\n}<\/code><\/pre>\n<p>Note You should use the User Secrets provider only in development, not in production, so in the preceding snippet you add the provider conditionally to ConfigurationManager. In production you should use environment variables or Azure Key Vault, as discussed earlier. All this is configured correctly by default when you use the default WebApplicationBuilder.<\/p>\n<p>\u6ce8\u610f \u60a8\u5e94\u8be5\u4ec5\u5728\u5f00\u53d1\u4e2d\u4f7f\u7528 User Secrets \u63d0\u4f9b\u7a0b\u5e8f\uff0c\u800c\u4e0d\u5e94\u5728\u751f\u4ea7\u4e2d\u4f7f\u7528\uff0c\u56e0\u6b64\u5728\u524d\u9762\u7684\u4ee3\u7801\u6bb5\u4e2d\uff0c\u60a8\u5c06\u6709\u6761\u4ef6\u5730\u5c06\u63d0\u4f9b\u7a0b\u5e8f\u6dfb\u52a0\u5230 ConfigurationManager\u3002\u5982\u524d\u6240\u8ff0\uff0c\u5728\u751f\u4ea7\u73af\u5883\u4e2d\uff0c\u5e94\u4f7f\u7528\u73af\u5883\u53d8\u91cf\u6216 Azure Key Vault\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5f53\u60a8\u4f7f\u7528\u9ed8\u8ba4\u7684 WebApplicationBuilder \u65f6\uff0c\u6240\u6709\u8fd9\u4e9b\u90fd\u662f\u6b63\u786e\u914d\u7f6e\u7684\u3002<\/p>\n<p>The AddUserSecrets method has several overloads, but the simplest is a generic method that you can call by passing your application\u2019s Program class as a generic argument, as shown in the preceding example. The User Secrets provider needs to read the UserSecretsId property that you (or Visual Studio) added to the .csproj file. The Program class acts as a simple marker to indicate which assembly contains this property.<\/p>\n<p>AddUserSecrets \u65b9\u6cd5\u5177\u6709\u591a\u4e2a\u91cd\u8f7d\uff0c\u4f46\u6700\u7b80\u5355\u7684\u662f\u6cdb\u578b\u65b9\u6cd5\uff0c\u60a8\u53ef\u4ee5\u901a\u8fc7\u5c06\u5e94\u7528\u7a0b\u5e8f\u7684 Program \u7c7b\u4f5c\u4e3a\u6cdb\u578b\u53c2\u6570\u4f20\u9012\u6765\u8c03\u7528\u8be5\u65b9\u6cd5\uff0c\u5982\u524d\u9762\u7684\u793a\u4f8b\u6240\u793a\u3002\u7528\u6237\u673a\u5bc6\u63d0\u4f9b\u7a0b\u5e8f\u9700\u8981\u8bfb\u53d6\u4f60\uff08\u6216 Visual Studio\uff09\u6dfb\u52a0\u5230 .csproj \u6587\u4ef6\u7684 UserSecretsId \u5c5e\u6027\u3002Program \u7c7b\u5145\u5f53\u4e00\u4e2a\u7b80\u5355\u7684\u6807\u8bb0\uff0c\u7528\u4e8e\u6307\u793a\u54ea\u4e2a\u7a0b\u5e8f\u96c6\u5305\u542b\u6b64\u5c5e\u6027\u3002<\/p>\n<p><strong>Note<\/strong> If you\u2019re interested, the .NET software development kit (SDK) uses the UserSecretsId property in your .csproj file to generate an assembly-level UserSecretsIdAttribute. Then the provider reads this attribute at runtime to determine the UserSecretsId of the app and generates the path to the secrets.json file.<br \/>\n<strong>\u6ce8\u610f<\/strong> \u5982\u679c\u60a8\u611f\u5174\u8da3\uff0c.NET SDK \u4f7f\u7528 .csproj \u6587\u4ef6\u4e2d\u7684 UserSecretsId \u5c5e\u6027\u751f\u6210\u7a0b\u5e8f\u96c6\u7ea7 UserSecretsIdAttribute\u3002\u7136\u540e\uff0c\u63d0\u4f9b\u7a0b\u5e8f\u5728\u8fd0\u884c\u65f6\u8bfb\u53d6\u6b64\u5c5e\u6027\u4ee5\u786e\u5b9a\u5e94\u7528\u7684 UserSecretsId \u5e76\u751f\u6210secrets.json\u6587\u4ef6\u7684\u8def\u5f84\u3002<\/p>\n<p>And there you have it\u2014safe storage of your secrets outside your project folder during development. This cautious approach may seem like overkill, but if you have anything you consider to be remotely sensitive that you need to load into configuration, I strongly urge you to use environment variables or User Secrets.<\/p>\n<p>\u8fd9\u5c31\u662f \u2014 \u5728\u5f00\u53d1\u8fc7\u7a0b\u4e2d\u5c06\u5bc6\u94a5\u5b89\u5168\u5730\u5b58\u50a8\u5728\u9879\u76ee\u6587\u4ef6\u5939\u4e4b\u5916\u3002\u8fd9\u79cd\u8c28\u614e\u7684\u65b9\u6cd5\u53ef\u80fd\u4f1a\u4f3c\u4e4e\u6709\u70b9\u77eb\u6789\u8fc7\u6b63\uff0c\u4f46\u5982\u679c\u60a8\u6709\u4efb\u4f55\u60a8\u8ba4\u4e3a\u8fdc\u7a0b\u654f\u611f\u7684\u4e1c\u897f\u9700\u8981\u52a0\u8f7d\u5230\u914d\u7f6e\u4e2d\uff0c\u6211\u5f3a\u70c8\u5efa\u8bae\u60a8\u4f7f\u7528\u73af\u5883\u53d8\u91cf\u6216\u7528\u6237\u5bc6\u94a5\u3002<\/p>\n<p>It\u2019s almost time to leave configuration providers behind, but before we do, I\u2019d like to show you the ASP.NET Core configuration system\u2019s party trick: reloading files on the fly.<\/p>\n<p>\u73b0\u5728\u5dee\u4e0d\u591a\u8be5\u629b\u5f03\u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\u4e86\uff0c\u4f46\u5728\u6b64\u4e4b\u524d\uff0c\u6211\u60f3\u5411\u60a8\u5c55\u793a ASP.NET Core \u914d\u7f6e\u7cfb\u7edf\u7684\u6d3e\u5bf9\u6280\u5de7\uff1a\u52a8\u6001\u91cd\u65b0\u52a0\u8f7d\u6587\u4ef6\u3002<\/p>\n<h3>10.2.4 Reloading configuration values when they change<\/h3>\n<h3>10.2.4 \u5728\u914d\u7f6e\u503c\u66f4\u6539\u65f6\u91cd\u65b0\u52a0\u8f7d\u914d\u7f6e\u503c<\/h3>\n<p>Besides security, not having to recompile your application every time you want to tweak a value is one of the advantages of using configuration and settings. In the previous version of ASP.NET, changing a setting by editing web.config would cause your app to restart. This feature beat having to recompile, but waiting for the app to start up before it could serve requests was a bit of a drag.<br \/>\n\u9664\u4e86\u5b89\u5168\u6027\u4e4b\u5916\uff0c\u4e0d\u5fc5\u5728\u6bcf\u6b21\u8981\u8c03\u6574\u503c\u65f6\u90fd\u91cd\u65b0\u7f16\u8bd1\u5e94\u7528\u7a0b\u5e8f\u662f\u4f7f\u7528 configuration \u548c settings \u7684\u4f18\u52bf\u4e4b\u4e00\u3002\u5728\u65e9\u671f\u7248\u672c\u7684 ASP.NET \u4e2d\uff0c\u901a\u8fc7\u7f16\u8f91 web.config \u6765\u66f4\u6539\u8bbe\u7f6e\u5c06\u5bfc\u81f4\u5e94\u7528\u7a0b\u5e8f\u91cd\u542f\u3002\u6b64\u529f\u80fd\u6bd4\u5fc5\u987b\u91cd\u65b0\u7f16\u8bd1\u8981\u597d\uff0c\u4f46\u7b49\u5f85\u5e94\u7528\u7a0b\u5e8f\u542f\u52a8\u540e\u624d\u80fd\u5904\u7406\u8bf7\u6c42\u6709\u70b9\u9ebb\u70e6\u3002<\/p>\n<p>In ASP.NET Core, you finally get the ability to edit a file and have the configuration of your application update automatically, without your having to recompile or restart. An often-cited scenario in which you might find this ability useful is when you\u2019re trying to debug an app you have in production. You typically configure logging to one of several levels:<\/p>\n<p>\u5728 ASP.NET Core \u4e2d\uff0c\u60a8\u6700\u7ec8\u80fd\u591f\u7f16\u8f91\u6587\u4ef6\u5e76\u81ea\u52a8\u66f4\u65b0\u5e94\u7528\u7a0b\u5e8f\u7684\u914d\u7f6e\uff0c\u800c\u65e0\u9700\u91cd\u65b0\u7f16\u8bd1\u6216\u91cd\u65b0\u542f\u52a8\u3002\u60a8\u53ef\u80fd\u4f1a\u53d1\u73b0\u6b64\u529f\u80fd\u975e\u5e38\u6709\u7528\u7684\u4e00\u4e2a\u7ecf\u5e38\u88ab\u5f15\u7528\u7684\u573a\u666f\u662f\uff0c\u5f53\u60a8\u5c1d\u8bd5\u8c03\u8bd5\u751f\u4ea7\u73af\u5883\u4e2d\u7684\u5e94\u7528\u7a0b\u5e8f\u65f6\u3002\u901a\u5e38\u5c06\u65e5\u5fd7\u8bb0\u5f55\u914d\u7f6e\u4e3a\u4ee5\u4e0b\u51e0\u4e2a\u7ea7\u522b\u4e4b\u4e00\uff1a<\/p>\n<ul>\n<li>Error<br \/>\n\u9519\u8bef<\/li>\n<li>Warning<br \/>\n\u8b66\u544a<\/li>\n<li>Information<br \/>\n\u4fe1\u606f<\/li>\n<li>Debug<br \/>\n\u8c03\u8bd5<\/li>\n<\/ul>\n<p>Each of these settings is more verbose than the last, but it also provides more context. By default, you might configure your app to log only warning and error-level logs in production so that you don\u2019t generate too many superfluous log entries. Conversely, if you\u2019re trying to debug a problem, you want as much information as possible, so you may want to use the debug log level.<\/p>\n<p>\u8fd9\u4e9b\u8bbe\u7f6e\u4e2d\u7684\u6bcf\u4e00\u4e2a\u90fd\u6bd4\u4e0a\u4e00\u4e2a\u8bbe\u7f6e\u66f4\u8be6\u7ec6\uff0c\u4f46\u5b83\u4e5f\u63d0\u4f9b\u4e86\u66f4\u591a\u7684\u4e0a\u4e0b\u6587\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u60a8\u53ef\u4ee5\u5c06\u5e94\u7528\u7a0b\u5e8f\u914d\u7f6e\u4e3a\u5728\u751f\u4ea7\u73af\u5883\u4e2d\u4ec5\u8bb0\u5f55\u8b66\u544a\u548c\u9519\u8bef\u7ea7\u522b\u7684\u65e5\u5fd7\uff0c\u8fd9\u6837\u5c31\u4e0d\u4f1a\u751f\u6210\u592a\u591a\u591a\u4f59\u7684\u65e5\u5fd7\u6761\u76ee\u3002\u76f8\u53cd\uff0c\u5982\u679c\u60a8\u5c1d\u8bd5\u8c03\u8bd5\u95ee\u9898\uff0c\u5219\u9700\u8981\u5c3d\u53ef\u80fd\u591a\u7684\u4fe1\u606f\uff0c\u56e0\u6b64\u53ef\u80fd\u9700\u8981\u4f7f\u7528 debug log \u7ea7\u522b\u3002<\/p>\n<p>Being able to change configuration at runtime means that you can easily switch on extra logs when you encounter a problem and switch them back afterward by editing your appsettings.json file.<\/p>\n<p>\u80fd\u591f\u5728\u8fd0\u884c\u65f6\u66f4\u6539\u914d\u7f6e\u610f\u5473\u7740\u60a8\u53ef\u4ee5\u5728\u9047\u5230\u95ee\u9898\u65f6\u8f7b\u677e\u6253\u5f00\u989d\u5916\u7684\u65e5\u5fd7\uff0c\u5e76\u5728\u4e4b\u540e\u901a\u8fc7\u7f16\u8f91 appsettings.json \u6587\u4ef6\u5c06\u5b83\u4eec\u5207\u6362\u56de\u6765\u3002<\/p>\n<p><strong>Note<\/strong> Reloading is generally available only for file-based configuration providers, such as the JSON provider, as opposed to the environment variable provider, for example.<br \/>\n<strong>\u6ce8\u610f<\/strong>  \u91cd\u65b0\u52a0\u8f7d\u901a\u5e38\u4ec5\u9002\u7528\u4e8e\u57fa\u4e8e\u6587\u4ef6\u7684\u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u4f8b\u5982 JSON \u63d0\u4f9b\u7a0b\u5e8f\uff0c\u800c\u4e0d\u662f\u73af\u5883\u53d8\u91cf\u63d0\u4f9b\u7a0b\u5e8f\u3002<\/p>\n<p>You can enable the reloading of configuration files when you add any of the file-based providers to your ConfigurationManager. The Add*File extension methods include an overload with a reloadOnChange parameter. If this parameter is set to true, the app monitors the filesystem for changes to the file and triggers a complete rebuild of the IConfiguration, if needs be. The following listing shows how to add configuration reloading to the appsettings.json file added manually to the ConfigurationManager.<\/p>\n<p>\u5f53\u60a8\u5c06\u4efb\u4f55\u57fa\u4e8e\u6587\u4ef6\u7684\u63d0\u4f9b\u7a0b\u5e8f\u6dfb\u52a0\u5230 ConfigurationManager \u65f6\uff0c\u60a8\u53ef\u4ee5\u542f\u7528\u914d\u7f6e\u6587\u4ef6\u7684\u91cd\u65b0\u52a0\u8f7d\u3002Add*File \u6269\u5c55\u540d\u65b9\u6cd5\u5305\u62ec\u5e26\u6709 reloadOnChange \u53c2\u6570\u7684\u91cd\u8f7d\u3002\u5982\u679c\u6b64\u53c2\u6570\u8bbe\u7f6e\u4e3a true\uff0c\u5219\u5e94\u7528\u7a0b\u5e8f\u4f1a\u76d1\u89c6\u6587\u4ef6\u7cfb\u7edf\u4e2d\u5bf9\u6587\u4ef6\u7684\u66f4\u6539\uff0c\u5e76\u5728\u9700\u8981\u65f6\u89e6\u53d1 IConfiguration \u7684\u5b8c\u5168\u91cd\u5efa\u3002\u4e0b\u9762\u7684\u6e05\u5355\u663e\u793a\u4e86\u5982\u4f55\u5c06\u914d\u7f6e\u91cd\u65b0\u52a0\u8f7d\u6dfb\u52a0\u5230\u624b\u52a8\u6dfb\u52a0\u5230 ConfigurationManager \u7684 appsettings.json \u6587\u4ef6\u4e2d\u3002<\/p>\n<p>Listing 10.5 Reloading appsettings.json when the file changes<br \/>\n\u793a\u4f8b 10.5 \u5f53\u6587\u4ef6\u66f4\u6539\u65f6\u91cd\u65b0\u52a0\u8f7d appsettings.json<\/p>\n<pre><code>WebApplicationBuilder builder = WebApplication.CreateBuilder(args);\n\nbuilder.Configuration.Sources.Clear();\nbuilder.Configuration\n    .AddJsonFile(\n        &quot;appsettings.json&quot;,\n        optional: true,\n        reloadOnChange: true); \u2776\n\nWebApplication app = builder.Build();\n\napp.MapGet(&quot;\/&quot;, () =&gt; app.Configuration.AsEnumerable());\n\napp.Run();<\/code><\/pre>\n<p>\u2776 IConfiguration will be rebuilt if the appsettings.json file changes.<br \/>\n\u5982\u679c IConfiguration \u6587\u4ef6\u53d1\u751f\u66f4\u6539\uff0cappsettings.json \u5c06\u91cd\u5efa\u3002<\/p>\n<p>Throughout section 10.2, you\u2019ve seen how to customize the ConfigurationManager providers by clearing the default sources and adding your own, but in most cases, that won\u2019t be necessary. As described in section 10.2.1, the default providers added by WebApplicationBuilder are normally good enough unless you want to add a new provider, such as Azure Key Vault. As a bonus, WebApplicationBuilder configures the appsettings.json with reloadOnChange:true by default. It\u2019s worth sticking with the defaults initially and clear the sources and start again only if you really need to.<\/p>\n<p>\u5728\u6574\u4e2a 10.2 \u8282\u4e2d\uff0c\u60a8\u5df2\u7ecf\u4e86\u89e3\u4e86\u5982\u4f55\u901a\u8fc7\u6e05\u9664\u9ed8\u8ba4\u6e90\u5e76\u6dfb\u52a0\u60a8\u81ea\u5df1\u7684\u6e90\u6765\u81ea\u5b9a\u4e49 ConfigurationManager \u63d0\u4f9b\u7a0b\u5e8f\uff0c\u4f46\u5728\u5927\u591a\u6570\u60c5\u51b5\u4e0b\uff0c\u8fd9\u4e0d\u662f\u5fc5\u9700\u7684\u3002\u5982\u7b2c 10.2.1 \u8282\u6240\u8ff0\uff0cWebApplicationBuilder \u6dfb\u52a0\u7684\u9ed8\u8ba4\u63d0\u4f9b\u7a0b\u5e8f\u901a\u5e38\u8db3\u591f\u597d\uff0c\u9664\u975e\u60a8\u8981\u6dfb\u52a0\u65b0\u7684\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u4f8b\u5982 Azure Key Vault\u3002\u4f5c\u4e3a\u5956\u52b1\uff0cWebApplicationBuilder \u9ed8\u8ba4\u4f7f\u7528 reloadOnChange\uff1atrue \u914d\u7f6eappsettings.json\u3002\u6700\u521d\u575a\u6301\u4f7f\u7528\u9ed8\u8ba4\u503c\u5e76\u6e05\u9664\u6e90\u5e76\u4ec5\u5728\u60a8\u786e\u5b9e\u9700\u8981\u65f6\u624d\u91cd\u65b0\u5f00\u59cb\u662f\u503c\u5f97\u7684\u3002<\/p>\n<p><strong>Warning<\/strong> Adding a file configuration source using reloadOnChange:true isn\u2019t entirely free, as ASP.NET Core sets up a file watcher in the background. Normally, this situation isn\u2019t problematic, but if you set up a configuration watching thousands of files, you could run into difficulties!<br \/>\n<strong>\u8b66\u544a<\/strong> \u4f7f\u7528 reloadOnChange\uff1atrue \u6dfb\u52a0\u6587\u4ef6\u914d\u7f6e\u6e90\u5e76\u975e\u5b8c\u5168\u514d\u8d39\uff0c\u56e0\u4e3a ASP.NET Core \u5728\u540e\u53f0\u8bbe\u7f6e\u4e86\u6587\u4ef6\u4fa6\u542c\u5668\u3002\u901a\u5e38\uff0c\u8fd9\u79cd\u60c5\u51b5\u6ca1\u6709\u95ee\u9898\uff0c\u4f46\u5982\u679c\u60a8\u8bbe\u7f6e\u4e00\u4e2a\u76d1\u89c6\u6570\u5343\u4e2a\u6587\u4ef6\u7684\u914d\u7f6e\uff0c\u60a8\u53ef\u80fd\u4f1a\u9047\u5230\u56f0\u96be\uff01<\/p>\n<p>In listing 10.5, any changes you make to the file will be mirrored in the IConfiguration. But as I said at the start of this chapter, IConfiguration isn\u2019t the preferred way to pass settings around in your application. Instead, as you\u2019ll see in section 10.3, you should favor strongly typed objects.<\/p>\n<p>\u5728\u6e05\u5355 10.5 \u4e2d\uff0c\u60a8\u5bf9\u6587\u4ef6\u6240\u505a\u7684\u4efb\u4f55\u66f4\u6539\u90fd\u5c06\u955c\u50cf\u5230 IConfiguration \u4e2d\u3002\u4f46\u6b63\u5982\u6211\u5728\u672c\u7ae0\u5f00\u5934\u6240\u8bf4\uff0cIConfiguration \u5e76\u4e0d\u662f\u5728\u5e94\u7528\u7a0b\u5e8f\u4e2d\u4f20\u9012\u8bbe\u7f6e\u7684\u9996\u9009\u65b9\u6cd5\u3002\u76f8\u53cd\uff0c\u6b63\u5982\u60a8\u5c06\u5728 10.3 \u8282\u4e2d\u770b\u5230\u7684\u90a3\u6837\uff0c\u60a8\u5e94\u8be5\u9996\u9009\u5f3a\u7c7b\u578b\u5bf9\u8c61\u3002<\/p>\n<h2>10.3 Using strongly typed settings with the options pattern<\/h2>\n<h2>10.3 \u5c06\u5f3a\u7c7b\u578b\u8bbe\u7f6e\u4e0e options \u6a21\u5f0f\u4e00\u8d77\u4f7f\u7528<\/h2>\n<p>In this section you\u2019ll learn about strongly typed configuration and the options pattern, the preferred way of accessing configuration in ASP.NET Core. By using strongly typed configuration, you can avoid problems with typos when accessing configuration. It also makes classes easier to test, as you can use simple POCO objects for configuration instead of relying on the IConfiguration abstraction.<\/p>\n<p>\u5728\u672c\u8282\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3\u5f3a\u7c7b\u578b\u914d\u7f6e\u548c\u9009\u9879\u6a21\u5f0f\uff0c\u8fd9\u662f\u5728 ASP.NET Core \u4e2d\u8bbf\u95ee\u914d\u7f6e\u7684\u9996\u9009\u65b9\u5f0f\u3002\u901a\u8fc7\u4f7f\u7528\u5f3a\u7c7b\u578b\u914d\u7f6e\uff0c\u60a8\u53ef\u4ee5\u907f\u514d\u5728\u8bbf\u95ee\u914d\u7f6e\u65f6\u51fa\u73b0\u62fc\u5199\u9519\u8bef\u95ee\u9898\u3002\u5b83\u8fd8\u4f7f\u7c7b\u66f4\u6613\u4e8e\u6d4b\u8bd5\uff0c\u56e0\u4e3a\u60a8\u53ef\u4ee5\u4f7f\u7528\u7b80\u5355\u7684 POCO \u5bf9\u8c61\u8fdb\u884c\u914d\u7f6e\uff0c\u800c\u4e0d\u662f\u4f9d\u8d56 IConfiguration \u62bd\u8c61\u3002<\/p>\n<p>Most of the examples I\u2019ve shown so far have been about how to get values into IConfiguration, as opposed to how to use them. You\u2019ve seen that you can access a key by using the builder.Configuration[&quot;key&quot;] dictionary syntax, but using string keys this way feels messy and prone to typos, and the value retrieved is always a string, so you often need to convert it to another type. Instead, ASP.NET Core promotes the use of strongly typed settings\u2014POCO objects that you define and create and that represent a small collection of settings, scoped to a single feature in your app.<\/p>\n<p>\u5230\u76ee\u524d\u4e3a\u6b62\uff0c\u6211\u5c55\u793a\u7684\u5927\u591a\u6570\u793a\u4f8b\u90fd\u662f\u5173\u4e8e\u5982\u4f55\u5c06\u503c\u5bfc\u5165 IConfiguration\uff0c\u800c\u4e0d\u662f\u5982\u4f55\u4f7f\u7528\u5b83\u4eec\u3002 \u60a8\u5df2\u7ecf\u770b\u5230\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528\u751f\u6210\u5668\u8bbf\u95ee\u5bc6\u94a5\u3002Configuration[\u201ckey\u201d] \u5b57\u5178\u8bed\u6cd5\uff0c\u4f46\u4ee5\u8fd9\u79cd\u65b9\u5f0f\u4f7f\u7528\u5b57\u7b26\u4e32\u952e\u611f\u89c9\u5f88\u6df7\u4e71\uff0c\u5bb9\u6613\u51fa\u73b0\u62fc\u5199\u9519\u8bef\uff0c\u800c\u4e14\u68c0\u7d22\u5230\u7684\u503c\u603b\u662f\u5b57\u7b26\u4e32\uff0c\u6240\u4ee5\u4f60\u7ecf\u5e38\u9700\u8981\u628a\u5b83\u8f6c\u6362\u6210\u53e6\u4e00\u79cd\u7c7b\u578b\u3002\u76f8\u53cd\uff0cASP.NET Core \u4fc3\u8fdb\u4e86\u5f3a\u7c7b\u578b\u8bbe\u7f6e\u7684\u4f7f\u7528\uff0c\u5373\u60a8\u5b9a\u4e49\u548c\u521b\u5efa\u7684 POCO \u5bf9\u8c61\uff0c\u8fd9\u4e9b\u5bf9\u8c61\u8868\u793a\u4e00\u5c0f\u90e8\u5206\u8bbe\u7f6e\uff0c\u8303\u56f4\u9650\u5b9a\u4e3a\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u5355\u4e2a\u529f\u80fd\u3002<\/p>\n<p>The following listing shows both the settings for your store locator component and display settings to customize the home page of the app. They\u2019re separated into two different objects with &quot;MapSettings&quot; and &quot;AppDisplaySettings&quot; keys, corresponding to the different areas of the app that they affect.<\/p>\n<p>\u4ee5\u4e0b\u6e05\u5355\u663e\u793a\u4e86 store locator \u7ec4\u4ef6\u7684\u5730\u56fe\u8bbe\u7f6e\u548c\u663e\u793a\u8bbe\u7f6e\uff0c\u4ee5\u81ea\u5b9a\u4e49\u5e94\u7528\u7a0b\u5e8f\u7684\u4e3b\u9875\u3002\u5b83\u4eec\u88ab\u5206\u6210\u4e24\u4e2a\u4e0d\u540c\u7684\u5bf9\u8c61\uff0c\u5206\u522b\u5177\u6709\u201cMapSettings\u201d\u548c\u201cAppDisplaySettings\u201d\u952e\uff0c\u5bf9\u5e94\u4e8e\u5b83\u4eec\u5f71\u54cd\u7684\u5e94\u7528\u7684\u4e0d\u540c\u533a\u57df\u3002<\/p>\n<p>Listing 10.6 Separating settings into different objects in appsettings.json<br \/>\n\u6e05\u5355 10.6 \u5728 appsettings.json \u4e2d\u5c06\u8bbe\u7f6e\u5206\u79bb\u5230\u4e0d\u540c\u7684\u5bf9\u8c61\u4e2d<\/p>\n<pre><code>{\n    &quot;MapSettings&quot;: { \u2776\n        &quot;DefaultZoomLevel&quot;: 6, \u2776\n        &quot;DefaultLocation&quot;: { \u2776\n            &quot;latitude&quot;: 50.500, \u2776\n            &quot;longitude&quot;: -4.000 \u2776\n    }\n},\n    &quot;AppDisplaySettings&quot;: { \u2777\n        &quot;Title&quot;: &quot;Acme Store Locator&quot;, \u2777\n        &quot;ShowCopyright&quot;: true \u2777\n    }\n}<\/code><\/pre>\n<p>\u2776 Settings related to the store locator section of the app<br \/>\n\u4e0e\u5e94\u7528\u7a0b\u5e8f\u7684\u5546\u5e97\u5b9a\u4f4d\u5668\u90e8\u5206\u76f8\u5173\u7684\u8bbe\u7f6e<\/p>\n<p>\u2777 General settings related to displaying the app<br \/>\n\u4e0e\u663e\u793a\u5e94\u7528\u7a0b\u5e8f\u76f8\u5173\u7684\u5e38\u89c4\u8bbe\u7f6e<\/p>\n<p>The simplest approach to exposing the home-page settings in an endpoint handler is to inject IConfiguration into the endpoint handler and access the values by using the dictionary syntax:<\/p>\n<p>\u5728\u7ec8\u7ed3\u70b9\u5904\u7406\u7a0b\u5e8f\u4e2d\u516c\u5f00\u4e3b\u9875\u8bbe\u7f6e\u7684\u6700\u7b80\u5355\u65b9\u6cd5\u662f\u5c06 IConfiguration \u6ce8\u5165\u5230\u7ec8\u7ed3\u70b9\u5904\u7406\u7a0b\u5e8f\u4e2d\uff0c\u5e76\u4f7f\u7528\u5b57\u5178\u8bed\u6cd5\u8bbf\u95ee\u503c\uff1a<\/p>\n<pre><code>app.MapGet(&quot;\/display-settings&quot;, (Iconfiguration config) =&gt;\n{\n    string title = config[&quot;AppDisplaySettings:Title&quot;];\n    bool showCopyright = bool.Parse(\n            config[&quot;AppDisplaySettings:ShowCopyright&quot;]);\n\n    return new { title, showCopyright };\n});<\/code><\/pre>\n<p>But you don\u2019t want to do this; there are too many strings for my liking! And that bool.Parse? Yuck! Instead, you can use custom strongly typed objects, with all the type safety and IntelliSense goodness that brings, as shown in the following listing.<\/p>\n<p>\u4f46\u4f60\u4e0d\u60f3\u8fd9\u6837\u505a;\u7434\u5f26\u592a\u591a\u4e86\uff0c\u6211\u4e0d\u559c\u6b22\uff01\u8fd8\u6709\u90a3\u4e2a bool\u3002\u89e3\u6790\uff1f\u5478\uff01\u76f8\u53cd\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528\u81ea\u5b9a\u4e49\u7684\u5f3a\u7c7b\u578b\u5bf9\u8c61\uff0c\u8fd9\u4e9b\u5bf9\u8c61\u5177\u6709\u5e26\u6765\u7684\u6240\u6709\u7c7b\u578b\u5b89\u5168\u6027\u548c IntelliSense \u4f18\u70b9\uff0c\u5982\u4e0b\u9762\u7684\u6e05\u5355\u6240\u793a\u3002<\/p>\n<p>Listing 10.7 Injecting strongly typed options into a handler using IOptions<T><br \/>\n\u6e05\u5355 10.7 \u4f7f\u7528 IOptions<T> \u5c06\u5f3a\u7c7b\u578b\u9009\u9879\u6ce8\u5165\u5904\u7406\u7a0b\u5e8f<\/p>\n<pre><code>app.MapGet(&quot;\/display-settings&quot;,\n    (IOptions&lt;AppDisplaySettings&gt; options) =&gt; \u2776\n{\n    AppDisplaySettings settings = options.Value; \u2777\n    string title = settings.Title; \u2778\n\n    bool showCopyright = settings.ShowCopyright; \u2779\n\n    return new { title, showCopyright };\n});<\/code><\/pre>\n<p>\u2776 You can inject a strongly typed options class using the IOptions&lt;&gt; wrapper interface.<br \/>\n\u60a8\u53ef\u4ee5\u4f7f\u7528 IOptions&lt;&gt; \u5305\u88c5\u5668\u63a5\u53e3\u6ce8\u5165\u5f3a\u7c7b\u578b\u9009\u9879\u7c7b\u3002<\/p>\n<p>\u2777 The Value property exposes the POCO settings object.<br \/>\nValue \u5c5e\u6027\u516c\u5f00 POCO \u8bbe\u7f6e\u5bf9\u8c61\u3002<\/p>\n<p>\u2778 The settings object contains properties that are bound to configuration values at runtime.<br \/>\nsettings \u5bf9\u8c61\u5305\u542b\u5728\u8fd0\u884c\u65f6\u7ed1\u5b9a\u5230\u914d\u7f6e\u503c\u7684\u5c5e\u6027\u3002<\/p>\n<p>\u2779 The binder can also convert string values directly to built-in types.<br \/>\nBinder \u8fd8\u53ef\u4ee5\u5c06\u5b57\u7b26\u4e32\u503c\u76f4\u63a5\u8f6c\u6362\u4e3a\u5185\u7f6e\u7c7b\u578b\u3002<\/p>\n<p>The ASP.NET Core configuration system includes a binder, which can take a collection of configuration values and bind them to a strongly typed object, called an options class. This binding is similar to the concept of JSON deserialization for creating types from chapter 6 and the model binding used by Model-View-Controller (MVC) and Razor Pages, which you\u2019ll learn about in part 3.<\/p>\n<p>ASP.NET Core \u914d\u7f6e\u7cfb\u7edf\u5305\u62ec\u4e00\u4e2a Binder\uff0c\u5b83\u53ef\u4ee5\u83b7\u53d6\u914d\u7f6e\u503c\u7684\u96c6\u5408\u5e76\u5c06\u5b83\u4eec\u7ed1\u5b9a\u5230\u4e00\u4e2a\u5f3a\u7c7b\u578b\u5bf9\u8c61\uff0c\u79f0\u4e3a options \u7c7b\u3002\u6b64\u7ed1\u5b9a\u7c7b\u4f3c\u4e8e\u7b2c 6 \u7ae0\u4e2d\u7528\u4e8e\u521b\u5efa\u7c7b\u578b\u7684 JSON \u53cd\u5e8f\u5217\u5316\u6982\u5ff5\uff0c\u4ee5\u53ca\u6a21\u578b-\u89c6\u56fe-\u63a7\u5236\u5668 \uff08MVC\uff09 \u548c Razor Pages \u4f7f\u7528\u7684\u6a21\u578b\u7ed1\u5b9a\uff0c\u60a8\u5c06\u5728\u7b2c 3 \u90e8\u5206\u4e2d\u4e86\u89e3\u3002<\/p>\n<p>Section 10.3.1 shows how to set up the binding of configuration values to a POCO options class, and section 10.3.2 shows how to make sure that it reloads when the underlying configuration values change. We\u2019ll look at the different sorts of objects you can bind in section 10.3.3.<\/p>\n<p>Section 10.3.1 \u663e\u793a\u4e86\u5982\u4f55\u8bbe\u7f6e\u914d\u7f6e\u503c\u5230 POCO options \u7c7b\u7684\u7ed1\u5b9a\uff0c\u800cSection 10.3.2 \u663e\u793a\u4e86\u5982\u4f55\u786e\u4fdd\u5728\u5e95\u5c42\u914d\u7f6e\u503c\u66f4\u6539\u65f6\u91cd\u65b0\u52a0\u8f7d\u5b83\u3002\u6211\u4eec\u5c06\u5728 10.3.3 \u8282\u4e2d\u770b\u770b\u4f60\u53ef\u4ee5\u7ed1\u5b9a\u7684\u4e0d\u540c\u79cd\u7c7b\u7684\u5bf9\u8c61\u3002<\/p>\n<h3>10.3.1 Introducing the IOptions interface<\/h3>\n<h3>10.3.1 IOptions \u63a5\u53e3\u7b80\u4ecb<\/h3>\n<p>ASP.NET Core introduced strongly typed settings as a way of letting configuration code adhere to the single-responsibility principle (SRP) and to allow the injection of configuration classes as explicit dependencies. Such settings also make testing easier; instead of having to create an instance of IConfiguration to test a service, you can create an instance of the POCO options class.<\/p>\n<p>ASP.NET Core \u5f15\u5165\u4e86\u5f3a\u7c7b\u578b\u8bbe\u7f6e\uff0c\u4ee5\u6b64\u65b9\u5f0f\u8ba9\u914d\u7f6e\u4ee3\u7801\u9075\u5faa\u5355\u4e00\u804c\u8d23\u539f\u5219 \uff08SRP\uff09\uff0c\u5e76\u5141\u8bb8\u5c06\u914d\u7f6e\u7c7b\u4f5c\u4e3a\u663e\u5f0f\u4f9d\u8d56\u9879\u6ce8\u5165\u3002\u6b64\u7c7b\u8bbe\u7f6e\u8fd8\u4f7f\u6d4b\u8bd5\u66f4\u5bb9\u6613;\u60a8\u4e0d\u5fc5\u521b\u5efa IConfiguration \u7684\u5b9e\u4f8b\u6765\u6d4b\u8bd5\u670d\u52a1\uff0c\u800c\u662f\u53ef\u4ee5\u521b\u5efa POCO \u9009\u9879\u7c7b\u7684\u5b9e\u4f8b\u3002<\/p>\n<p>The AppDisplaySettings class shown in the previous example could be simple, exposing only the values related to the home page:<\/p>\n<p>\u4e0a\u4f8b\u6240\u793a\u7684 AppDisplaySettings \u7c7b\u53ef\u80fd\u5f88\u7b80\u5355\uff0c\u53ea\u516c\u5f00\u4e0e\u4e3b\u9875\u76f8\u5173\u7684\u503c\uff1a<\/p>\n<pre><code>public class AppDisplaySettings\n{\n    public string Title { get; set; }\n    public bool ShowCopyright { get; set; }\n}<\/code><\/pre>\n<p>Your options classes need to be nonabstract and have a public parameterless constructor to be eligible for binding. The binder sets any public properties that match configuration values, as you\u2019ll see in section 10.3.3.<\/p>\n<p>\u4f60\u7684 options \u7c7b\u5fc5\u987b\u662f\u975e\u62bd\u8c61\u7684\uff0c\u5e76\u4e14\u6709\u4e00\u4e2a\u516c\u5171\u7684\u65e0\u53c2\u6570\u6784\u9020\u51fd\u6570\u624d\u6709\u8d44\u683c\u8fdb\u884c\u7ed1\u5b9a\u3002Binders \u8bbe\u7f6e\u4e0e configuration \u503c\u5339\u914d\u7684\u4efb\u4f55\u516c\u5171\u5c5e\u6027\uff0c\u5982 Section 10.3.3 \u6240\u793a\u3002<\/p>\n<p><strong>Tip<\/strong> You\u2019re not restricted to built-in types such as string and bool; you can use nested complex types too. The options system binds sections to complex properties. See the associated source code for examples.<br \/>\n<strong>\u63d0\u793a<\/strong> \u60a8\u4e0d\u4ec5\u9650\u4e8e string \u548c bool \u7b49\u5185\u7f6e\u7c7b\u578b;\u60a8\u4e5f\u53ef\u4ee5\u4f7f\u7528\u5d4c\u5957\u7684\u590d\u6742\u7c7b\u578b\u3002options \u7cfb\u7edf\u5c06 sections \u7ed1\u5b9a\u5230 complex \u5c5e\u6027\u3002\u6709\u5173\u793a\u4f8b\uff0c\u8bf7\u53c2\u9605\u5173\u8054\u7684\u6e90\u4ee3\u7801\u3002<\/p>\n<p>To help facilitate the binding of configuration values to your custom POCO options classes, ASP.NET Core introduces the IOptions<T> interface, a simple interface with a single property, Value, that contains your configured POCO options class at runtime. Options classes are configured as services in Program.cs , as shown in the following listing.<\/p>\n<p>\u4e3a\u4e86\u5e2e\u52a9\u5c06\u914d\u7f6e\u503c\u7ed1\u5b9a\u5230\u81ea\u5b9a\u4e49 POCO \u9009\u9879\u7c7b\uff0cASP.NET Core \u5f15\u5165\u4e86 IOptions<T> \u63a5\u53e3\uff0c\u8fd9\u662f\u4e00\u4e2a\u7b80\u5355\u7684\u63a5\u53e3\uff0c\u5177\u6709\u5355\u4e2a\u5c5e\u6027 Value\uff0c\u5176\u4e2d\u5305\u542b\u60a8\u5728\u8fd0\u884c\u65f6\u914d\u7f6e\u7684 POCO \u9009\u9879\u7c7b\u3002\u9009\u9879\u7c7b\u5728 Program.cs \u4e2d\u914d\u7f6e\u4e3a services\uff0c\u5982\u4ee5\u4e0b\u6e05\u5355\u6240\u793a\u3002<\/p>\n<p>Listing 10.8 Configuring the options classes using Configure<T> in Startup.cs<br \/>\n\u6e05\u5355 10.8 \u5728 Startup.cs \u4e2d\u4f7f\u7528Configure<T><\/p>\n<pre><code>WebApplicationBuilder builder = WebApplication.CreateBuilder(args);\n\nbuilder.Services.Configure&lt;MapSettings&gt;(\n    builder.Configuration.GetSection(&quot;MapSettings&quot;)); \u2776\nbuilder.Services.Configure&lt;AppDisplaySettings&gt;(\n    builder.Configuration.GetSection(&quot;AppDisplaySettings&quot;)); \u2777\n<\/code><\/pre>\n<p>\u2776 Binds the MapSettings section to the POCO options class MapSettings<br \/>\n\u5c06 MapSettings \u90e8\u5206\u7ed1\u5b9a\u5230 POCO \u9009\u9879\u7c7b MapSettings<\/p>\n<p>\u2777 Binds the AppDisplaySettings section to the POCO options class AppDisplaySettings<br \/>\n\u5c06 AppDisplaySettings \u90e8\u5206\u7ed1\u5b9a\u5230 POCO \u9009\u9879\u7c7b AppDisplaySettings<\/p>\n<p><strong>Tip<\/strong> You don\u2019t have to use the same name for both the section and class, as I do in listing 10.8; it\u2019s simply a convention I like to follow. With this convention, you can also use the nameof() operator to further reduce the chance of typos, such as by calling GetSection(nameof(MapSettings)).<br \/>\n<strong>\u63d0\u793a<\/strong> \u60a8\u4e0d\u5fc5\u50cf\u5728\u6e05\u5355 10.8 \u4e2d\u90a3\u6837\u5bf9 section \u548c class \u4f7f\u7528\u76f8\u540c\u7684\u540d\u79f0;\u8fd9\u53ea\u662f\u6211\u559c\u6b22\u9075\u5faa\u7684\u60ef\u4f8b\u3002\u901a\u8fc7\u6b64\u7ea6\u5b9a\uff0c\u60a8\u8fd8\u53ef\u4ee5\u4f7f\u7528 nameof\uff08\uff09 \u8fd0\u7b97\u7b26\u6765\u8fdb\u4e00\u6b65\u51cf\u5c11\u62fc\u5199\u9519\u8bef\u7684\u53ef\u80fd\u6027\uff0c\u4f8b\u5982\u901a\u8fc7\u8c03\u7528 GetSection\uff08nameof\uff08MapSettings\uff09\uff09\u3002<\/p>\n<p>Each call to Configure<T> sets up the following series of actions internally:<br \/>\n\u6bcf\u6b21\u8c03\u7528 Configure<T> \u90fd\u4f1a\u5728\u5185\u90e8\u8bbe\u7f6e\u4ee5\u4e0b\u4e00\u7cfb\u5217\u4f5c\uff1a<\/p>\n<ol>\n<li>\n<p>Creates an instance of ConfigureOptions<T>, which indicates that IOptions<T> should be configured based on configuration.<br \/>\n\u521b\u5efa ConfigureOptions<T> \u7684\u5b9e\u4f8b\uff0c\u8fd9\u8868\u793a\u5e94\u6839\u636e\u914d\u7f6e\u914d\u7f6e IOptions<T>\u3002<br \/>\nIf Configure<T> is called multiple times, multiple ConfigureOptions<T> objects will be used, all of which can be applied to create the final object in much the same way that IConfiguration is built from multiple layers.<br \/>\n\u5982\u679c\u591a\u6b21\u8c03\u7528 Configure<T>\uff0c\u5219\u5c06\u4f7f\u7528\u591a\u4e2a ConfigureOptions<T> \u5bf9\u8c61\uff0c\u6240\u6709\u8fd9\u4e9b\u5bf9\u8c61\u90fd\u53ef\u4ee5\u5e94\u7528\u4e8e\u521b\u5efa\u6700\u7ec8\u5bf9\u8c61\uff0c\u5176\u65b9\u5f0f\u4e0e\u4ece\u591a\u4e2a\u5c42\u6784\u5efa IConfiguration \u7684\u65b9\u5f0f\u5927\u81f4\u76f8\u540c\u3002<\/p>\n<\/li>\n<li>\n<p>Each ConfigureOptions<T> instance binds a section of IConfiguration to an instance of the T POCO class, setting any public properties on the options class based on the keys in the provided ConfigurationSection.<br \/>\n\u6bcf\u4e2a ConfigureOptions<T> \u5b9e\u4f8b\u5c06 IConfiguration \u7684\u4e00\u4e2a\u90e8\u5206\u7ed1\u5b9a\u5230 T POCO \u7c7b\u7684\u5b9e\u4f8b\uff0c\u6839\u636e\u63d0\u4f9b\u7684 ConfigurationSection \u4e2d\u7684\u952e\u8bbe\u7f6e\u9009\u9879\u7c7b\u4e0a\u7684\u4efb\u4f55\u516c\u5171\u5c5e\u6027\u3002<\/p>\n<\/li>\n<\/ol>\n<p>Remember that the section name (&quot;MapSettings&quot; in listing 10.8) can have any value; it doesn\u2019t have to match the name of your options class.<br \/>\n\u8bf7\u8bb0\u4f4f\uff0c\u90e8\u5206\u540d\u79f0\uff08\u6e05\u5355 10.8 \u4e2d\u7684 \u201cMapSettings\u201d\uff09\u53ef\u4ee5\u6709\u4efb\u4f55\u503c;\u5b83\u4e0d\u5fc5\u4e0e Options \u7c7b\u7684\u540d\u79f0\u5339\u914d\u3002<\/p>\n<ol start=\"3\">\n<li>The IOptions<T> interface is registered in the DI container as a singleton, with the final bound POCO object in the Value property.<br \/>\nIOptions<T> \u63a5\u53e3\u5728 DI \u5bb9\u5668\u4e2d\u6ce8\u518c\u4e3a\u5355\u4e00\u5b9e\u4f8b\uff0c\u6700\u7ec8\u7ed1\u5b9a\u7684 POCO \u5bf9\u8c61\u4f4d\u4e8e Value \u5c5e\u6027\u4e2d\u3002<\/li>\n<\/ol>\n<p>This last step lets you inject your options classes into handlers and services by injecting IOptions<T>, as you saw in listing 10.7, giving you encapsulated, strongly typed access to your configuration values. No more magic strings. Woo-hoo!<\/p>\n<p>\u6700\u540e\u4e00\u6b65\u5141\u8bb8\u4f60\u901a\u8fc7\u6ce8\u5165 IOptions<T> \u5c06\u9009\u9879\u7c7b\u6ce8\u5165\u5230\u5904\u7406\u7a0b\u5e8f\u548c\u670d\u52a1\u4e2d\uff0c\u5c31\u50cf\u4f60\u5728\u6e05\u5355 10.7 \u4e2d\u770b\u5230\u7684\u90a3\u6837\uff0c\u4e3a\u4f60\u63d0\u4f9b\u4e86\u5bf9\u914d\u7f6e\u503c\u7684\u5c01\u88c5\u3001\u5f3a\u7c7b\u578b\u8bbf\u95ee\u3002\u4e0d\u518d\u6709\u795e\u5947\u7684\u5b57\u7b26\u4e32\u3002\u545c\u547c\uff01<\/p>\n<p><strong>Warning<\/strong> If you forget to call Configure<T> and inject IOptions<T> into your services, you won\u2019t see any errors, but the T options class won\u2019t be bound to anything and will have only default values in its properties.<br \/>\n<strong>\u8b66\u544a<\/strong> \u5982\u679c\u60a8\u5fd8\u8bb0\u8c03\u7528 Configure<T> \u5e76\u5c06 IOptions<T> \u6ce8\u5165\u5230\u60a8\u7684\u670d\u52a1\u4e2d\uff0c\u60a8\u5c06\u4e0d\u4f1a\u770b\u5230\u4efb\u4f55\u9519\u8bef\uff0c\u4f46 T options \u7c7b\u4e0d\u4f1a\u7ed1\u5b9a\u5230\u4efb\u4f55\u5185\u5bb9\uff0c\u5e76\u4e14\u5176\u5c5e\u6027\u4e2d\u53ea\u6709\u9ed8\u8ba4\u503c\u3002<\/p>\n<p>The binding of the T options class to ConfigurationSection happens when you first request IOptions<T>. The object is registered in the DI container as a singleton, so it\u2019s bound only once.<\/p>\n<p>T options \u7c7b\u4e0e ConfigurationSection \u7684\u7ed1\u5b9a\u53d1\u751f\u5728\u60a8\u9996\u6b21\u8bf7\u6c42 IOptions<T> \u65f6\u3002 \u8be5\u5bf9\u8c61\u5728 DI \u5bb9\u5668\u4e2d\u6ce8\u518c\u4e3a\u5355\u4e00\u5b9e\u4f8b\uff0c\u56e0\u6b64\u5b83\u53ea\u7ed1\u5b9a\u4e00\u6b21\u3002<\/p>\n<p>This setup has one catch: you can\u2019t use the reloadOnChange parameter I described in section 10.2.4 to reload your strongly typed options classes when using IOptions<T>. IConfiguration will still be reloaded if you edit your appsettings.json files, but it won\u2019t propagate to your options class.<\/p>\n<p>\u6b64\u8bbe\u7f6e\u6709\u4e00\u4e2a\u95ee\u9898\uff1a\u5728\u4f7f\u7528 IOptions<T> \u65f6\uff0c\u60a8\u4e0d\u80fd\u4f7f\u7528\u6211\u5728 Section 10.2.4 \u4e2d\u63cf\u8ff0\u7684 reloadOnChange \u53c2\u6570\u6765\u91cd\u65b0\u52a0\u8f7d\u5f3a\u7c7b\u578b\u9009\u9879\u7c7b\u3002\u5982\u679c\u7f16\u8f91 IConfiguration \u6587\u4ef6\uff0cappsettings.json \u4ecd\u4f1a\u91cd\u65b0\u52a0\u8f7d\uff0c\u4f46\u5b83\u4e0d\u4f1a\u4f20\u64ad\u5230\u9009\u9879\u7c7b\u3002<\/p>\n<p>If that fact seems like a step backward or even a deal-breaker, don\u2019t worry. IOptions<T> has a cousin, IOptionsSnapshot<T>, for such an occasion.<\/p>\n<p>\u5982\u679c\u8fd9\u4e2a\u4e8b\u5b9e\u4f3c\u4e4e\u662f\u5012\u9000\uff0c\u751a\u81f3\u662f\u7834\u574f\u4ea4\u6613\uff0c\u8bf7\u4e0d\u8981\u62c5\u5fc3\u3002 IOptions<T> \u6709\u4e00\u4e2a\u8868\u4eb2 IOptionsSnapshot<T> \u7528\u4e8e\u6b64\u7c7b\u573a\u5408\u3002<\/p>\n<h3>10.3.2 Reloading strongly typed options with IOptionsSnapshot<\/h3>\n<h3>10.3.2 \u4f7f\u7528 IOptionsSnapshot \u91cd\u65b0\u52a0\u8f7d\u5f3a\u7c7b\u578b\u9009\u9879<\/h3>\n<p>In section 10.3.1, you used IOptions<T> to provide strongly typed access to configuration. Using IOptions<T> to provide strongly typed access to configuration provided a nice encapsulation of the settings for a particular service, but with a specific drawback: the options class never changes, even if you modify the underlying configuration file from which it was loaded, such as appsettings.json.<\/p>\n<p>\u5728\u7b2c 10.3.1 \u8282\u4e2d\uff0c\u60a8\u4f7f\u7528\u4e86 IOptions<T> \u63d0\u4f9b\u5bf9\u914d\u7f6e\u7684\u5f3a\u7c7b\u578b\u8bbf\u95ee\u3002\u4f7f\u7528 IOptions<T> \u63d0\u4f9b\u5bf9\u914d\u7f6e\u7684\u5f3a\u7c7b\u578b\u8bbf\u95ee\uff0c\u4e3a\u7279\u5b9a\u670d\u52a1\u63d0\u4f9b\u4e86\u5f88\u597d\u7684\u8bbe\u7f6e\u5c01\u88c5\uff0c\u4f46\u6709\u4e00\u4e2a\u7279\u5b9a\u7684\u7f3a\u70b9\uff1a\u9009\u9879\u7c7b\u6c38\u8fdc\u4e0d\u4f1a\u66f4\u6539\uff0c\u5373\u4f7f\u60a8\u4fee\u6539\u4e86\u4ece\u4e2d\u52a0\u8f7d\u5b83\u7684\u57fa\u7840\u914d\u7f6e\u6587\u4ef6\uff0c\u4f8b\u5982 appsettings.json\u3002<\/p>\n<p>This situation isn\u2019t always a problem (you generally shouldn\u2019t be modifying files on live production servers anyway), but if you need this functionality, you can use the IOptionsSnapshot<T> interface. Conceptually, IOptionsSnaphot<T> is identical to IOptions<T> in that it\u2019s a strongly typed representation of a section of configuration. The difference is when and how often the POCO options objects are created when they\u2019re used:<\/p>\n<p>\u8fd9\u79cd\u60c5\u51b5\u5e76\u4e0d\u603b\u662f\u95ee\u9898\uff08\u901a\u5e38\u65e0\u8bba\u5982\u4f55\u90fd\u4e0d\u5e94\u8be5\u5728\u5b9e\u65f6\u751f\u4ea7\u670d\u52a1\u5668\u4e0a\u4fee\u6539\u6587\u4ef6\uff09\uff0c\u4f46\u5982\u679c\u60a8\u9700\u8981\u6b64\u529f\u80fd\uff0c\u5219\u53ef\u4ee5\u4f7f\u7528 IOptionsSnapshot<T> \u63a5\u53e3\u3002\u4ece\u6982\u5ff5\u4e0a\u8bb2\uff0cIOptionsSnaphot<T> \u4e0e IOptions<T> \u76f8\u540c\uff0c\u56e0\u4e3a\u5b83\u662f\u914d\u7f6e\u90e8\u5206\u7684\u5f3a\u7c7b\u578b\u8868\u793a\u5f62\u5f0f\u3002\u533a\u522b\u5728\u4e8e\u4f7f\u7528 POCO \u9009\u9879\u5bf9\u8c61\u7684\u521b\u5efa\u65f6\u95f4\u548c\u9891\u7387\uff1a<\/p>\n<ul>\n<li>\n<p>IOptions<T>\u2014The instance is created once, when first needed. It always contains the configuration from when the object instance was first created.<br \/>\nIOptions<T> \u2013 \u9996\u6b21\u9700\u8981\u65f6\uff0c\u5c06\u521b\u5efa\u4e00\u6b21\u5b9e\u4f8b\u3002\u5b83\u59cb\u7ec8\u5305\u542b\u9996\u6b21\u521b\u5efa\u5bf9\u8c61\u5b9e\u4f8b\u65f6\u7684\u914d\u7f6e\u3002<\/p>\n<\/li>\n<li>\n<p>IOptionsSnapshot<T>\u2014A new instance is created, when needed, if the underlying configuration has changed since the last instance was created.<br \/>\nIOptionsSnapshot<T> \u2013 \u5982\u679c\u81ea\u521b\u5efa\u4e0a\u4e00\u4e2a\u5b9e\u4f8b\u4ee5\u6765\u5e95\u5c42\u914d\u7f6e\u5df2\u66f4\u6539\uff0c\u5219\u5728\u9700\u8981\u65f6\u521b\u5efa\u65b0\u5b9e\u4f8b\u3002<\/p>\n<\/li>\n<\/ul>\n<p><strong>Warning<\/strong> IOptionsSnapshot<T> is registered as a scoped service, so you can\u2019t inject it into singleton services; if you do, you\u2019ll have a captive dependency, as discussed in chapter 9. If you need a singleton version of IOptionsSnapshot<T>, you can use a similar interface, IOptionsMonitor<T>. See this blog post for details: <a href=\"http:\/\/mng.bz\/9Da7\">http:\/\/mng.bz\/9Da7<\/a>.<br \/>\n<strong>\u8b66\u544a<\/strong> IOptionsSnapshot<T> \u6ce8\u518c\u4e3a\u8303\u56f4\u670d\u52a1\uff0c\u56e0\u6b64\u60a8\u4e0d\u80fd\u5c06\u5176\u6ce8\u5165\u5230\u5355\u4e00\u5b9e\u4f8b\u670d\u52a1\u4e2d;\u5982\u679c\u8fd9\u6837\u505a\uff0c\u60a8\u5c06\u62e5\u6709\u4e00\u4e2a\u6355\u83b7\u4f9d\u8d56\u9879\uff0c\u5982\u7b2c 9 \u7ae0\u6240\u8ff0\u3002\u5982\u679c\u9700\u8981 IOptionsSnapshot<T> \u7684\u5355\u4e00\u5b9e\u4f8b\u7248\u672c\uff0c\u53ef\u4ee5\u4f7f\u7528\u7c7b\u4f3c\u7684\u63a5\u53e3 IOptionsMonitor<T>\u3002\u6709\u5173\u8be6\u7ec6\u4fe1\u606f\uff0c\u8bf7\u53c2\u9605\u6b64\u535a\u5ba2\u6587\u7ae0\uff1a<a href=\"http:\/\/mng.bz\/9Da7\">http:\/\/mng.bz\/9Da7<\/a>\u3002<\/p>\n<p>IOptionsSnaphot<T> is set up for your options classes automatically at the same time as IOptions<T>, so you can use it in your services in exactly the same way. The following listing shows how you could update your display-settings API so that you always get the latest configuration values in your strongly typed AppDisplaySettings options class.<\/p>\n<p>IOptionsSnaphot<T> \u4e0e IOptions<T> \u540c\u65f6\u81ea\u52a8\u4e3a\u60a8\u7684\u9009\u9879\u7c7b\u8bbe\u7f6e\uff0c\u56e0\u6b64\u60a8\u53ef\u4ee5\u4ee5\u5b8c\u5168\u76f8\u540c\u7684\u65b9\u5f0f\u5728\u670d\u52a1\u4e2d\u4f7f\u7528\u5b83\u3002\u4ee5\u4e0b\u6e05\u5355\u663e\u793a\u4e86\u5982\u4f55\u66f4\u65b0 display-settings API\uff0c\u4ee5\u4fbf\u59cb\u7ec8\u5728\u5f3a\u7c7b\u578b AppDisplaySettings \u9009\u9879\u7c7b\u4e2d\u83b7\u53d6\u6700\u65b0\u7684\u914d\u7f6e\u503c\u3002<\/p>\n<p>Listing 10.9 Injecting reloadable options using IOptionsSnapshot<T><br \/>\n\u6e05\u5355 10.9 \u4f7f\u7528IOptionsSnapshot<T><\/p>\n<pre><code>app.MapGet(&quot;\/display-settings&quot;,\n    (IOptionsSnapshot&lt;AppDisplaySettings&gt; options) =&gt; \u2776\n{\n    AppDisplaySettings settings = options.Value; \u2777\n\n    return new\n    {\n        title = settings.Title, \u2778\n        showCopyright = settings.ShowCopyright, \u2778\n    };\n});<\/code><\/pre>\n<p>\u2776 <code>IOptionsSnapshot&lt;T&gt;<\/code> updates automatically if the underlying configuration values<br \/>\nchange.<br \/>\n\u5982\u679c\u5e95\u5c42\u914d\u7f6e\u503c\u53d1\u751f\u66f4\u6539\uff0c<code>IOptionsSnapshot&lt;T&gt;<\/code> \u4f1a\u81ea\u52a8\u66f4\u65b0\u3002<\/p>\n<p>\u2777 The Value property exposes the POCO settings object, the same as for <code>IOptions&lt;T&gt;<\/code>.<br \/>\nValue \u5c5e\u6027\u516c\u5f00 POCO \u8bbe\u7f6e\u5bf9\u8c61\uff0c\u4e0e <code>IOptions&lt;T&gt;<\/code> \u76f8\u540c\u3002<\/p>\n<p>\u2778 The settings match the configuration values at that point in time instead of at first<br \/>\nrun.<br \/>\n\u8fd9\u4e9b\u8bbe\u7f6e\u4e0e\u8be5\u65f6\u95f4\u70b9\u7684\u914d\u7f6e\u503c\u5339\u914d\uff0c\u800c\u4e0d\u662f\u5728\u9996\u6b21\u8fd0\u884c\u65f6\u5339\u914d\u3002<\/p>\n<p>As <code>IOptionsSnapshot&lt;AppDisplaySettings&gt;<\/code> is registered as a scoped service, it\u2019s re-created at every request. If you edit the settings file and cause IConfiguration to reload, <code>IOptionsSnapshot&lt;AppDisplaySettings&gt;<\/code> shows the new values on the next request. A new AppDisplaySettings object is created with the new configuration values and is used for all future DI\u2014until you edit the file again, of course!<\/p>\n<p>\u7531\u4e8e <code>IOptionsSnapshot&lt;AppDisplaySettings&gt; <\/code>\u6ce8\u518c\u4e3a\u4f5c\u7528\u57df\u670d\u52a1\uff0c\u56e0\u6b64\u4f1a\u5728\u6bcf\u6b21\u8bf7\u6c42\u65f6\u91cd\u65b0\u521b\u5efa\u5b83\u3002\u5982\u679c\u7f16\u8f91\u8bbe\u7f6e\u6587\u4ef6\u5e76\u5bfc\u81f4 IConfiguration \u91cd\u65b0\u52a0\u8f7d\uff0c\u5219 <code>IOptionsSnapshot&lt;AppDisplaySettings&gt;<\/code> \u5c06\u5728\u4e0b\u4e00\u4e2a\u8bf7\u6c42\u4e2d\u663e\u793a\u65b0\u503c\u3002\u4f7f\u7528\u65b0\u7684\u914d\u7f6e\u503c\u521b\u5efa\u4e00\u4e2a\u65b0\u7684 AppDisplaySettings \u5bf9\u8c61\uff0c\u5e76\u5c06\u5176\u7528\u4e8e\u6240\u6709\u672a\u6765\u7684 DI \u2014 \u5f53\u7136\uff0c\u76f4\u5230\u60a8\u518d\u6b21\u7f16\u8f91\u8be5\u6587\u4ef6\u4e3a\u6b62\uff01<\/p>\n<p>Reloading your settings automatically is as simple as that: update your code to use <code>IOptionsSnapshot&lt;T&gt;<\/code> instead of <code>IOptions&lt;T&gt;<\/code> wherever you need it. But be aware that this change isn\u2019t free. You\u2019re rebinding and reconfiguring your options object with every request, which may have performance implications. In practice, reloading settings isn\u2019t common in production, so you may decide that the developer convenience isn\u2019t worth the performance impact.<\/p>\n<p>\u81ea\u52a8\u91cd\u65b0\u52a0\u8f7d\u8bbe\u7f6e\u975e\u5e38\u7b80\u5355\uff1a\u66f4\u65b0\u4ee3\u7801\u4ee5\u4f7f\u7528 <code>IOptionsSnapshot&lt;T&gt;<\/code>\u800c\u4e0d\u662f<code>IOptions&lt;T&gt;<\/code>,\u65e0\u8bba\u60a8\u9700\u8981\u4ec0\u4e48\u5730\u65b9\u3002\u4f46\u8bf7\u6ce8\u610f\uff0c\u6b64\u66f4\u6539\u4e0d\u662f\u514d\u8d39\u7684\u3002\u60a8\u6b63\u5728\u4f7f\u7528\u6bcf\u4e2a\u8bf7\u6c42\u91cd\u65b0\u7ed1\u5b9a\u548c\u91cd\u65b0\u914d\u7f6e options \u5bf9\u8c61\uff0c\u8fd9\u53ef\u80fd\u4f1a\u5bf9\u6027\u80fd\u4ea7\u751f\u5f71\u54cd\u3002\u5728\u5b9e\u8df5\u4e2d\uff0c\u91cd\u65b0\u52a0\u8f7d\u8bbe\u7f6e\u5728\u751f\u4ea7\u4e2d\u5e76\u4e0d\u5e38\u89c1\uff0c\u56e0\u6b64\u60a8\u53ef\u80fd\u4f1a\u8ba4\u4e3a\u5f00\u53d1\u4eba\u5458\u7684\u4fbf\u5229\u6027\u4e0d\u503c\u5f97\u5bf9\u6027\u80fd\u9020\u6210\u5f71\u54cd\u3002<\/p>\n<p>An important consideration in using the options pattern is the design of your POCO options classes themselves. These classes typically are simple collections of properties, but there are a few things to bear in mind so that you don\u2019t get stuck debugging why the binding seemingly hasn\u2019t worked.<\/p>\n<p>\u4f7f\u7528\u9009\u9879\u6a21\u5f0f\u7684\u4e00\u4e2a\u91cd\u8981\u8003\u8651\u56e0\u7d20\u662f POCO \u9009\u9879\u7c7b\u672c\u8eab\u7684\u8bbe\u8ba1\u3002\u8fd9\u4e9b\u7c7b\u901a\u5e38\u662f\u7b80\u5355\u7684\u5c5e\u6027\u96c6\u5408\uff0c\u4f46\u9700\u8981\u8bb0\u4f4f\u4e00\u4e9b\u4e8b\u9879\uff0c\u8fd9\u6837\u60a8\u5c31\u4e0d\u4f1a\u9677\u5165\u8c03\u8bd5\u7ed1\u5b9a\u4f3c\u4e4e\u4e0d\u8d77\u4f5c\u7528\u7684\u539f\u56e0\u3002<\/p>\n<h3>10.3.3 Designing your options classes for automatic binding<\/h3>\n<h3>10.3.3 \u4e3a\u81ea\u52a8\u7ed1\u5b9a\u8bbe\u8ba1 options \u7c7b<\/h3>\n<p>I\u2019ve already touched on some of the requirements for POCO classes to work with the <code>IOptions&lt;T&gt;<\/code> binder, but there are a few rules to remember. The first key point is that the binder creates instances of your options classes by using reflection, so your POCO options classes need to<\/p>\n<p>\u6211\u5df2\u7ecf\u8c08\u5230\u4e86 POCO \u7c7b\u4e0e <code>IOptions&lt;T&gt;<\/code> Binder \u4e00\u8d77\u4f7f\u7528\u7684\u4e00\u4e9b\u8981\u6c42\uff0c\u4f46\u6709\u4e00\u4e9b\u89c4\u5219\u9700\u8981\u8bb0\u4f4f\u3002\u7b2c\u4e00\u4e2a\u5173\u952e\u70b9\u662f Binder \u4f7f\u7528\u53cd\u5c04\u521b\u5efa\u9009\u9879\u7c7b\u7684\u5b9e\u4f8b\uff0c\u56e0\u6b64\u60a8\u7684 POCO \u9009\u9879\u7c7b\u9700\u8981<\/p>\n<ul>\n<li>\n<p>Be nonabstract<br \/>\n\u975e\u62bd\u8c61<\/p>\n<\/li>\n<li>\n<p>Have a default (public parameterless) constructor<br \/>\n\u5177\u6709\u9ed8\u8ba4 \uff08public parameterless\uff09 \u6784\u9020\u51fd\u6570<\/p>\n<\/li>\n<\/ul>\n<p>If your classes satisfy these two points, the binder will loop through all the properties on your class and bind any that it can. In the broadest sense, the binder can bind any property that<\/p>\n<p>\u5982\u679c\u60a8\u7684\u7c7b\u6ee1\u8db3\u8fd9\u4e24\u70b9\uff0c\u5219 Binder \u5c06\u904d\u5386\u7c7b\u4e0a\u7684\u6240\u6709\u5c5e\u6027\uff0c\u5e76\u7ed1\u5b9a\u5b83\u53ef\u4ee5\u7ed1\u5b9a\u7684\u4efb\u4f55\u5c5e\u6027\u3002\u4ece\u6700\u5e7f\u6cdb\u7684\u610f\u4e49\u4e0a\u8bb2\uff0cBinder \u53ef\u4ee5\u7ed1\u5b9a<\/p>\n<ul>\n<li>\n<p>Is public<br \/>\n\u662f\u516c\u5f00\u7684<\/p>\n<\/li>\n<li>\n<p>Has a getter (the binder won\u2019t write set-only properties)<br \/>\n\u5177\u6709 getter\uff08Binder \u4e0d\u4f1a\u5199\u5165\u4ec5 set-only \u5c5e\u6027\uff09<\/p>\n<\/li>\n<li>\n<p>Has a setter or, for complex types, a non-null value<br \/>\n\u5177\u6709 setter\uff0c\u6216\u8005\u5bf9\u4e8e\u590d\u6742\u7c7b\u578b\uff0c\u5177\u6709\u975e null \u503c<\/p>\n<\/li>\n<li>\n<p>Isn\u2019t an indexer<br \/>\n\u4e0d\u662f\u7d22\u5f15\u5668<\/p>\n<\/li>\n<\/ul>\n<p>Listing 10.10 shows two extensive options class with a host of different types of properties. All the properties on BindableOptions are valid to bind, and all the properties on UnbindableOptions are not.<\/p>\n<p>\u6e05\u5355 10.10 \u5c55\u793a\u4e86\u4e24\u4e2a\u6269\u5c55\u7684\u9009\u9879\u7c7b\uff0c\u5b83\u4eec\u5177\u6709\u8bb8\u591a\u4e0d\u540c\u7c7b\u578b\u7684\u5c5e\u6027\u3002BindableOptions \u4e0a\u7684\u6240\u6709\u5c5e\u6027\u90fd\u5bf9 bind \u6709\u6548\uff0c\u800c UnbindableOptions \u4e0a\u7684\u6240\u6709\u5c5e\u6027\u90fd\u4e0d\u662f\u3002<\/p>\n<p>Listing 10.10 An options class containing binding and nonbinding properties<br \/>\n\u6e05\u5355 10.10 \u5305\u542b binding \u548c nonbinding \u5c5e\u6027\u7684 options \u7c7b<\/p>\n<pre><code>public class BindableOptions\n{\n    public string String { get; set; } \u2776\n    public int Integer { get; set; } \u2776\n    public SubClass Object { get; set; } \u2776\n    public SubClass ReadOnly { get; } = new SubClass(); \u2776\n    public Dictionary&lt;string, SubClass&gt; Dictionary { get; set; } \u2777\n    public List&lt;SubClass&gt; List { get; set; } \u2777\n    public IDictionary&lt;string, SubClass&gt; IDictionary { get; set; } \u2777\n    public IEnumerable&lt;SubClass&gt; IEnumerable { get; set; } \u2777\n    public ICollection&lt;SubClass&gt; ReadOnlyCollection { get; } \u2777\n        = new List&lt;SubClass&gt;(); \u2777\n\n    public class SubClass\n    {\n    public string Value { get; set; }\n    }\n}\n\npublic class UnbindableOptions\n{\n    internal string NotPublic { get; set; } \u2778\n    public SubClass SetOnly { set =&gt; _setOnly = value; } \u2778\n    public SubClass NullReadOnly { get; } = null; \u2778\n    public SubClass NullPrivateSetter { get; private set; } = null; \u2778\n    public SubClass this[int i] { \u2778\n        get =&gt; _indexerList[i]; \u2778\n        set =&gt; _indexerList[i] = value; \u2778\n    }\n    public List&lt;SubClass&gt; NullList { get; } \u2779\n    public Dictionary&lt;int, SubClass&gt; IntegerKeys { get; set; } \u2779\n    public IEnumerable&lt;SubClass&gt; ReadOnlyEnumerable { get; } \u2779\n        = new List&lt;SubClass&gt;(); \u2779\n\n    public SubClass _setOnly = null; \u277a\n    private readonly List&lt;SubClass&gt; _indexerList \u277a\n        = new List&lt;SubClass&gt;(); \u277a\n\n    public class SubClass\n    {\n        public string Value { get; set; }\n    }\n}<\/code><\/pre>\n<p>\u2776 The binder can bind simple and complex object types, and read-only properties with<br \/>\na default.<br \/>\nBinder \u53ef\u4ee5\u5c06\u7b80\u5355\u548c\u590d\u6742\u7684\u5bf9\u8c61\u7c7b\u578b\u4ee5\u53ca\u53ea\u8bfb\u5c5e\u6027\u4e0e\u9ed8\u8ba4\u503c\u7ed1\u5b9a\u3002<\/p>\n<p>\u2777 The binder will also bind collections, including interfaces.<br \/>\nBinder \u8fd8\u5c06\u7ed1\u5b9a\u96c6\u5408\uff0c\u5305\u62ec\u63a5\u53e3\u3002<\/p>\n<p>\u2778 The binder can\u2019t bind nonpublic, set-only, null-read-only, or indexer properties.<br \/>\nBinder \u65e0\u6cd5\u7ed1\u5b9a non-public\u3001set-only\u3001null-read-only \u6216 indexer \u5c5e\u6027\u3002<\/p>\n<p>\u2779 These collection properties can\u2019t be bound.<br \/>\n\u8fd9\u4e9b\u96c6\u5408\u5c5e\u6027\u65e0\u6cd5\u7ed1\u5b9a\u3002<\/p>\n<p>\u277a The backing fields for implementing SetOnly and Indexer properties\u2014not bound<br \/>\ndirectly<br \/>\n\u7528\u4e8e\u5b9e\u73b0 SetOnly \u548c Indexer \u5c5e\u6027\u7684\u652f\u6301\u5b57\u6bb5 - \u4e0d\u76f4\u63a5\u7ed1\u5b9a<\/p>\n<p>As shown in the listing, the binder generally supports collections\u2014both implementations and interfaces. If the collection property is already initialized, the binder uses the initialized value; otherwise, the binder may be able to create the collection instance automatically. If your property implements any of the following interfaces, the binder creates a List&lt;&gt; of the appropriate type as the backing object:<\/p>\n<p>\u5982\u6e05\u5355\u6240\u793a\uff0cBinder \u901a\u5e38\u652f\u6301\u96c6\u5408\u2014 \u5305\u62ec\u5b9e\u73b0\u548c\u63a5\u53e3\u3002\u5982\u679c collection \u5c5e\u6027\u5df2\u521d\u59cb\u5316\uff0c\u5219 Binder \u5c06\u4f7f\u7528\u521d\u59cb\u5316\u7684\u503c;\u5426\u5219\uff0cBinder \u53ef\u80fd\u80fd\u591f\u81ea\u52a8\u521b\u5efa collection \u5b9e\u4f8b\u3002\u5982\u679c\u60a8\u7684\u5c5e\u6027\u5b9e\u73b0\u4ee5\u4e0b\u4efb\u4f55\u63a5\u53e3\uff0c\u5219 Binder \u4f1a\u521b\u5efa\u4e00\u4e2a List&lt;&gt; \u4f5c\u4e3a\u540e\u5907\u5bf9\u8c61\uff1a<\/p>\n<ul>\n<li><code>IReadOnlyList&lt;&gt;<\/code><\/li>\n<li><code>IReadOnlyCollection&lt;&gt;<\/code><\/li>\n<li><code>ICollection&lt;&gt;<\/code><\/li>\n<li><code>IEnumerable&lt;&gt;<\/code><\/li>\n<\/ul>\n<p><strong>Warning<\/strong> You can\u2019t bind to an <code>IEnumerable&lt;&gt;<\/code> property that has already been initialized, as this interface doesn\u2019t expose an Add function, and the binder won\u2019t replace the backing value. You can bind to an <code>IEnumerable&lt;&gt;<\/code> if you leave its initial value null.<br \/>\n<strong>\u8b66\u544a<\/strong> \u60a8\u4e0d\u80fd\u7ed1\u5b9a\u5230\u5df2\u521d\u59cb\u5316\u7684 <code>IEnumerable&lt;&gt;<\/code> \u5c5e\u6027\uff0c\u56e0\u4e3a\u6b64\u63a5\u53e3\u4e0d\u4f1a\u516c\u5f00 Add \u51fd\u6570\uff0c\u5e76\u4e14 Binder \u4e0d\u4f1a\u66ff\u6362\u540e\u5907\u503c\u3002\u5982\u679c\u4fdd\u7559 IEnumerable \u7684\u521d\u59cb\u503c&lt;&gt;\u5219\u53ef\u4ee5\u7ed1\u5b9a\u5230 IEnumerable null \u7684.<\/p>\n<p>Similarly, the binder creates a <code>Dictionary&lt;,&gt;<\/code> as the backing field for properties with dictionary interfaces as long as they use string keys:<br \/>\n\u540c\u6837\uff0cBinder \u4f1a\u521b\u5efa\u4e00\u4e2a <code>Dictionary&lt;\uff0c&gt;<\/code> \u4f5c\u4e3a\u5177\u6709\u5b57\u5178\u63a5\u53e3\u7684\u5c5e\u6027\u7684\u540e\u5907\u5b57\u6bb5\uff0c\u53ea\u8981\u5b83\u4eec\u4f7f\u7528 string\u3001enum \u6216 integer\uff08int\u3001short\u3001byte \u7b49\uff09\u952e\uff1a<\/p>\n<ul>\n<li>IDictionary&lt;string,&gt;<\/li>\n<li>IReadOnlyDictionary&lt;string,&gt;<\/li>\n<\/ul>\n<p><strong>Warning<\/strong> You can\u2019t bind dictionaries with non-string keys, such as int. For examples of binding collection types, see the associated source code for this book.<br \/>\n<strong>\u8b66\u544a<\/strong> \u60a8\u4e0d\u80fd\u7ed1\u5b9a\u4f7f\u7528\u975e\u5b57\u7b26\u4e32\u6216\u975e\u6574\u6570\u952e\u7684\u5b57\u5178\uff0c\u4f8b\u5982 custom classes \u6216 double\u3002\u6709\u5173\u7ed1\u5b9a\u96c6\u5408\u7c7b\u578b\u7684\u793a\u4f8b\uff0c\u8bf7\u53c2\u9605\u672c\u4e66\u7684\u76f8\u5173\u6e90\u4ee3\u7801\u3002<\/p>\n<p>Clearly, there are quite a few nuances here, but if you stick to the simple cases from the preceding example, you\u2019ll be fine. Be sure to check for typos in your JSON files! You could also consider using explicit options validation, as described in this post: <a href=\"http:\/\/mng.bz\/jPjr\">http:\/\/mng.bz\/jPjr<\/a>.<\/p>\n<p>\u663e\u7136\uff0c\u8fd9\u91cc\u6709\u5f88\u591a\u7ec6\u5fae\u5dee\u522b\uff0c\u4f46\u5982\u679c\u4f60\u575a\u6301\u4f7f\u7528\u524d\u9762\u793a\u4f8b\u4e2d\u7684\u7b80\u5355\u60c5\u51b5\uff0c\u4f60\u4f1a\u6ca1\u4e8b\u7684\u3002\u8bf7\u52a1\u5fc5\u68c0\u67e5 JSON \u6587\u4ef6\u4e2d\u662f\u5426\u6709\u62fc\u5199\u9519\u8bef\uff01\u4f60\u4e5f\u53ef\u4ee5\u8003\u8651\u4f7f\u7528\u663e\u5f0f\u9009\u9879\u9a8c\u8bc1\uff0c\u5982\u672c\u6587\u6240\u8ff0\uff1a<a href=\"http:\/\/mng.bz\/jPjr\">http:\/\/mng.bz\/jPjr<\/a>\u3002<\/p>\n<p><strong>Tip<\/strong> The options pattern is most commonly used to bind POCO classes to configuration, but you can also configure your strongly typed settings classes in code by providing a lambda to the Configure function;, as in services.Configure<TestOptions>(opt =&gt; opt.Value = true).<br \/>\n<strong>\u63d0\u793a<\/strong> \u9009\u9879\u6a21\u5f0f\u6700\u5e38\u7528\u4e8e\u5c06 POCO \u7c7b\u7ed1\u5b9a\u5230\u914d\u7f6e\uff0c\u4f46\u60a8\u4e5f\u53ef\u4ee5\u901a\u8fc7\u5411 Configure \u51fd\u6570\u63d0\u4f9b lambda \u6765\u5728\u4ee3\u7801\u4e2d\u914d\u7f6e\u5f3a\u7c7b\u578b\u8bbe\u7f6e\u7c7b\uff0c\u5c31\u50cf\u5728\u670d\u52a1\u4e2d\u4e00\u6837.Configure<TestOptions>\uff08opt =&gt; opt.\u503c = true\uff09\u3002<\/p>\n<p>The Options pattern is used throughout ASP.NET Core, but not everyone is a fan. In section 10.3.4 you\u2019ll see how to use strongly typed settings and the configuration binder without the Options pattern.<br \/>\nOptions \u6a21\u5f0f\u5728\u6574\u4e2a ASP.NET Core \u4e2d\u4f7f\u7528\uff0c\u4f46\u5e76\u975e\u6bcf\u4e2a\u4eba\u90fd\u662f\u7c89\u4e1d\u3002\u5728 Section 10.3.4 \u4e2d\uff0c\u60a8\u5c06\u770b\u5230\u5982\u4f55\u4f7f\u7528\u5f3a\u7c7b\u578b\u8bbe\u7f6e\u548c\u6ca1\u6709 Options \u6a21\u5f0f\u7684\u914d\u7f6e Binder\u3002<\/p>\n<h3>10.3.4 Binding strongly typed settings without the IOptions interface<\/h3>\n<h3>10.3.4 \u5728\u6ca1\u6709 IOptions \u63a5\u53e3\u7684\u60c5\u51b5\u4e0b\u7ed1\u5b9a\u5f3a\u7c7b\u578b\u8bbe\u7f6e<\/h3>\n<p>The IOptions interface is canonical in ASP.NET Core; it\u2019s used by the core ASP.NET Core libraries and has various convenience functions for binding strongly typed settings, as you\u2019ve already seen. In many cases, however, the IOptions interface doesn\u2019t give many benefits for consumers of the strongly typed settings objects. Services must take a dependency on the IOptions interface but then immediately extract the real object by calling <code>IOptions&lt;T&gt;<\/code>.Value. This situation can be especially annoying if you\u2019re building a reusable library that isn\u2019t inherently tied to ASP.NET Core, as you must expose the <code>IOptions&lt;T&gt;<\/code> interface in all your public APIs.<\/p>\n<p>IOptions \u63a5\u53e3\u5728 ASP.NET Core \u4e2d\u662f\u89c4\u8303\u7684;\u6b63\u5982\u60a8\u5df2\u7ecf\u770b\u5230\u7684\uff0c\u5b83\u7531 Core ASP.NET Core \u5e93\u4f7f\u7528\uff0c\u5e76\u4e14\u5177\u6709\u7528\u4e8e\u7ed1\u5b9a\u5f3a\u7c7b\u578b\u8bbe\u7f6e\u7684\u5404\u79cd\u4fbf\u6377\u51fd\u6570\u3002\u4f46\u662f\uff0c\u5728\u8bb8\u591a\u60c5\u51b5\u4e0b\uff0cIOptions \u63a5\u53e3\u5e76\u6ca1\u6709\u4e3a\u5f3a\u7c7b\u578b\u8bbe\u7f6e\u5bf9\u8c61\u7684\u4f7f\u7528\u8005\u5e26\u6765\u5f88\u591a\u597d\u5904\u3002\u670d\u52a1\u5fc5\u987b\u4f9d\u8d56\u4e8e IOptions \u63a5\u53e3\uff0c\u4f46\u968f\u540e\u901a\u8fc7\u8c03\u7528 <code>IOptions&lt;T&gt;<\/code> \u7acb\u5373\u63d0\u53d6\u771f\u5b9e\u5bf9\u8c61\u3002\u503c\u3002\u5982\u679c\u60a8\u6b63\u5728\u6784\u5efa\u4e00\u4e2a\u672c\u8d28\u4e0a\u4e0d\u7ed1\u5b9a\u5230 ASP.NET Core \u7684\u53ef\u91cd\u7528\u5e93\uff0c\u5219\u8fd9\u79cd\u60c5\u51b5\u53ef\u80fd\u5c24\u5176\u4ee4\u4eba\u70e6\u607c\uff0c\u56e0\u4e3a\u60a8\u5fc5\u987b\u5728\u6240\u6709\u516c\u5171 API \u4e2d\u516c\u5f00 <code>IOptions&lt;T&gt;<\/code> \u63a5\u53e3\u3002<\/p>\n<p>Luckily, the configuration binder that maps IConfiguration objects to strongly typed settings objects isn\u2019t inherently tied to IOptions. Listing 10.11 shows how you can bind a strongly typed settings object to a configuration section manually, register it with the DI container, and inject the MapSettings object directly into a handler or service without the additional ceremony required to use IOptions<MapSettings>.<\/p>\n<p>\u5e78\u8fd0\u7684\u662f\uff0c\u5c06 IConfiguration \u5bf9\u8c61\u6620\u5c04\u5230\u5f3a\u7c7b\u578b\u8bbe\u7f6e\u5bf9\u8c61\u7684\u914d\u7f6e\u7ed1\u5b9a\u5668\u672c\u8eab\u5e76\u4e0d\u4e0e IOptions \u76f8\u5173\u8054\u3002\u6e05\u5355 10.11 \u5c55\u793a\u4e86\u5982\u4f55\u624b\u52a8\u5c06\u5f3a\u7c7b\u578b\u8bbe\u7f6e\u5bf9\u8c61\u7ed1\u5b9a\u5230\u914d\u7f6e\u90e8\u5206\uff0c\u5c06\u5176\u6ce8\u518c\u5230 DI \u5bb9\u5668\u4e2d\uff0c\u5e76\u5c06 MapSettings \u5bf9\u8c61\u76f4\u63a5\u6ce8\u5165\u5904\u7406\u7a0b\u5e8f\u6216\u670d\u52a1\u4e2d\uff0c\u800c\u65e0\u9700\u4f7f\u7528 <code>IOptions&lt;MapSettings&gt;<\/code> \u6240\u9700\u7684\u989d\u5916\u4eea\u5f0f\u3002<\/p>\n<p>Listing 10.11 Configuring strongly typed settings without IOptions in Program.cs<br \/>\n\u6e05\u5355 10.11 \u914d\u7f6e\u6ca1\u6709Program.cs \u4e2d\u7684 IOptions<\/p>\n<pre><code>WebApplicationBuilder builder = WebApplication.CreateBuilder(args);\n\nvar settings = new MapSettings (); \u2776\nbuilder.Configuration.GetSection(&quot;MapSettings&quot;).Bind(settings); \u2777\nbuilder.Services.AddSingleton(settings); \u2778\n\nWebApplication app = builder.Build();\n\napp.MapGet(&quot;\/&quot;, (MapSettings mapSettings) =&gt; mapSettings); \u2779\n\napp.Run();<\/code><\/pre>\n<p>\u2776 Creates a new instance of the MapSettings object<br \/>\n\u521b\u5efa MapSettings \u5bf9\u8c61\u7684\u65b0\u5b9e\u4f8b<br \/>\n\u2777 Binds the MapSettings section in IConfiguration to the settings object<br \/>\n\u5c06 IConfiguration \u4e2d\u7684 MapSettings \u90e8\u5206\u7ed1\u5b9a\u5230\u8bbe\u7f6e\u5bf9\u8c61<br \/>\n\u2778 Registers the settings object as a singleton<br \/>\n\u5c06 settings \u5bf9\u8c61\u6ce8\u518c\u4e3a\u5355\u4f8b<br \/>\n\u2779 Injects the MapSettings object directly using DI<br \/>\n\u4f7f\u7528 DI \u76f4\u63a5\u6ce8\u5165 MapSettings \u5bf9\u8c61<\/p>\n<p>Alternatively, you can register the IOptions type in the DI container but then use a lambda to additionally register MapSettings as a singleton so it can be directly injected, as shown in listing 10.12.<\/p>\n<p>\u6216\u8005\uff0c\u4f60\u53ef\u4ee5\u5728 DI \u5bb9\u5668\u4e2d\u6ce8\u518c IOptions \u7c7b\u578b\uff0c\u7136\u540e\u4f7f\u7528 lambda \u53e6\u5916\u5c06 MapSettings \u6ce8\u518c\u4e3a\u5355\u4f8b\uff0c\u4ee5\u4fbf\u53ef\u4ee5\u76f4\u63a5\u6ce8\u5165\uff0c\u5982\u6e05\u5355 10.12 \u6240\u793a\u3002<\/p>\n<p>Listing 10.12 Configuring strongly typed settings for direct injection<br \/>\n\u793a\u4f8b 10.12 \u4e3a\u76f4\u63a5\u6ce8\u5165\u914d\u7f6e\u5f3a\u7c7b\u578b\u8bbe\u7f6e<\/p>\n<pre><code>WebApplicationBuilder builder = WebApplication.CreateBuilder(args);\n\nbuilder.Services.Configure&lt;MapSettings&gt;( \u2776\n    builder.Configuration.GetSection(&quot;MapSettings&quot;)); \u2776\nbuilder.Services.AddSingleton(provider =&gt; \u2777\n    provider.GetRequiredService&lt;IOptions&lt;MapSettings&gt;&gt;().Value); \u2777\n\nWebApplication app = builder.Build();\n\napp.MapGet(&quot;\/&quot;, (MapSettings mapSettings) =&gt; mapSettings); \u2778\n\napp.Run();<\/code><\/pre>\n<p>\u2776 Configures the IOptions as normal<br \/>\n\u6b63\u5e38\u914d\u7f6e IOptions<br \/>\n\u2777 Registers the MapSettings object in DI by delegating to the IOptions registration<br \/>\n\u901a\u8fc7\u59d4\u6258 IOptions \u6ce8\u518c\uff0c\u5728 DI \u4e2d\u6ce8\u518c MapSettings \u5bf9\u8c61<br \/>\n\u2778 Injects the MapSettings object directly DI<br \/>\n\u76f4\u63a5\u6ce8\u5165 MapSettings \u5bf9\u8c61 DI<\/p>\n<p>If you use either of these approaches, you won\u2019t benefit from the ability to reload strongly typed settings without further work or from some of the more advanced uses of IOptions, but in most cases, that\u2019s not a big problem. I\u2019m a fan of these approaches generally, but as always, consider what you\u2019re losing before adopting them wholeheartedly.<\/p>\n<p>\u5982\u679c\u4f7f\u7528\u8fd9\u4e24\u79cd\u65b9\u6cd5\u4e2d\u7684\u4efb\u4f55\u4e00\u79cd\uff0c\u5219\u4e0d\u4f1a\u4ece\u65e0\u9700\u8fdb\u4e00\u6b65\u5de5\u4f5c\u5373\u53ef\u91cd\u65b0\u52a0\u8f7d\u5f3a\u7c7b\u578b\u8bbe\u7f6e\u7684\u80fd\u529b\u4e2d\u53d7\u76ca\uff0c\u4e5f\u4e0d\u4f1a\u53d7\u76ca\u4e8e IOptions \u7684\u4e00\u4e9b\u66f4\u9ad8\u7ea7\u7684\u7528\u6cd5\uff0c\u4f46\u5728\u5927\u591a\u6570\u60c5\u51b5\u4e0b\uff0c\u8fd9\u4e0d\u662f\u4e00\u4e2a\u5927\u95ee\u9898\u3002\u6211\u901a\u5e38\u662f\u8fd9\u4e9b\u65b9\u6cd5\u7684\u7c89\u4e1d\uff0c\u4f46\u4e0e\u5f80\u5e38\u4e00\u6837\uff0c\u5728\u5168\u5fc3\u5168\u610f\u91c7\u7528\u5b83\u4eec\u4e4b\u524d\uff0c\u8bf7\u8003\u8651\u4e00\u4e0b\u4f60\u5931\u53bb\u4e86\u4ec0\u4e48\u3002<\/p>\n<p><strong>Tip<\/strong> In chapter 31 I show one such advanced scenario in which you configure an IOptions object using services in your DI container. For other scenarios, see Microsoft\u2019s \u201cOptions pattern in ASP.NET Core\u201d documentation at <a href=\"http:\/\/mng.bz\/DR7y\">http:\/\/mng.bz\/DR7y<\/a>, or see the various IOptions posts on my blog, such as this one: <a href=\"http:\/\/mng.bz\/l1Aj\">http:\/\/mng.bz\/l1Aj<\/a>.<br \/>\n<strong>\u63d0\u793a<\/strong> \u5728\u7b2c 31 \u7ae0\u4e2d\uff0c\u6211\u5c06\u5c55\u793a\u4e00\u4e2a\u8fd9\u6837\u7684\u9ad8\u7ea7\u573a\u666f\uff0c\u5728\u8be5\u573a\u666f\u4e2d\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528 DI \u5bb9\u5668\u4e2d\u7684\u670d\u52a1\u914d\u7f6e IOptions \u5bf9\u8c61\u3002\u5bf9\u4e8e\u5176\u4ed6\u65b9\u6848\uff0c\u8bf7\u53c2\u9605 <a href=\"http:\/\/mng.bz\/DR7y\">http:\/\/mng.bz\/DR7y<\/a> \u4e0a Microsoft \u7684\u201cASP.NET Core \u4e2d\u7684\u9009\u9879\u6a21\u5f0f\u201d\u6587\u6863\uff0c\u6216\u67e5\u770b\u6211\u535a\u5ba2\u4e0a\u7684\u5404\u79cd IOptions \u5e16\u5b50\uff0c\u4f8b\u5982\uff1a<a href=\"http:\/\/mng.bz\/l1Aj\">http:\/\/mng.bz\/l1Aj<\/a>\u3002<\/p>\n<p>That brings us to the end of this section on strongly typed settings. In section 10.4 we\u2019ll look at how you can change your settings dynamically at runtime, based on the environment in which your app is running.<\/p>\n<p>\u8fd9\u5c06\u6211\u4eec\u5e26\u5230\u672c\u8282\u5173\u4e8e\u5f3a\u7c7b\u578b\u8bbe\u7f6e\u7684\u7ed3\u5c3e\u3002\u5728 Section 10.4 \u4e2d\uff0c\u6211\u4eec\u5c06\u4e86\u89e3\u5982\u4f55\u6839\u636e\u5e94\u7528\u7a0b\u5e8f\u7684\u8fd0\u884c\u73af\u5883\u5728\u8fd0\u884c\u65f6\u52a8\u6001\u66f4\u6539\u8bbe\u7f6e\u3002<\/p>\n<h2>10.4 Configuring an application for multiple environments<\/h2>\n<h2>10.4  \u4e3a\u591a\u4e2a\u73af\u5883\u914d\u7f6e\u5e94\u7528\u7a0b\u5e8f<\/h2>\n<p>In this section you\u2019ll learn about hosting environments in ASP.NET Core. You\u2019ll learn how to set and determine which environment an application is running in and how to change which configuration values are used, based on the environment. Using environments lets you switch easily among different sets of configuration values in production compared with development, for example.<\/p>\n<p>\u5728\u672c\u8282\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3\u5982\u4f55\u5728 ASP.NET Core \u4e2d\u6258\u7ba1\u73af\u5883\u3002\u60a8\u5c06\u5b66\u4e60\u5982\u4f55\u8bbe\u7f6e\u548c\u786e\u5b9a\u5e94\u7528\u7a0b\u5e8f\u5728\u54ea\u4e2a\u73af\u5883\u4e2d\u8fd0\u884c\uff0c\u4ee5\u53ca\u5982\u4f55\u6839\u636e\u73af\u5883\u66f4\u6539\u4f7f\u7528\u7684\u914d\u7f6e\u503c\u3002\u4f8b\u5982\uff0c\u4e0e\u5f00\u53d1\u76f8\u6bd4\uff0c\u4f7f\u7528\u73af\u5883\u53ef\u4ee5\u8ba9\u60a8\u5728\u751f\u4ea7\u4e2d\u7684\u4e0d\u540c\u914d\u7f6e\u503c\u96c6\u4e4b\u95f4\u8f7b\u677e\u5207\u6362\u3002<\/p>\n<p>Any application that makes it to production will likely have to run in multiple environments. If you\u2019re building an application with database access, for example, you\u2019ll probably have a small database running on your machine that you use for development. In production, you\u2019ll have a completely different database running on a server somewhere else.<\/p>\n<p>\u4efb\u4f55\u8fdb\u5165\u751f\u4ea7\u73af\u5883\u7684\u5e94\u7528\u7a0b\u5e8f\u90fd\u53ef\u80fd\u5fc5\u987b\u5728\u591a\u4e2a\u73af\u5883\u4e2d\u8fd0\u884c\u3002\u4f8b\u5982\uff0c\u5982\u679c\u60a8\u6b63\u5728\u6784\u5efa\u5177\u6709\u6570\u636e\u5e93\u8bbf\u95ee\u6743\u9650\u7684\u5e94\u7528\u7a0b\u5e8f\uff0c\u5219\u60a8\u7684\u8ba1\u7b97\u673a\u4e0a\u53ef\u80fd\u4f1a\u8fd0\u884c\u4e00\u4e2a\u7528\u4e8e\u5f00\u53d1\u7684\u5c0f\u578b\u6570\u636e\u5e93\u3002\u5728\u751f\u4ea7\u73af\u5883\u4e2d\uff0c\u60a8\u5c06\u5728\u5176\u4ed6\u4f4d\u7f6e\u7684\u670d\u52a1\u5668\u4e0a\u8fd0\u884c\u4e00\u4e2a\u5b8c\u5168\u4e0d\u540c\u7684\u6570\u636e\u5e93\u3002<\/p>\n<p>Another common requirement is to have different amounts of logging depending on where your app is running. In development, it\u2019s great to generate lots of logs, which help with debugging, but when you get to production, too many logs can be overwhelming. You\u2019ll want to log warnings, errors, and maybe information-level logs, but definitely not debug-level logs!<\/p>\n<p>\u53e6\u4e00\u4e2a\u5e38\u89c1\u8981\u6c42\u662f\uff0c\u6839\u636e\u5e94\u7528\u7a0b\u5e8f\u7684\u8fd0\u884c\u4f4d\u7f6e\uff0c\u5177\u6709\u4e0d\u540c\u7684\u65e5\u5fd7\u8bb0\u5f55\u91cf\u3002\u5728\u5f00\u53d1\u4e2d\uff0c\u751f\u6210\u5927\u91cf\u65e5\u5fd7\u975e\u5e38\u6709\u7528\uff0c\u8fd9\u6709\u52a9\u4e8e\u8c03\u8bd5\uff0c\u4f46\u662f\u5f53\u60a8\u8fdb\u5165\u751f\u4ea7\u73af\u5883\u65f6\uff0c\u8fc7\u591a\u7684\u65e5\u5fd7\u53ef\u80fd\u4f1a\u8ba9\u4eba\u4e0d\u77e5\u6240\u63aa\u3002\u60a8\u9700\u8981\u8bb0\u5f55\u8b66\u544a\u3001\u9519\u8bef\uff0c\u4e5f\u8bb8\u8fd8\u9700\u8981\u4fe1\u606f\u7ea7\u65e5\u5fd7\uff0c\u4f46\u7edd\u5bf9\u4e0d\u662f\u8c03\u8bd5\u7ea7\u65e5\u5fd7\uff01<\/p>\n<p>To handle these requirements, you need to make sure that your app loads different configuration values depending on the environment it\u2019s running in: load the production database connection string when in production, and so on. You need to consider three aspects:<\/p>\n<p>\u8981\u6ee1\u8db3\u8fd9\u4e9b\u8981\u6c42\uff0c\u60a8\u9700\u8981\u786e\u4fdd\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u6839\u636e\u5176\u8fd0\u884c\u73af\u5883\u52a0\u8f7d\u4e0d\u540c\u7684\u914d\u7f6e\u503c\uff1a\u5728\u751f\u4ea7\u73af\u5883\u4e2d\u52a0\u8f7d\u751f\u4ea7\u6570\u636e\u5e93\u8fde\u63a5\u5b57\u7b26\u4e32\uff0c\u4f9d\u6b64\u7c7b\u63a8\u3002\u60a8\u9700\u8981\u8003\u8651\u4e09\u4e2a\u65b9\u9762\uff1a<\/p>\n<ul>\n<li>\n<p>How your app identifies the environment it\u2019s running in<br \/>\n\u60a8\u7684\u5e94\u7528\u5982\u4f55\u8bc6\u522b\u5b83\u6b63\u5728\u8fd0\u884c\u7684\u73af\u5883<\/p>\n<\/li>\n<li>\n<p>How you load different configuration values based on the current environment<br \/>\n\u5982\u4f55\u6839\u636e\u5f53\u524d\u73af\u5883\u52a0\u8f7d\u4e0d\u540c\u7684\u914d\u7f6e\u503c<\/p>\n<\/li>\n<li>\n<p>How to change the environment for a particular machine<br \/>\n\u5982\u4f55\u66f4\u6539\u7279\u5b9a\u8ba1\u7b97\u673a\u7684\u73af\u5883<\/p>\n<\/li>\n<\/ul>\n<p>This section tackles these aspects in turn so that you can easily tell your development machine apart from your production servers and act accordingly.<\/p>\n<p>\u672c\u8282\u4f9d\u6b21\u5904\u7406\u8fd9\u4e9b\u65b9\u9762\uff0c\u4ee5\u4fbf\u60a8\u53ef\u4ee5\u8f7b\u677e\u5730\u5c06\u5f00\u53d1\u8ba1\u7b97\u673a\u4e0e\u751f\u4ea7\u670d\u52a1\u5668\u533a\u5206\u5f00\u6765\uff0c\u5e76\u91c7\u53d6\u76f8\u5e94\u7684\u63aa\u65bd\u3002<\/p>\n<h3>10.4.1 Identifying the hosting environment<\/h3>\n<h3>10.4.1 \u786e\u5b9a\u6258\u7ba1\u73af\u5883<\/h3>\n<p>When you create a WebApplicationBuilder instance in Program.cs, it automatically sets up the hosting environment for your application. By default, WebApplicationBuilder uses, perhaps unsurprisingly, an environment variable to identify the current environment. The WebApplicationBuilder looks for a magic environment variable called ASPNETCORE_ENVIRONMENT, uses it to create an IHostEnvironment object, and exposes it as WebApplicationBuilder.Environment.<\/p>\n<p>\u5f53\u60a8\u5728 Program.cs \u4e2d\u521b\u5efa WebApplicationBuilder \u5b9e\u4f8b\u65f6\uff0c\u5b83\u4f1a\u81ea\u52a8\u4e3a\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u8bbe\u7f6e\u6258\u7ba1\u73af\u5883\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cWebApplicationBuilder \u4f7f\u7528\u73af\u5883\u53d8\u91cf\u6765\u6807\u8bc6\u5f53\u524d\u73af\u5883\uff0c\u8fd9\u4e5f\u8bb8\u4e0d\u8db3\u4e3a\u5947\u3002WebApplicationBuilder \u67e5\u627e\u4e00\u4e2a\u540d\u4e3a ASPNETCORE_ENVIRONMENT \u7684\u795e\u5947\u73af\u5883\u53d8\u91cf\uff0c\u4f7f\u7528\u5b83\u6765\u521b\u5efa\u4e00\u4e2aIHostEnvironment \u5bf9\u8c61\uff0c\u5e76\u5c06\u5176\u516c\u5f00\u4e3aWebApplicationBuilder.Environment \u7684 Web \u5e94\u7528\u7a0b\u5e8f\u3002<\/p>\n<p><strong>Note<\/strong> You can use either the DOTNET_ENVIRONMENT or ASPNETCORE<em>ENVIRONMENT environment variable. The ASPNETCORE<\/em> value overrides the DOTNET<em> value if both are set. I use the ASPNETCORE<\/em> version throughout this book.<br \/>\n<strong>\u6ce8\u610f<\/strong> \u60a8\u53ef\u4ee5\u4f7f\u7528 DOTNET_ENVIRONMENT \u6216 ASPNETCORE<em>ENVIRONMENT \u73af\u5883\u53d8\u91cf\u3002\u5982\u679c\u540c\u65f6\u8bbe\u7f6e\u4e86\u4e24\u8005\uff0c\u5219 ASPNETCORE<\/em> \u503c\u5c06\u8986\u76d6 DOTNET_ \u503c\u3002\u6211\u5728\u672c\u4e66\u4e2d\u90fd\u4f7f\u7528ASPNETCORE_\u7248\u672c\u3002<\/p>\n<p>The IHostEnvironment interface exposes several useful properties about the running context of your app. The ContentRootPath property, for example, tells the application in which directory it can find any configuration files, such as appsettings.json. This folder is typically the one in which the application is running.<\/p>\n<p>IHostEnvironment \u63a5\u53e3\u516c\u5f00\u4e86\u6709\u5173\u5e94\u7528\u7a0b\u5e8f\u8fd0\u884c\u4e0a\u4e0b\u6587\u7684\u51e0\u4e2a\u6709\u7528\u5c5e\u6027\u3002\u4f8b\u5982\uff0cContentRootPath \u5c5e\u6027\u544a\u8bc9\u5e94\u7528\u7a0b\u5e8f\u5b83\u53ef\u4ee5\u5728\u54ea\u4e2a\u76ee\u5f55\u4e2d\u627e\u5230\u4efb\u4f55\u914d\u7f6e\u6587\u4ef6\uff0c\u6bd4\u5982 appsettings.json\u3002\u6b64\u6587\u4ef6\u5939\u901a\u5e38\u662f\u8fd0\u884c\u5e94\u7528\u7a0b\u5e8f\u7684\u6587\u4ef6\u5939\u3002<\/p>\n<p><strong>TIP<\/strong> \u2003ContentRootPath is not where you store static files that the browser can access directly; that\u2019s the WebRootPath, typically wwwroot. WebRootPath is also exposed on the Environment property via the IWebHostEnvironment interface.<br \/>\n<strong>\u63d0\u793a<\/strong> ContentRootPath \u4e0d\u662f\u5b58\u50a8\u6d4f\u89c8\u5668\u53ef\u4ee5\u76f4\u63a5\u8bbf\u95ee\u7684\u9759\u6001\u6587\u4ef6\u7684\u4f4d\u7f6e;\u5373 WebRootPath\uff0c\u901a\u5e38\u4e3a wwwroot\u3002WebRootPath \u8fd8\u901a\u8fc7 IWebHostEnvironment \u63a5\u53e3\u5728 Environment \u5c5e\u6027\u4e0a\u516c\u5f00\u3002<\/p>\n<p>The IHostEnvironment.EnvironmentName property is what interests us in this section. It\u2019s set to the value of the ASPNETCORE_ENVIRONMENT environment variable, so it can be any value, but you should stick to three commonly used values in most cases:<\/p>\n<p>IHostEnvironment.EnvironmentName \u5c5e\u6027\u662f\u672c\u8282\u4e2d\u6211\u4eec\u611f\u5174\u8da3\u7684\u5185\u5bb9\u3002\u5b83\u8bbe\u7f6e\u4e3a ASPNETCORE_ENVIRONMENT \u73af\u5883\u53d8\u91cf\u7684\u503c\uff0c\u56e0\u6b64\u5b83\u53ef\u4ee5\u662f\u4efb\u4f55\u503c\uff0c\u4f46\u5728\u5927\u591a\u6570\u60c5\u51b5\u4e0b\uff0c\u60a8\u5e94\u8be5\u575a\u6301\u4f7f\u7528\u4e09\u4e2a\u5e38\u7528\u7684\u503c\uff1a<\/p>\n<ul>\n<li>&quot;Development&quot; \u5f00\u53d1<\/li>\n<li>&quot;Staging&quot; \u6682\u5b58<\/li>\n<li>&quot;Production&quot; \u751f\u4ea7<\/li>\n<\/ul>\n<p>ASP.NET Core includes several helper methods for working with these three values, so you\u2019ll have an easier time if you stick to them. In particular, whenever you\u2019re testing whether your app is running in a particular environment, you should use one of the following extension methods:<\/p>\n<p>ASP.NET Core \u5305\u542b\u591a\u4e2a\u7528\u4e8e\u5904\u7406\u8fd9\u4e09\u4e2a\u503c\u7684\u5e2e\u52a9\u7a0b\u5e8f\u65b9\u6cd5\uff0c\u56e0\u6b64\uff0c\u5982\u679c\u575a\u6301\u4f7f\u7528\u5b83\u4eec\uff0c\u60a8\u5c06\u4f1a\u66f4\u8f7b\u677e\u3002\u5177\u4f53\u800c\u8a00\uff0c\u6bcf\u5f53\u6d4b\u8bd5\u5e94\u7528\u7a0b\u5e8f\u662f\u5426\u5728\u7279\u5b9a\u73af\u5883\u4e2d\u8fd0\u884c\u65f6\uff0c\u90fd\u5e94\u4f7f\u7528\u4ee5\u4e0b\u6269\u5c55\u65b9\u6cd5\u4e4b\u4e00\uff1a<\/p>\n<ul>\n<li>IHostEnvironment.IsDevelopment()<\/li>\n<li>IHostEnvironment.IsStaging()<\/li>\n<li>IHostEnvironment.IsProduction()<\/li>\n<li>IHostEnvironment.IsEnvironment(string environmentName)<\/li>\n<\/ul>\n<p>All these methods make sure that they do case-insensitive checks of the environment variable, so you won\u2019t get any wonky errors at runtime if you don\u2019t capitalize the environment variable value.<\/p>\n<p>\u6240\u6709\u8fd9\u4e9b\u65b9\u6cd5\u90fd\u786e\u4fdd\u5b83\u4eec\u5bf9\u73af\u5883\u53d8\u91cf\u6267\u884c\u4e0d\u533a\u5206\u5927\u5c0f\u5199\u7684\u68c0\u67e5\uff0c\u56e0\u6b64\u5982\u679c\u4e0d\u5c06\u73af\u5883\u53d8\u91cf\u503c\u5927\u5199\uff0c\u5728\u8fd0\u884c\u65f6\u4e0d\u4f1a\u6536\u5230\u4efb\u4f55\u4e0d\u7a33\u5b9a\u7684\u9519\u8bef\u3002<\/p>\n<p><strong>Tip<\/strong> Where possible, use the IHostEnvironment extension methods instead of direct string comparison with EnvironmentName, as the methods provide case-insensitive matching.<br \/>\n<strong>\u63d0\u793a<\/strong> \u5982\u679c\u53ef\u80fd\uff0c\u8bf7\u4f7f\u7528 IHostEnvironment \u6269\u5c55\u65b9\u6cd5\uff0c\u800c\u4e0d\u662f\u76f4\u63a5\u4e0e EnvironmentName \u8fdb\u884c\u5b57\u7b26\u4e32\u6bd4\u8f83\uff0c\u56e0\u4e3a\u8fd9\u4e9b\u65b9\u6cd5\u63d0\u4f9b\u4e0d\u533a\u5206\u5927\u5c0f\u5199\u7684\u5339\u914d\u3002<\/p>\n<p>IHostEnvironment doesn\u2019t do anything other than expose the details of your current environment, but you can use it in various ways. In chapter 4 you saw that WebApplication adds the DeveloperExceptionMiddleware to your middleware pipeline only in the development environment. Now you know where WebApplication was getting its information about the environment: IHostEnvironment.<\/p>\n<p>IHostEnvironment \u9664\u4e86\u516c\u5f00\u5f53\u524d\u73af\u5883\u7684\u8be6\u7ec6\u4fe1\u606f\u5916\uff0c\u4e0d\u6267\u884c\u4efb\u4f55\u5176\u4ed6\u4f5c\uff0c\u4f46\u60a8\u53ef\u4ee5\u901a\u8fc7\u591a\u79cd\u65b9\u5f0f\u4f7f\u7528\u5b83\u3002\u5728\u7b2c 4 \u7ae0\u4e2d\uff0c\u60a8\u770b\u5230 WebApplication \u4ec5\u5728\u5f00\u53d1\u73af\u5883\u4e2d\u5c06 DeveloperExceptionMiddleware \u6dfb\u52a0\u5230\u60a8\u7684\u4e2d\u95f4\u4ef6\u7ba1\u9053\u4e2d\u3002\u73b0\u5728\uff0c\u60a8\u77e5\u9053 WebApplication \u4ece\u4f55\u5904\u83b7\u53d6\u6709\u5173\u73af\u5883\u7684\u4fe1\u606f\uff1aIHostEnvironment\u3002<\/p>\n<p>You can use a similar approach to customize which configuration values you load at runtime by loading different files when running in development versus production. This approach is common; it\u2019s included out of the box in most ASP.NET Core templates and by default when you use the default ConfigurationManager included with WebApplicationBuilder.<\/p>\n<p>\u60a8\u53ef\u4ee5\u4f7f\u7528\u7c7b\u4f3c\u7684\u65b9\u6cd5\u6765\u81ea\u5b9a\u4e49\u5728\u8fd0\u884c\u65f6\u52a0\u8f7d\u7684\u914d\u7f6e\u503c\uff0c\u65b9\u6cd5\u662f\u5728\u5728\u5f00\u53d1\u73af\u5883\u4e2d\u8fd0\u884c\u4e0e\u751f\u4ea7\u73af\u5883\u3002\u8fd9\u79cd\u65b9\u6cd5\u5f88\u5e38\u89c1;\u5b83\u5728\u5927\u591a\u6570 ASP.NET Core \u6a21\u677f\u4e2d\u90fd\u662f\u5f00\u7bb1\u5373\u7528\u7684\uff0c\u5e76\u4e14\u5728\u60a8\u4f7f\u7528 WebApplicationBuilder \u4e2d\u5305\u542b\u7684\u9ed8\u8ba4 ConfigurationManager \u65f6\u9ed8\u8ba4\u5305\u542b\u3002<\/p>\n<h3>10.4.2 Loading environment-specific configuration files<\/h3>\n<h3>10.4.2 \u52a0\u8f7d\u7279\u5b9a\u4e8e\u73af\u5883\u7684\u914d\u7f6e\u6587\u4ef6<\/h3>\n<p>The EnvironmentName value is determined early in the process of bootstrapping your application, before the default ConfigurationManager is fully populated by WebApplicationBuilder. As a result, you can dynamically change which configuration providers are added to the builder and, hence, which configuration values are loaded when the IConfiguration is built.<\/p>\n<p>EnvironmentName \u503c\u662f\u5728\u5f15\u5bfc\u5e94\u7528\u7a0b\u5e8f\u7684\u65e9\u671f\u786e\u5b9a\u7684\uff0c\u5728\u9ed8\u8ba4 ConfigurationManager \u7531 WebApplicationBuilder \u5b8c\u5168\u586b\u5145\u4e4b\u524d\u3002\u56e0\u6b64\uff0c\u60a8\u53ef\u4ee5\u52a8\u6001\u66f4\u6539\u5c06\u54ea\u4e9b\u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\u6dfb\u52a0\u5230\u751f\u6210\u5668\u4e2d\uff0c\u4ece\u800c\u5728\u6784\u5efa IConfiguration \u65f6\u52a0\u8f7d\u54ea\u4e9b\u914d\u7f6e\u503c\u3002<\/p>\n<p>A common pattern is to have an optional, environment-specific appsettings .ENVIRONMENT.json file that\u2019s loaded after the default appsettings.json file. The following listing shows how you could achieve this task if you\u2019re customizing the ConfigurationMaanger in Program.cs, but it\u2019s also effectively what WebApplicationBuilder does by default.<\/p>\n<p>\u4e00\u79cd\u5e38\u89c1\u6a21\u5f0f\u662f\u5177\u6709\u53ef\u9009\u7684\u3001\u7279\u5b9a\u4e8e\u73af\u5883\u7684 appsettings \u3002ENVIRONMENT.json \u5728\u9ed8\u8ba4 appsettings.json \u6587\u4ef6\u4e4b\u540e\u52a0\u8f7d\u7684\u6587\u4ef6\u3002\u4e0b\u9762\u7684\u6e05\u5355\u663e\u793a\u4e86\u5982\u679c\u60a8\u5728 Program.cs \u4e2d\u81ea\u5b9a\u4e49 ConfigurationManager\uff0c\u5982\u4f55\u5b8c\u6210\u6b64\u4efb\u52a1\uff0c\u4f46\u8fd9\u4e5f\u662f WebApplication-Builder \u9ed8\u8ba4\u6240\u505a\u7684\u3002<\/p>\n<p>Listing 10.13 Adding environment-specific appsettings.json files<\/p>\n<pre><code>WebApplicationBuilder builder = WebApplication.CreateBuilder(args);\n\nIHostEnvironment env = builder.Environment; \u2776\n\nbuilder.Configuration.Sources.Clear();\nbuilder.Configuration\n    .AddJsonFile(\n        &quot;appsettings.json&quot;,\n        optional: false) \u2777\n    .AddJsonFile( \u2778\n        $\u201dappsettings.{env.EnvironmentName}.json\u201d, \u2778\n        Optional: true); \u2778\n\nWebApplication app = builder.Build();\n\napp.MapGet(&quot;\/&quot;, () =&gt;&quot;Hello world!&quot;);\n\napp.Run();<\/code><\/pre>\n<p>\u2776 The current IHostEnvironment is available on WebApplicationBuilder.<br \/>\n\u5f53\u524d\u7684 IHostEnvironment \u5728 WebApplicationBuilder \u4e0a\u53ef\u7528\u3002<br \/>\n\u2777 It\u2019s common to make the base appsettings.json compulsory.<br \/>\n\u5c06 base appsettings.json \u8bbe\u4e3a\u5fc5\u4fee\u662f\u5f88\u5e38\u89c1\u7684\u3002<br \/>\n\u2778 Adds an optional environment-specific JSON file where the filename varies with the<br \/>\nenvironment<br \/>\n\u6dfb\u52a0\u4e00\u4e2a\u53ef\u9009\u7684\u7279\u5b9a\u4e8e\u73af\u5883\u7684 JSON \u6587\u4ef6\uff0c\u5176\u4e2d\u6587\u4ef6\u540d\u968f\u73af\u5883\u800c\u53d8\u5316<\/p>\n<p>With this pattern, a global appsettings.json file contains settings applicable to most environments. Additional optional JSON files called appsettings.Development.json, appsettings.Staging.json, and appsettings.Production.json are subsequently added to ConfigurationManager, depending on the current EnvironmentName.<\/p>\n<p>\u4f7f\u7528\u6b64\u6a21\u5f0f\u65f6\uff0c\u5168\u5c40appsettings.json\u6587\u4ef6\u5305\u542b\u9002\u7528\u4e8e\u5927\u591a\u6570\u73af\u5883\u7684\u8bbe\u7f6e\u3002\u540d\u4e3a appsettings \u7684\u5176\u4ed6\u53ef\u9009 JSON \u6587\u4ef6\u3002Development.json\uff0cappsettings\u3002Staging.json \u548c appsettings \u4e2d\u3002Production.json\u968f\u540e\u4f1a\u6dfb\u52a0\u5230 ConfigurationManager\uff0c\u5177\u4f53\u53d6\u51b3\u4e8e\u5f53\u524d\u7684 EnvironmentName\u3002<\/p>\n<p>Any settings in these files will overwrite values from the global appsettings.json if they have the same key, as you\u2019ve seen previously. Using environment-specific settings files lets you do things like set the logging to be verbose only in the development environment and switch to more selective logs in production.<\/p>\n<p>\u8fd9\u4e9b\u6587\u4ef6\u4e2d\u7684\u4efb\u4f55\u8bbe\u7f6e\u90fd\u5c06\u8986\u76d6\u5168\u5c40appsettings.json\u7684\u503c\uff0c\u5982\u679c\u5b83\u4eec\u5177\u6709\u76f8\u540c\u7684\u952e\uff0c\u5c31\u50cf\u60a8\u4e4b\u524d\u770b\u5230\u7684\u90a3\u6837\u3002\u4f7f\u7528\u7279\u5b9a\u4e8e\u73af\u5883\u7684\u8bbe\u7f6e\u6587\u4ef6\uff0c\u60a8\u53ef\u4ee5\u6267\u884c\u4e00\u4e9b\u4f5c\uff0c\u4f8b\u5982\u5728\u5f00\u53d1\u73af\u5883\u4e2d\u5c06\u65e5\u5fd7\u8bb0\u5f55\u8bbe\u7f6e\u4e3a\u4ec5\u8be6\u7ec6\uff0c\u5e76\u5728\u751f\u4ea7\u73af\u5883\u4e2d\u5207\u6362\u5230\u66f4\u5177\u9009\u62e9\u6027\u7684\u65e5\u5fd7\u3002<\/p>\n<p>Another common pattern is to add or remove configuration providers depending on the environment. You might use the User Secrets provider when developing locally, for example, but Azure Key Vault in production. Listing 10.14 shows how you can use IHostEnvironment to include the User Secrets provider conditionally only in development. Again, WebApplicationBuilder uses this pattern by default.<\/p>\n<p>\u53e6\u4e00\u79cd\u5e38\u89c1\u6a21\u5f0f\u662f\u6839\u636e\u73af\u5883\u6dfb\u52a0\u6216\u5220\u9664\u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\u3002\u4f8b\u5982\uff0c\u5728\u672c\u5730\u5f00\u53d1\u65f6\u4f7f\u7528\u7528\u6237\u673a\u5bc6\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u4f46\u5728\u751f\u4ea7\u73af\u5883\u4e2d\u4f7f\u7528 Azure Key Vault\u3002\u6e05\u5355 10.14 \u5c55\u793a\u4e86\u5982\u4f55\u4f7f\u7528 IHostEnvironment \u4ec5\u5728\u5f00\u53d1\u4e2d\u6709\u6761\u4ef6\u5730\u5305\u542b User Secrets \u63d0\u4f9b\u7a0b\u5e8f\u3002\u540c\u6837\uff0cWebApplicationBuilder \u9ed8\u8ba4\u4f7f\u7528\u6b64\u6a21\u5f0f\u3002<\/p>\n<p>Listing 10.14 Conditionally including the User Secrets configuration provider<br \/>\n\u6e05\u5355 10.14 \u6709\u6761\u4ef6\u5730\u5305\u542b User Secrets \u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f<\/p>\n<pre><code>WebApplicationBuilder builder = WebApplication.CreateBuilder(args);\n\nIHostEnvironment env = builder.Environment;\n\nbuilder.Configuration.Sources.Clear();\nbuilder.Configuration\n    .AddJsonFile(\n        \"appsettings.json\",\n        optional: false)\n    .AddJsonFile(\n        $\"appsettings.{env}.json\",\n        Optional: true);\n\nif(env.IsDevelopment()) \u2776\n{\n    builder.Configuration.AddUserSecrets<Program>(); \u2777\n}\n\nWebApplication app = builder.Build();\n\napp.MapGet(\"\/\", () =>\"Hello world!\");\n\napp.Run();\n<\/code><\/pre>\n<p>\u2776 Extension methods make checking the environment simple and explicit.<br \/>\n\u5c06\u95ee\u9898\u8be6\u60c5\u670d\u52a1\u6dfb\u52a0\u5230 DI \u5bb9\u5668\u4e2d\uff0c\u4f9b ExceptionHandlerMiddleware \u4f7f\u7528<br \/>\n\u2777 In Staging and Production, the User Secrets provider won\u2019t be used.<br \/>\n\u5f53\u4e0d\u5728\u5f00\u53d1\u4e2d\u65f6\uff0c\u7ba1\u9053\u4f7f\u7528 ExceptionHandlerMiddleware\u3002<\/p>\n<p>As already mentioned, it\u2019s also common to customize your application\u2019s middleware pipeline based on the environment. In chapter 4 you learned that WebApplication adds the DeveloperExceptionPageMiddleware conditionally when developing locally. The following listing shows how you can use IHostEnvironment to control your pipeline in this way so that when you\u2019re in staging or production, your app uses ExceptionHandlerMiddleware instead.<\/p>\n<p>\u5982\u524d\u6240\u8ff0\uff0c\u6839\u636e\u73af\u5883\u81ea\u5b9a\u4e49\u5e94\u7528\u7a0b\u5e8f\u7684\u4e2d\u95f4\u4ef6\u7ba1\u9053\u4e5f\u5f88\u5e38\u89c1\u3002\u5728\u7b2c 4 \u7ae0\u4e2d\uff0c\u60a8\u4e86\u89e3\u4e86 WebApplication \u5728\u672c\u5730\u5f00\u53d1\u65f6\u6709\u6761\u4ef6\u5730\u6dfb\u52a0 DeveloperExceptionPageMiddleware\u3002\u4e0b\u9762\u7684\u6e05\u5355\u663e\u793a\u4e86\u5982\u4f55\u4ee5\u8fd9\u79cd\u65b9\u5f0f\u4f7f\u7528 IHostEnvironment \u6765\u63a7\u5236\u7ba1\u9053\uff0c\u4ee5\u4fbf\u5728\u6682\u5b58\u6216\u751f\u4ea7\u73af\u5883\u4e2d\uff0c\u5e94\u7528\u7a0b\u5e8f\u6539\u7528 ExceptionHandlerMiddleware\u3002<\/p>\n<p>Listing 10.15 Using the hosting environment to customize your middleware pipeline<br \/>\n\u6e05\u5355 10.15 \u4f7f\u7528\u6258\u7ba1\u73af\u5883\u81ea\u5b9a\u4e49\u4e2d\u95f4\u4ef6\u7ba1\u9053<\/p>\n<pre><code>WebApplicationBuilder builder = WebApplication.CreateBuilder(args);\n\nbuilder.AddProblemDetails(); \u2776\n\nWebApplication app = builder.Build();\n\nif (!builder.Environment.IsDevelopment()) \u2777\n{ \u2777\n    app.UseExceptionHandler(); \u2777\n} \u2777\n\napp.MapGet(\"\/\", () =>\"Hello world!\");\n\napp.Run();\n<\/code><\/pre>\n<p>\u2776 Adds the problem details service to the DI container for use by the ExceptionHandlerMiddleware<br \/>\n\u5c06\u95ee\u9898\u8be6\u60c5\u670d\u52a1\u6dfb\u52a0\u5230 DI \u5bb9\u5668\u4e2d\uff0c\u4f9b ExceptionHandlerMiddleware \u4f7f\u7528<br \/>\n\u2777 When not in development, the pipeline uses ExceptionHandlerMiddleware.<br \/>\n\u5f53\u4e0d\u5728\u5f00\u53d1\u4e2d\u65f6\uff0c\u7ba1\u9053\u4f7f\u7528 ExceptionHandlerMiddleware\u3002<\/p>\n<p><strong>Note<\/strong> In listing 10.15 you added the Problem Details services to the DI container so that the ExceptionHandlerMiddleware can generate a Problem Details response automatically. As you\u2019re adding the extra middleware only in Staging and Production, you could add the services conditionally to the DI container too instead of always adding them as we did here.<br \/>\n<strong>\u6ce8\u610f<\/strong> \u5728\u793a\u4f8b 10.15 \u4e2d\uff0c\u4f60\u5411 DI \u5bb9\u5668\u6dfb\u52a0\u4e86 Problem Details \u670d\u52a1\uff0c\u4ee5\u4fbf ExceptionHandlerMiddleware \u53ef\u4ee5\u81ea\u52a8\u751f\u6210 Problem Details \u54cd\u5e94\u3002\u7531\u4e8e\u60a8\u4ec5\u5728 Staging \u548c Production \u4e2d\u6dfb\u52a0\u989d\u5916\u7684\u4e2d\u95f4\u4ef6\uff0c\u56e0\u6b64\u60a8\u4e5f\u53ef\u4ee5\u6709\u6761\u4ef6\u5730\u5c06\u670d\u52a1\u6dfb\u52a0\u5230 DI \u5bb9\u5668\u4e2d\uff0c\u800c\u4e0d\u662f\u50cf\u6211\u4eec\u5728\u8fd9\u91cc\u6240\u505a\u7684\u90a3\u6837\u603b\u662f\u6dfb\u52a0\u5b83\u4eec\u3002<\/p>\n<p>You can inject IHostEnvironment anywhere in your app, but I advise against using it in your own services outside Program.cs. It\u2019s far better to use the configuration providers to customize strongly typed settings based on the current hosting environment and inject these settings into your application instead.<\/p>\n<p>\u60a8\u53ef\u4ee5\u5728\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u4efb\u4f55\u4f4d\u7f6e\u6ce8\u5165 IHostEnvironment\uff0c\u4f46\u6211\u5efa\u8bae\u4e0d\u8981\u5728 Program.cs \u4e4b\u5916\u7684\u60a8\u81ea\u5df1\u7684\u670d\u52a1\u4e2d\u4f7f\u7528\u5b83\u3002\u6700\u597d\u4f7f\u7528\u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\u6839\u636e\u5f53\u524d\u6258\u7ba1\u73af\u5883\u81ea\u5b9a\u4e49\u5f3a\u7c7b\u578b\u8bbe\u7f6e\uff0c\u5e76\u5c06\u8fd9\u4e9b\u8bbe\u7f6e\u6ce8\u5165\u5230\u5e94\u7528\u7a0b\u5e8f\u4e2d\u3002<\/p>\n<p>As useful as it is, setting IHostEnvironment with an environment variable can be a little cumbersome if you want to switch back and forth among different environments during testing. Personally, I\u2019m always forgetting how to set environment variables on the various operating systems I use. The final skill I\u2019d like to teach you is how to set the hosting environment when you\u2019re developing locally.<\/p>\n<p>\u5c3d\u7ba1\u5b83\u5f88\u6709\u7528\uff0c\u4f46\u5982\u679c\u60a8\u60f3\u5728\u6d4b\u8bd5\u671f\u95f4\u5728\u4e0d\u540c\u73af\u5883\u4e4b\u95f4\u6765\u56de\u5207\u6362\uff0c\u5219\u4f7f\u7528\u73af\u5883\u53d8\u91cf\u8bbe\u7f6e IHostEnvironment \u53ef\u80fd\u4f1a\u6709\u70b9\u9ebb\u70e6\u3002\u5c31\u6211\u4e2a\u4eba\u800c\u8a00\uff0c\u6211\u603b\u662f\u5fd8\u8bb0\u5982\u4f55\u5728\u6211\u4f7f\u7528\u7684\u5404\u79cd\u4f5c\u7cfb\u7edf\u4e0a\u8bbe\u7f6e\u73af\u5883\u53d8\u91cf\u3002\u6700\u7ec8\u6280\u80fd\u6211\u60f3\u6559\u4f60\u5728\u672c\u5730\u5f00\u53d1\u65f6\u5982\u4f55\u8bbe\u7f6e\u6258\u7ba1\u73af\u5883\u3002<\/p>\n<h3>10.4.3 Setting the hosting environment<\/h3>\n<h3>10.4.3 \u8bbe\u7f6e\u6258\u7ba1\u73af\u5883<\/h3>\n<p>In this section I show you a couple of ways to set the hosting environment when you\u2019re developing. These techniques make it easy to test a specific app\u2019s behavior in different environments without having to change the environment for all the apps on your machine.<\/p>\n<p>\u5728\u672c\u8282\u4e2d\uff0c\u6211\u5c06\u5411\u60a8\u5c55\u793a\u5728\u5f00\u53d1\u65f6\u8bbe\u7f6e\u6258\u7ba1\u73af\u5883\u7684\u51e0\u79cd\u65b9\u6cd5\u3002\u901a\u8fc7\u8fd9\u4e9b\u6280\u672f\uff0c\u53ef\u4ee5\u8f7b\u677e\u6d4b\u8bd5\u7279\u5b9a\u5e94\u7528\u7a0b\u5e8f\u5728\u4e0d\u540c\u73af\u5883\u4e2d\u7684\u884c\u4e3a\uff0c\u800c\u65e0\u9700\u66f4\u6539\u8ba1\u7b97\u673a\u4e0a\u6240\u6709\u5e94\u7528\u7a0b\u5e8f\u7684\u73af\u5883\u3002<\/p>\n<p>If your ASP.NET Core application can\u2019t find an ASPNETCORE_ENVIRONMENT environment variable when it starts up, it defaults to a production environment, as shown in figure 10.6. So when you deploy to production, you\u2019ll be using the correct environment by default.<\/p>\n<p>\u5982\u679c\u60a8\u7684 ASP.NET Core \u5e94\u7528\u7a0b\u5e8f\u5728\u542f\u52a8\u65f6\u627e\u4e0d\u5230 ASPNETCORE_ENVIRONMENT \u73af\u5883\u53d8\u91cf\uff0c\u5219\u9ed8\u8ba4\u4f7f\u7528\u751f\u4ea7\u73af\u5883\uff0c\u5982\u56fe 10.6 \u6240\u793a\u3002\u56e0\u6b64\uff0c\u5f53\u60a8\u90e8\u7f72\u5230\u751f\u4ea7\u73af\u5883\u65f6\uff0c\u9ed8\u8ba4\u60c5\u51b5\u4e0b\u5c06\u4f7f\u7528\u6b63\u786e\u7684\u73af\u5883\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1006.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 10.6 By default, ASP.NET Core applications run in the production hosting environment. You can override this default by setting the ASPNETCORE_ENVIRONMENT variable.<\/p>\n<p>\u56fe 10.6 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cASP.NET Core \u5e94\u7528\u7a0b\u5e8f\u5728\u751f\u4ea7\u6258\u7ba1\u73af\u5883\u4e2d\u8fd0\u884c\u3002\u60a8\u53ef\u4ee5\u8986\u76d6\u6b64\u9ed8\u8ba4\u503c\u901a\u8fc7\u8bbe\u7f6e ASPNETCORE_ENVIRONMENT \u53d8\u91cf\u3002<\/p>\n<p><strong>Tip<\/strong> By default, the current hosting environment is logged to the console at startup, which can be useful for checking that the environment variable has been picked up correctly.<br \/>\n<strong>\u63d0\u793a<\/strong> \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5f53\u524d\u6258\u7ba1\u73af\u5883\u5728\u542f\u52a8\u65f6\u8bb0\u5f55\u5230\u63a7\u5236\u53f0\u4e2d\uff0c\u8fd9\u5bf9\u4e8e\u68c0\u67e5\u662f\u5426\u5df2\u6b63\u786e\u9009\u53d6\u73af\u5883\u53d8\u91cf\u975e\u5e38\u6709\u7528\u3002<\/p>\n<p>Another option is to use a launchSettings.json file to control the environment. All the default ASP.NET Core applications include this file in the Properties folder. LaunchSettings.json defines profiles for running your application.<\/p>\n<p>\u53e6\u4e00\u79cd\u9009\u62e9\u662f\u4f7f\u7528 launchSettings.json \u6587\u4ef6\u6765\u63a7\u5236\u73af\u5883\u3002\u6240\u6709\u9ed8\u8ba4\u7684 ASP.NET Core \u5e94\u7528\u7a0b\u5e8f\u90fd\u5c06\u6b64\u6587\u4ef6\u5305\u542b\u5728 Properties \u6587\u4ef6\u5939\u4e2d\u3002LaunchSettings.json \u5b9a\u4e49\u7528\u4e8e\u8fd0\u884c\u5e94\u7528\u7a0b\u5e8f\u7684\u914d\u7f6e\u6587\u4ef6\u3002<\/p>\n<p><strong>Tip<\/strong> You can use profiles to run your application with different environment variables. You can also use profiles to emulate running on Windows behind Internet Information Services (IIS) by using the IIS Express profile. I rarely use this profile, even in Windows, and always choose the http or https profile.<br \/>\n<strong>\u63d0\u793a<\/strong> \u60a8\u53ef\u4ee5\u4f7f\u7528\u914d\u7f6e\u6587\u4ef6\u6765\u8fd0\u884c\u5177\u6709\u4e0d\u540c\u73af\u5883\u53d8\u91cf\u7684\u5e94\u7528\u7a0b\u5e8f\u3002\u60a8\u8fd8\u53ef\u4ee5\u4f7f\u7528\u914d\u7f6e\u6587\u4ef6\u6765\u6a21\u62df\u4f7f\u7528 IIS Express \u914d\u7f6e\u6587\u4ef6\u5728 Internet Information Services \uff08IIS\uff09 \u540e\u9762\u7684 Windows \u4e0a\u8fd0\u884c\u3002\u6211\u5f88\u5c11\u4f7f\u7528\u6b64\u914d\u7f6e\u6587\u4ef6\uff0c\u5373\u4f7f\u5728 Windows \u4e2d\u4e5f\u662f\u5982\u6b64\uff0c\u5e76\u4e14\u603b\u662f\u9009\u62e9 http \u6216 https \u914d\u7f6e\u6587\u4ef6\u3002<\/p>\n<p>Listing 10.16 shows a typical launchSettings.json file that defines three profiles: http, https, and IIS Express. The first two profiles are equivalent to using dotnet run to run the project. The http profile listens only for http:\/\/ requests, whereas https listens for both http:\/\/ and https:\/\/. The IIS Express profile can be used only in Windows and uses IIS Express to run your application.<\/p>\n<p>\u6e05\u5355 10.16 \u663e\u793a\u4e86\u4e00\u4e2a\u5178\u578b\u7684 launchSettings.json \u6587\u4ef6\uff0c\u5b83\u5b9a\u4e49\u4e86\u4e09\u4e2a\u914d\u7f6e\u6587\u4ef6\uff1ahttp\u3001https \u548c IIS Express\u3002\u524d\u4e24\u4e2a\u914d\u7f6e\u6587\u4ef6\u7b49\u6548\u4e8e\u4f7f\u7528 dotnet run \u8fd0\u884c\u9879\u76ee\u3002http \u914d\u7f6e\u6587\u4ef6\u4ec5\u4fa6\u542c http:\/\/ \u8bf7\u6c42\uff0c\u800c https \u540c\u65f6\u4fa6\u542c http:\/\/ \u548c <a href=\"https:\/\/\u3002IIS\">https:\/\/\u3002IIS<\/a> Express \u914d\u7f6e\u6587\u4ef6\u53ea\u80fd\u5728 Windows \u4e2d\u4f7f\u7528\uff0c\u5e76\u4f7f\u7528 IIS Express \u8fd0\u884c\u5e94\u7528\u7a0b\u5e8f\u3002<\/p>\n<p>Listing 10.16 A typical launchSettings.json file defining three profiles<br \/>\n\u6e05\u5355 10.16 \u5b9a\u4e49\u4e09\u4e2a\u914d\u7f6e\u6587\u4ef6\u7684\u5178\u578b launchSettings.json \u6587\u4ef6<\/p>\n<pre><code>{\n    \"iisSettings\": { \u2776\n        \"windowsAuthentication\": false, \u2776\n        \"anonymousAuthentication\": true, \u2776\n        \"iisExpress\": { \u2776\n            \"applicationUrl\": \"http:\/\/localhost:53846\", \u2776\n            \"sslPort\": 44399 \u2776\n            }\n            },\n            \"profiles\": {\n            \"http\": { \u2777\n                \"commandName\": \"Project\", \u2778\n                \"dotnetRunMessages\": true, \u2779\n                \"launchBrowser\": true, \u277a\n                \"applicationUrl\": \"http:\/\/localhost:5063\", \u277b\n                \"environmentVariables\": { \u277c\n                \"ASPNETCORE_ENVIRONMENT\": \"Development\" \u277c\n            } \u277c\n            },\n            \"https\": { \u277d\n                \"commandName\": \"Project\",\n                \"dotnetRunMessages\": true,\n                \"launchBrowser\": true,\n                \"applicationUrl\": \"https:\/\/localhost:7202;http:\/\/localhost:5063\", \u277e\n                \"environmentVariables\": {\n                \"ASPNETCORE_ENVIRONMENT\": \"Development\"\n            }\n            },\n                \"IIS Express\": { \u277f\n                \"commandName\": \"IISExpress\",\n                \"launchBrowser\": true,\n                \"environmentVariables\": { \u24eb\n                \"ASPNETCORE_ENVIRONMENT\": \"Development\" \u24eb\n            } \u24eb\n        }\n    }\n}<\/code><\/pre>\n<p>\u2776 Defines settings for running behind IIS or using the IIS Express profile<br \/>\n\u5b9a\u4e49\u5728 IIS \u540e\u9762\u8fd0\u884c\u6216\u4f7f\u7528 IIS Express \u914d\u7f6e\u6587\u4ef6\u7684\u8bbe\u7f6e<br \/>\n\u2777 The \u201chttp\u201d profile is used by default in macOS.<br \/>\nmacOS \u4e2d\u9ed8\u8ba4\u4f7f\u7528 \u201chttp\u201d \u914d\u7f6e\u6587\u4ef6\u3002<br \/>\n\u2778 The \u201cproject\u201d command is equivalent to calling dotnet run on the project.<br \/>\n\u201cproject\u201d \u547d\u4ee4\u7b49\u6548\u4e8e\u5728\u9879\u76ee\u4e0a\u8c03\u7528 dotnet run\u3002<br \/>\n\u2779 If true, gives feedback when dotnet run is executing a build or restore<br \/>\n\u5982\u679c\u4e3a true\uff0c\u5219\u5728 dotnet run \u6267\u884c\u751f\u6210\u6216\u8fd8\u539f\u65f6\u63d0\u4f9b\u53cd\u9988<br \/>\n\u277a If true, launches the browser when you run the application<br \/>\n\u5982\u679c\u4e3a true\uff0c\u5219\u5728\u8fd0\u884c\u5e94\u7528\u7a0b\u5e8f\u65f6\u542f\u52a8\u6d4f\u89c8\u5668<br \/>\n\u277b Defines the URLs the application will listen on in this profile<br \/>\n\u5b9a\u4e49\u5e94\u7528\u7a0b\u5e8f\u5c06\u5728\u6b64\u914d\u7f6e\u6587\u4ef6\u4e2d\u4fa6\u542c\u7684 URL<br \/>\n\u277c Defines custom environment variables for the profile and sets the environment to<br \/>\nDevelopment<br \/>\n\u4e3a\u914d\u7f6e\u6587\u4ef6\u5b9a\u4e49\u81ea\u5b9a\u4e49\u73af\u5883\u53d8\u91cf\uff0c\u5e76\u5c06\u73af\u5883\u8bbe\u7f6e\u4e3a Development<br \/>\n\u277d The https profile is used by default in Visual Studio in Windows.<br \/>\n\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0chttps \u914d\u7f6e\u6587\u4ef6\u5728 Windows \u7684 Visual Studio \u4e2d\u4f7f\u7528\u3002<br \/>\n\u277e The https profile listens on both http:\/\/ and https:\/\/ URLs.<br \/>\nhttps \u914d\u7f6e\u6587\u4ef6\u540c\u65f6\u4fa6\u542c http:\/\/ \u548c https:\/\/ URL\u3002<br \/>\n\u277f Runs the application behind IIS Express (Windows only)<br \/>\n\u5728 IIS Express \u540e\u9762\u8fd0\u884c\u5e94\u7528\u7a0b\u5e8f\uff08\u4ec5\u9650 Windows\uff09<br \/>\n\u24eb Each profile can have different environment variables.<br \/>\n\u6bcf\u4e2a\u914d\u7f6e\u6587\u4ef6\u53ef\u4ee5\u5177\u6709\u4e0d\u540c\u7684\u73af\u5883\u53d8\u91cf\u3002<\/p>\n<p>The advantage of using the launchSettings.json file locally is that it allows you to set local environment variables for a project. In listing 10.16 the environment is set to the development environment, for example. Setting environment variables with launchSettings.json means you can use different environment variables for each project and even for each profile, and store them in source control.<\/p>\n<p>\u5728\u672c\u5730\u4f7f\u7528 launchSettings.json \u6587\u4ef6\u7684\u4f18\u70b9\u662f\uff0c\u5b83\u5141\u8bb8\u4e3a\u9879\u76ee\u8bbe\u7f6e\u672c\u5730\u73af\u5883\u53d8\u91cf\u3002\u4f8b\u5982\uff0c\u5728\u5217\u8868 10.16 \u4e2d\uff0c\u73af\u5883\u88ab\u8bbe\u7f6e\u4e3a\u5f00\u53d1\u73af\u5883\u3002\u4f7f\u7528 launchSettings.json \u8bbe\u7f6e\u73af\u5883\u53d8\u91cf\u610f\u5473\u7740\u60a8\u53ef\u4ee5\u4e3a\u6bcf\u4e2a\u9879\u76ee\u751a\u81f3\u6bcf\u4e2a\u914d\u7f6e\u6587\u4ef6\u4f7f\u7528\u4e0d\u540c\u7684\u73af\u5883\u53d8\u91cf\uff0c\u5e76\u5c06\u5b83\u4eec\u5b58\u50a8\u5728\u6e90\u4ee3\u7801\u63a7\u5236\u4e2d\u3002<\/p>\n<p>You can choose a profile to use in Visual Studio by choosing it from the drop-down menu next to the Debug button on the toolbar, as shown in figure 10.7. You can choose a profile to run from the command line by using `dotnet run --launch-profile &lt;Profile Name&gt;`. If you don\u2019t specify a profile, the first profile listed in launchSettings.json is used. If you don\u2019t want to use any profile, you must explicitly ignore the launchSettings.json file by using dotnet run --no-launch-profile.<\/p>\n<p>\u60a8\u53ef\u4ee5\u4ece\u5de5\u5177\u680f\u4e0a Debug \uff08\u8c03\u8bd5\uff09 \u6309\u94ae\u65c1\u8fb9\u7684\u4e0b\u62c9\u83dc\u5355\u4e2d\u9009\u62e9\u8981\u5728 Visual Studio \u4e2d\u4f7f\u7528\u7684\u914d\u7f6e\u6587\u4ef6\uff0c\u5982\u56fe 10.7 \u6240\u793a\u3002\u60a8\u53ef\u4ee5\u4f7f\u7528 `dotnet run --launch- profile &lt;Profile Name&gt;`\u4ece\u547d\u4ee4\u884c\u9009\u62e9\u8981\u8fd0\u884c\u7684\u914d\u7f6e\u6587\u4ef6\u3002\u5982\u679c\u672a\u6307\u5b9a\u914d\u7f6e\u6587\u4ef6\uff0c\u5219\u4f7f\u7528 launchSettings .json\u4e2d\u5217\u51fa\u7684\u7b2c\u4e00\u4e2a\u914d\u7f6e\u6587\u4ef6\u3002\u5982\u679c\u4e0d\u60f3\u4f7f\u7528\u4efb\u4f55\u914d\u7f6e\u6587\u4ef6\uff0c\u5219\u5fc5\u987b\u4f7f\u7528 dotnet run --no-launch- profile \u663e\u5f0f\u5ffd\u7565 launchSettings.json \u6587\u4ef6\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1007.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 10.7 You can select the profile to use from Visual Studio by choosing it from the Debug drop-down menu. Visual Studio defaults to using the https profile.<br \/>\n\u56fe 10.7 \u60a8\u53ef\u4ee5\u4ece Debug \u4e0b\u62c9\u83dc\u5355\u4e2d\u9009\u62e9\u8981\u4f7f\u7528\u7684\u914d\u7f6e\u6587\u4ef6\uff0c\u4ece Visual Studio \u4e2d\u9009\u62e9\u5b83\u3002Visual Studio \u9ed8\u8ba4\u4f7f\u7528 https \u914d\u7f6e\u6587\u4ef6\u3002<\/p>\n<p>If you\u2019re using Visual Studio, you can edit the launchSettings.json file visually: double-click the Properties node, choose the Debug tab, and choose Open debug launch profiles UI. You can see in figure 10.8 that the ASPNETCORE_ENVIRONMENT is set to Development; any changes made on this tab are mirrored in launchSettings.json.<\/p>\n<p>\u5982\u679c\u60a8\u4f7f\u7528\u7684\u662f Visual Studio\uff0c\u5219\u53ef\u4ee5\u76f4\u89c2\u5730\u7f16\u8f91 launchSettings.json \u6587\u4ef6\uff1a\u53cc\u51fb Properties \uff08\u5c5e\u6027\uff09 \u8282\u70b9\uff0c\u9009\u62e9 Debug \uff08\u8c03\u8bd5\uff09 \u9009\u9879\u5361\uff0c\u7136\u540e\u9009\u62e9 Open debug launch profiles UI \uff08\u6253\u5f00\u8c03\u8bd5\u542f\u52a8\u914d\u7f6e\u6587\u4ef6 UI\uff09\u3002\u5728\u56fe 10.8 \u4e2d\u53ef\u4ee5\u770b\u5230\uff0cASPNETCORE_ENVIRONMENT \u8bbe\u7f6e\u4e3a Development;\u5728\u6b64\u9009\u9879\u5361\u4e0a\u6240\u505a\u7684\u4efb\u4f55\u66f4\u6539\u90fd\u4f1a\u955c\u50cf\u5230 launchSettings.json \u4e2d\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/1008.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 10.8 You can use Visual Studio to edit the launchSettings.json file, if you prefer. Changes will be mirrored between the launchSettings.json file and the Properties dialog box.<br \/>\n\u56fe 10.8 \u5982\u679c\u60a8\u613f\u610f\uff0c\u53ef\u4ee5\u4f7f\u7528 Visual Studio \u7f16\u8f91 launchSettings.json \u6587\u4ef6\u3002\u66f4\u6539\u5c06\u5728 launchSettings.json \u6587\u4ef6\u548c Properties \uff08\u5c5e\u6027\uff09 \u5bf9\u8bdd\u6846\u4e4b\u95f4\u955c\u50cf\u3002<\/p>\n<p>The launchSettings.json file is intended for local development only; by default, the file isn\u2019t deployed to production servers. Although you can deploy and use the file in production, doing so generally isn\u2019t worth the hassle. Environment variables are a better fit.<br \/>\nlaunchSettings.json \u6587\u4ef6\u4ec5\u7528\u4e8e\u672c\u5730\u5f00\u53d1;\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u6587\u4ef6\u4e0d\u4f1a\u90e8\u7f72\u5230\u751f\u4ea7\u670d\u52a1\u5668\u3002\u5c3d\u7ba1\u60a8\u53ef\u4ee5\u5728\u751f\u4ea7\u73af\u5883\u4e2d\u90e8\u7f72\u548c\u4f7f\u7528\u8be5\u6587\u4ef6\uff0c\u4f46\u8fd9\u6837\u505a\u901a\u5e38\u4e0d\u503c\u5f97\u3002\u73af\u5883\u53d8\u91cf\u66f4\u5408\u9002\u3002<\/p>\n<p>One final trick I\u2019ve used to set the environment in production is to use command-line arguments. You could set the environment to staging like this:<\/p>\n<p>\u6211\u5728\u751f\u4ea7\u73af\u5883\u4e2d\u8bbe\u7f6e\u73af\u5883\u65f6\u4f7f\u7528\u7684\u6700\u540e\u4e00\u4e2a\u6280\u5de7\u662f\u4f7f\u7528\u547d\u4ee4\u884c\u53c2\u6570\u3002\u60a8\u53ef\u4ee5\u5c06\u73af\u5883\u8bbe\u7f6e\u4e3a stage\uff0c\u5982\u4e0b\u6240\u793a\uff1a<\/p>\n<pre><code>dotnet run --no-launch-profile --environment Staging<\/code><\/pre>\n<p><strong>Note<\/strong> that you also have to pass --no-launch-profile if there\u2019s a launchSettings.json file; otherwise, the values in the file take precedence.<br \/>\n<strong>\u6ce8\u610f<\/strong>  \u5982\u679c\u6709 launchSettings.json \u6587\u4ef6\uff0c\u60a8\u8fd8\u5fc5\u987b\u4f20\u9012 --no-launch-profile;\u5426\u5219\uff0c\u6587\u4ef6\u4e2d\u7684\u503c\u4f18\u5148\u3002<\/p>\n<p>That brings us to the end of this chapter on configuration. Configuration isn\u2019t glamorous, but it\u2019s an essential part of all apps. The ASP.NET Core configuration provider model handles a wide range of scenarios, letting you store settings and secrets in a variety of locations.<\/p>\n<p>\u8fd9\u8ba9\u6211\u4eec\u7ed3\u675f\u4e86\u672c\u7ae0\u5173\u4e8e\u914d\u7f6e\u7684\u7ae0\u8282\u3002\u914d\u7f6e\u5e76\u4e0d\u8ff7\u4eba\uff0c\u4f46\u5b83\u662f\u6240\u6709\u5e94\u7528\u7a0b\u5e8f\u7684\u91cd\u8981\u7ec4\u6210\u90e8\u5206\u3002ASP.NET Core \u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\u6a21\u578b\u53ef\u5904\u7406\u5404\u79cd\u65b9\u6848\uff0c\u8ba9\u60a8\u80fd\u591f\u5728\u5404\u79cd\u4f4d\u7f6e\u5b58\u50a8\u8bbe\u7f6e\u548c\u673a\u5bc6\u3002<\/p>\n<p>Simple settings can be stored in appsettings.json, where they\u2019re easy to tweak and modify during development, and they can be overwritten by using environment-specific JSON files. Meanwhile, your secrets and sensitive settings can be stored outside the project file in the User Secrets manager or as environment variables. This approach gives you both flexibility and safety\u2014as long as you don\u2019t go writing your secrets to appsettings.json!<\/p>\n<p>\u7b80\u5355\u7684\u8bbe\u7f6e\u53ef\u4ee5\u5b58\u50a8\u5728 appsettings.json \u4e2d\uff0c\u5728\u5f00\u53d1\u8fc7\u7a0b\u4e2d\u5f88\u5bb9\u6613\u8c03\u6574\u548c\u4fee\u6539\uff0c\u5e76\u4e14\u53ef\u4ee5\u4f7f\u7528\u7279\u5b9a\u4e8e\u73af\u5883\u7684 JSON \u6587\u4ef6\u8986\u76d6\u5b83\u4eec\u3002\u540c\u65f6\uff0c\u60a8\u7684 Secret \u548c\u654f\u611f\u8bbe\u7f6e\u53ef\u4ee5\u5b58\u50a8\u5728 User Secrets Manager \u4e2d\u7684\u9879\u76ee\u6587\u4ef6\u5916\u90e8\u6216\u4f5c\u4e3a\u73af\u5883\u53d8\u91cf\u5b58\u50a8\u3002\u8fd9\u79cd\u65b9\u6cd5\u4e3a\u60a8\u63d0\u4f9b\u4e86\u7075\u6d3b\u6027\u548c\u5b89\u5168\u6027 - \u53ea\u8981\u60a8\u4e0d\u5c06\u60a8\u7684\u79d8\u5bc6\u5199\u7ed9 appsettings.json\uff01<\/p>\n<p>In chapter 11 we take a look at the OpenAPI specification and how you can use it for documenting your APIs, testing your endpoints, and generating strongly typed clients.<\/p>\n<p>\u5728\u7b2c 11 \u7ae0\u4e2d\uff0c\u6211\u4eec\u5c06\u4e86\u89e3 OpenAPI \u89c4\u8303\uff0c\u4ee5\u53ca\u5982\u4f55\u4f7f\u7528\u5b83\u6765\u8bb0\u5f55 API\u3001\u6d4b\u8bd5\u7aef\u70b9\u548c\u751f\u6210\u5f3a\u7c7b\u578b\u5ba2\u6237\u7aef\u3002<\/p>\n<h2>10.5 Summary<\/h2>\n<h2>10.5 \u603b\u7ed3<\/h2>\n<p>Anything that could be considered to be a setting or a secret is normally stored as a configuration value. Externalizing these values means that you can change them without recompiling your app.<br \/>\n\u4efb\u4f55\u53ef\u88ab\u89c6\u4e3a\u8bbe\u7f6e\u6216\u5bc6\u94a5\u7684\u5185\u5bb9\u901a\u5e38\u5b58\u50a8\u4e3a\u914d\u7f6e\u503c\u3002\u5916\u90e8\u5316\u8fd9\u4e9b\u503c\u610f\u5473\u7740\u60a8\u65e0\u9700\u91cd\u65b0\u7f16\u8bd1\u5e94\u7528\u7a0b\u5e8f\u5373\u53ef\u66f4\u6539\u5b83\u4eec\u3002<\/p>\n<p>ASP.NET Core uses configuration providers to load key-value pairs from a variety of sources. Applications can use many configuration providers.<br \/>\nASP.NET Core \u4f7f\u7528\u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\u4ece\u5404\u79cd\u6765\u6e90\u52a0\u8f7d\u952e\u503c\u5bf9\u3002\u5e94\u7528\u7a0b\u5e8f\u53ef\u4ee5\u4f7f\u7528\u8bb8\u591a\u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\u3002<\/p>\n<p>You can add configuration providers to an instance of ConfigurationManager by using extension methods such as AddJsonFile().<br \/>\n\u60a8\u53ef\u4ee5\u4f7f\u7528\u6269\u5c55\u65b9\u6cd5\uff08\u5982 AddJsonFile\uff08\uff09\uff09\u5c06\u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\u6dfb\u52a0\u5230 ConfigurationManager \u5b9e\u4f8b\u3002<\/p>\n<p>The order in which you add providers to ConfigurationManager is important; subsequent providers replace the values of the same settings defined in earlier providers while preserving unique settings.<br \/>\n\u5411 ConfigurationManager \u6dfb\u52a0\u63d0\u4f9b\u7a0b\u5e8f\u7684\u987a\u5e8f\u5f88\u91cd\u8981;\u540e\u7eed\u63d0\u4f9b\u7a0b\u5e8f\u5c06\u66ff\u6362\u65e9\u671f\u63d0\u4f9b\u7a0b\u5e8f\u4e2d\u5b9a\u4e49\u7684\u76f8\u540c\u8bbe\u7f6e\u7684\u503c\uff0c\u540c\u65f6\u4fdd\u7559\u552f\u4e00\u8bbe\u7f6e\u3002<\/p>\n<p>ASP.NET Core includes built-in providers for JSON files, XML files, environment files, and command-line arguments, among others. NuGet packages exist for many other providers, such as YAML files and Azure Key Vault.<br \/>\nASP.NET Core \u5305\u62ec\u7528\u4e8e JSON \u6587\u4ef6\u3001XML \u6587\u4ef6\u3001\u73af\u5883\u6587\u4ef6\u548c\u547d\u4ee4\u884c\u53c2\u6570\u7b49\u7684\u5185\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\u3002NuGet \u5305\u9002\u7528\u4e8e\u8bb8\u591a\u5176\u4ed6\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u4f8b\u5982 YAML \u6587\u4ef6\u548c Azure Key Vault\u3002<\/p>\n<p>ConfigurationManager implements IConfiguration as well as IConfigurationBuilder, so you can retrieve configuration values from it directly.<br \/>\nConfigurationManager \u5b9e\u73b0 IConfiguration \u548c IConfigurationBuilder\uff0c\u56e0\u6b64\u60a8\u53ef\u4ee5\u76f4\u63a5\u4ece\u4e2d\u68c0\u7d22\u914d\u7f6e\u503c\u3002<\/p>\n<p>Configuration keys aren\u2019t case-sensitive, so you must take care not to lose values when loading settings from case-sensitive sources such as YAML.<br \/>\n\u914d\u7f6e\u952e\u4e0d\u533a\u5206\u5927\u5c0f\u5199\uff0c\u56e0\u6b64\u5728\u4ece\u533a\u5206\u5927\u5c0f\u5199\u7684\u6e90\uff08\u5982 YAML\uff09\u52a0\u8f7d\u8bbe\u7f6e\u65f6\uff0c\u5fc5\u987b\u6ce8\u610f\u4e0d\u8981\u4e22\u5931\u503c\u3002<\/p>\n<p>You can retrieve settings from IConfiguration directly by using the indexer syntax, such as Configuration[&quot;MySettings:Value&quot;]. This technique is often useful for accessing configuration values in Program.cs.<br \/>\n\u53ef\u4ee5\u4f7f\u7528\u7d22\u5f15\u5668\u8bed\u6cd5\uff08\u5982 Configuration[\u201cMySettings\uff1aValue\u201d]\uff09\u76f4\u63a5\u4ece IConfiguration \u68c0\u7d22\u8bbe\u7f6e\u3002\u6b64\u65b9\u6cd5\u901a\u5e38\u7528\u4e8e\u8bbf\u95ee Program.cs \u4e2d\u7684\u914d\u7f6e\u503c\u3002<\/p>\n<p>WebApplicationBuilder automatically configures a ConfigurationManager with JSON, environment variables, command-line arguments, and User Secret providers. This combination provides in-repository storage in JSON files, secret storage in both development and production, and the ability to override settings easily at runtime.<br \/>\nWebApplicationBuilder \u4f7f\u7528 JSON\u3001\u73af\u5883\u53d8\u91cf\u3001\u547d\u4ee4\u884c\u53c2\u6570\u548c\u7528\u6237\u5bc6\u94a5\u63d0\u4f9b\u7a0b\u5e8f\u81ea\u52a8\u914d\u7f6e ConfigurationManager\u3002\u8fd9\u79cd\u7ec4\u5408\u5728 JSON \u6587\u4ef6\u4e2d\u63d0\u4f9b\u5b58\u50a8\u5e93\u5185\u5b58\u50a8\u3001\u5f00\u53d1\u548c\u751f\u4ea7\u4e2d\u7684\u79d8\u5bc6\u5b58\u50a8\uff0c\u4ee5\u53ca\u5728\u8fd0\u884c\u65f6\u8f7b\u677e\u8986\u76d6\u8bbe\u7f6e\u7684\u80fd\u529b\u3002<\/p>\n<p>In production, store secrets in environment variables to reduce the chance of incorrectly exposing the secrets in your code repository. These secrets can be loaded after your file-based settings in the configuration builder.<br \/>\n\u5728\u751f\u4ea7\u73af\u5883\u4e2d\uff0c\u5c06\u5bc6\u94a5\u5b58\u50a8\u5728\u73af\u5883\u53d8\u91cf\u4e2d\uff0c\u4ee5\u51cf\u5c11\u5728\u4ee3\u7801\u5b58\u50a8\u5e93\u4e2d\u9519\u8bef\u5730\u66b4\u9732\u5bc6\u94a5\u7684\u53ef\u80fd\u6027\u3002\u8fd9\u4e9b\u5bc6\u94a5\u53ef\u4ee5\u5728\u914d\u7f6e\u751f\u6210\u5668\u4e2d\u57fa\u4e8e\u6587\u4ef6\u7684\u8bbe\u7f6e\u4e4b\u540e\u52a0\u8f7d\u3002<\/p>\n<p>On development machines, the User Secrets Manager is a more convenient tool than using environment variables. It stores secrets in your operating system\u2019s user profile, outside the project folder, reducing the risk of accidentally exposing secrets in your code repository.<br \/>\n\u5728\u5f00\u53d1\u8ba1\u7b97\u673a\u4e0a\uff0cUser Secrets Manager \u662f\u6bd4\u4f7f\u7528\u73af\u5883\u53d8\u91cf\u66f4\u65b9\u4fbf\u7684\u5de5\u5177\u3002\u5b83\u5c06\u5bc6\u94a5\u5b58\u50a8\u5728\u4f5c\u7cfb\u7edf\u7684\u7528\u6237\u914d\u7f6e\u6587\u4ef6\u4e2d\uff0c\u4f4d\u4e8e\u9879\u76ee\u6587\u4ef6\u5939\u4e4b\u5916\uff0c\u4ece\u800c\u964d\u4f4e\u4e86\u5728\u4ee3\u7801\u5b58\u50a8\u5e93\u4e2d\u610f\u5916\u66b4\u9732\u5bc6\u94a5\u7684\u98ce\u9669\u3002<\/p>\n<p>Be aware that neither environment variables nor the User Secrets Manager tool encrypts secrets. They merely store them in locations that are less likely to be made public, as they\u2019re outside your project folder.<br \/>\n\u8bf7\u6ce8\u610f\uff0c\u73af\u5883\u53d8\u91cf\u548c User Secrets Manager \u5de5\u5177\u90fd\u4e0d\u4f1a\u52a0\u5bc6\u5bc6\u94a5\u3002\u5b83\u4eec\u4ec5\u5c06\u5b83\u4eec\u5b58\u50a8\u5728\u4e0d\u592a\u53ef\u80fd\u516c\u5f00\u7684\u4f4d\u7f6e\uff0c\u56e0\u4e3a\u5b83\u4eec\u4f4d\u4e8e\u5de5\u7a0b\u6587\u4ef6\u5939\u4e4b\u5916\u3002<\/p>\n<p>File-based providers such as the JSON provider can reload configuration values automatically when the file changes, allowing you to update configuration values in real time without restarting your app.<br \/>\n\u57fa\u4e8e\u6587\u4ef6\u7684\u63d0\u4f9b\u7a0b\u5e8f\uff08\u5982 JSON \u63d0\u4f9b\u7a0b\u5e8f\uff09\u53ef\u4ee5\u5728\u6587\u4ef6\u66f4\u6539\u65f6\u81ea\u52a8\u91cd\u65b0\u52a0\u8f7d\u914d\u7f6e\u503c\uff0c\u4ece\u800c\u5141\u8bb8\u60a8\u5b9e\u65f6\u66f4\u65b0\u914d\u7f6e\u503c\uff0c\u800c\u65e0\u9700\u91cd\u65b0\u542f\u52a8\u5e94\u7528\u7a0b\u5e8f\u3002<\/p>\n<p>Use strongly typed POCO options classes to access configuration in your app. Using strongly typed options reduces coupling in your app and ensures that classes are dependent only on the configuration values they use.<br \/>\n\u4f7f\u7528\u5f3a\u7c7b\u578b POCO \u9009\u9879\u7c7b\u8bbf\u95ee\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u914d\u7f6e\u3002\u4f7f\u7528\u5f3a\u7c7b\u578b\u9009\u9879\u53ef\u4ee5\u51cf\u5c11\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u8026\u5408\uff0c\u5e76\u786e\u4fdd\u7c7b\u4ec5\u4f9d\u8d56\u4e8e\u5b83\u4eec\u4f7f\u7528\u7684\u914d\u7f6e\u503c\u3002<\/p>\n<p>Use the <code>Configure&lt;T&gt;()<\/code> extension method in ConfigureServices to bind your POCO options objects to ConfigurationSection. Alternatively, you can configure <code>IOptions&lt;T&gt;<\/code> objects in code instead of using configuration values by passing a lambda to the Configure() method.<br \/>\n\u4f7f\u7528 ConfigureServices \u4e2d\u7684 <code>Configure&lt;T&gt;\uff08\uff09<\/code> \u6269\u5c55\u65b9\u6cd5\u5c06 POCO \u9009\u9879\u5bf9\u8c61\u7ed1\u5b9a\u5230 ConfigurationSection\u3002\u6216\u8005\uff0c\u60a8\u4e5f\u53ef\u4ee5\u5728\u4ee3\u7801\u4e2d\u914d\u7f6e <code>IOptions&lt;T&gt;<\/code> \u5bf9\u8c61\uff0c\u800c\u4e0d\u662f\u901a\u8fc7\u5c06 lambda \u4f20\u9012\u7ed9 Configure\uff08\uff09 \u65b9\u6cd5\u6765\u4f7f\u7528\u914d\u7f6e\u503c\u3002<\/p>\n<p>You can inject the <code>IOptions&lt;T&gt;<\/code> interface into your services by using DI. You can access the strongly typed options object on the Value property. <code>IOptions&lt;T&gt;<\/code> values are registered in DI as singletons, so they remain the same even if the underlying configuration changes.<br \/>\n\u60a8\u53ef\u4ee5\u901a\u8fc7 DI \u5c06 <code>IOptions&lt;T&gt;<\/code> \u63a5\u53e3\u6ce8\u5165\u5230\u60a8\u7684\u670d\u52a1\u4e2d\u3002\u60a8\u53ef\u4ee5\u5728 Value \u5c5e\u6027\u4e0a\u8bbf\u95ee\u5f3a\u7c7b\u578b options \u5bf9\u8c61\u3002<code>IOptions&lt;T&gt;<\/code> \u503c\u5728 DI \u4e2d\u6ce8\u518c\u4e3a\u5355\u4e00\u5b9e\u4f8b\uff0c\u56e0\u6b64\u5373\u4f7f\u5e95\u5c42\u914d\u7f6e\u53d1\u751f\u66f4\u6539\uff0c\u5b83\u4eec\u4e5f\u4fdd\u6301\u4e0d\u53d8\u3002<\/p>\n<p>If you want to reload your POCO options objects when your configuration changes, use the <code>IOptionsSnapshot&lt;T&gt;<\/code> interface instead. These instances are registered in DI with a scoped lifetime, so they\u2019re re-created for every request. Using the <code>IOptionsSnapshot&lt;T&gt;<\/code> interface has performance implications due to binding to the options object repeatedly, so use it only when that effect is acceptable.<br \/>\n\u5982\u679c\u8981\u5728\u914d\u7f6e\u66f4\u6539\u65f6\u91cd\u65b0\u52a0\u8f7d POCO \u9009\u9879\u5bf9\u8c61\uff0c\u8bf7\u6539\u7528 <code>IOptionsSnapshot&lt;T&gt;<\/code> \u63a5\u53e3\u3002\u8fd9\u4e9b\u5b9e\u4f8b\u5728 DI \u4e2d\u6ce8\u518c\uff0c\u5177\u6709\u4f5c\u7528\u57df\u751f\u547d\u5468\u671f\uff0c\u56e0\u6b64\u4f1a\u4e3a\u6bcf\u4e2a\u8bf7\u6c42\u91cd\u65b0\u521b\u5efa\u5b83\u4eec\u3002\u7531\u4e8e\u91cd\u590d\u7ed1\u5b9a\u5230 options \u5bf9\u8c61\uff0c\u56e0\u6b64\u4f7f\u7528 <code>IOptionsSnapshot&lt;T&gt;<\/code> \u63a5\u53e3\u4f1a\u5f71\u54cd\u6027\u80fd\uff0c\u56e0\u6b64\u8bf7\u4ec5\u5728\u8be5\u6210\u672c\u53ef\u63a5\u53d7\u65f6\u4f7f\u7528\u5b83\u3002<\/p>\n<p>Applications running in different environments, such as development versus production , often require different configuration values. ASP.NET Core determines the current hosting environment by using the ASPNETCORE_ENVIRONMENT environment variable. If this variable isn\u2019t set, the environment is assumed to be production.<br \/>\n\u5728\u4e0d\u540c\u73af\u5883\uff08\u4f8b\u5982\u5f00\u53d1\u73af\u5883\u4e0e\u751f\u4ea7\u73af\u5883\uff09\u4e2d\u8fd0\u884c\u7684\u5e94\u7528\u7a0b\u5e8f\u901a\u5e38\u9700\u8981\u4e0d\u540c\u7684\u914d\u7f6e\u503c\u3002ASP.NET Core \u4f7f\u7528 ASPNETCORE_ENVIRONMENT \u73af\u5883\u53d8\u91cf\u786e\u5b9a\u5f53\u524d\u6258\u7ba1\u73af\u5883\u3002\u5982\u679c\u672a\u8bbe\u7f6e\u6b64\u53d8\u91cf\uff0c\u5219\u5047\u5b9a\u73af\u5883\u4e3a production\u3002<\/p>\n<p>You can set the hosting environment locally by using the launchSettings.json file, which allows you to scope environment variables to a specific project.<br \/>\n\u60a8\u53ef\u4ee5\u4f7f\u7528 launchSettings.json \u6587\u4ef6\u5728\u672c\u5730\u8bbe\u7f6e\u6258\u7ba1\u73af\u5883\uff0c\u8be5\u6587\u4ef6\u5141\u8bb8\u60a8\u5c06\u73af\u5883\u53d8\u91cf\u7684\u8303\u56f4\u9650\u5b9a\u4e3a\u7279\u5b9a\u9879\u76ee\u3002<\/p>\n<p>The current hosting environment is exposed as an IHostEnvironment interface. You can check for specific environments by using IsDevelopment(), IsStaging(), and IsProduction(). Then you can use the IHostEnvironment object to load files specific to the current environment, such as appsettings.Production.json.<br \/>\n\u5f53\u524d\u6258\u7ba1\u73af\u5883\u4f5c\u4e3a IHostEnvironment \u63a5\u53e3\u516c\u5f00\u3002\u60a8\u53ef\u4ee5\u4f7f\u7528 IsDevelopment\uff08\uff09\u3001IsStaging\uff08\uff09 \u548c IsProduction\uff08\uff09 \u68c0\u67e5\u7279\u5b9a\u73af\u5883\u3002\u7136\u540e\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528 IHostEnvironment \u5bf9\u8c61\u52a0\u8f7d\u7279\u5b9a\u4e8e\u5f53\u524d\u73af\u5883\u7684\u6587\u4ef6\uff0c\u4f8b\u5982 appsettings\u3002Production.json\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>10 Configuring an ASP.NET Core application 10 \u914d\u7f6e ASP.NET Core \u5e94\u7528\u7a0b\u5e8f This chapter covers \u672c\u7ae0\u6db5\u76d6 Loading settings from multiple configuration providers \u4ece\u591a\u4e2a\u914d\u7f6e\u63d0\u4f9b\u7a0b\u5e8f\u52a0\u8f7d\u8bbe\u7f6e Storing sensitive settings safely \u5b89\u5168\u5730\u5b58\u50a8\u654f\u611f\u8bbe\u7f6e Using strongly typed settings objects \u4f7f\u7528\u5f3a\u7c7b\u578b\u8bbe\u7f6e\u5bf9\u8c61 Using different settings in different hosting environments \u5728\u4e0d\u540c\u7684\u6258\u7ba1\u73af\u5883\u4e2d\u4f7f\u7528\u4e0d\u540c\u7684\u8bbe\u7f6e In part 1 of this book, you learned the basics of getting an ASP.NET [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[19],"class_list":["post-591","post","type-post","status-publish","format-standard","hentry","category-csharp","tag-asp-net-core-in-action"],"_links":{"self":[{"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts\/591","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=591"}],"version-history":[{"count":0,"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts\/591\/revisions"}],"wp:attachment":[{"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=591"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=591"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=591"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}