在 ASP.NET 5 应用中访问环境变量
这是一个简短的 walkthrough,介绍在使用 ASP.NET 5 DNX 执行环境编写应用程序时如何访问环境变量。
重要提示: 本文已过时。 新版本已发布,针对已发布的 .NET Core 和 ASP.NET Core 1.x 版本,解决了相同的问题。
引言
在编写 Web 应用程序或控制台应用程序时,您经常需要访问诸如应用程序运行的目录、托管环境的版本或诸如 TEMP
文件夹位置或 PATH
和 USERPROFILE
变量之类的环境变量。
我们可能还希望将与安全相关的信息(如数据库密码或安全令牌)存储在不被提交到源代码管理的文件中。
在 .Net 4.x 中,我们使用了 AppDomain
或 ConfigurationManager.AppSettings
等静态变量,这些变量可能会根据应用程序运行的类型和环境引发各种问题。对于 .Net 可移植库,这样做也不太方便。
使用面向 Core CLR
的新应用编写时,这些结构不再可用,但更重要的是,我们不再需要它们了。
通过 DNX
,ASP.NET 团队为各种应用程序编写了一个出色的宿主环境,但也带来了许多新概念。
例如,有不同的方法可以访问应用程序运行的环境变量:
- 通过依赖注入注入强类型、与宿主相关的数据
- 通过配置使用
string key, string value
对
依赖注入
ASP.NET 团队引入了一个轻量级的 DI 框架,DNX
也使用该框架将内容注入到您的应用程序中。
注意
内置的 DI 框架仅支持构造函数注入。它可以被更重量级的包(如 Autofaq 或 Ninject)替换。在本文中,我们将使用内置的 DI。
DNX
的一个优点是它可以将有用的数据注入到我们应用程序的入口点。
对于 ASP.NET Web 应用程序,我们可以注入到 Startup.cs
的构造函数中;对于控制台应用程序,我们使用 Program.cs
的构造函数。
现在的问题是,我们需要注入什么以及它是如何工作的?
Microsoft.Framework.Runtime.Abstractions
NuGet 包提供了所有可用的接口。如果您将其中一个接口添加到构造函数中,宿主 (DNX) 将在运行时注入实例化的具体实现。
具体实现可能会因应用程序运行的环境(例如 Windows 或 Linux)而异。
这就是依赖注入和新框架的强大之处。在开发时,我们无需了解,更重要的是,无需关心这些差异。
该框架为我们抽象了这些,它将能够正常工作。而且,由于这些接口提供了强类型契约,我们可以预期这些属性都已设置。
Microsoft.Framework.Runtime.Abstractions
NuGet 包中有几个接口为您提供了不同的环境信息:
IApplicationEnvironment
提供对常用应用程序信息的访问IRuntimeEnvironment
提供对运行时环境的访问IRuntimeOptions
表示传递给运行时启动的选项
提示
还有更多接口,如ICompilerOptions
或IAssemblyLoader
,它们非常有用,但在此不作讨论。请自行探索!
示例
要编写 ASP.NET 5 控制台应用程序,请使用 Visual Studio 2015 (RC 或更高版本) 和新的 ASP.NET 5 项目模板来创建一个控制台应用程序。这将创建一个面向新 DNX 4.5.1
和 DNX Core 5.0
的 project.json
文件和一个简单的 Program.cs
文件。
<code>public class Program
{
public void Main(string[] args)
{
}
}
</code>
要在我们的控制台应用程序中使用 Microsoft.Framework.Runtime.Abstractions
NuGet 包,我们必须将其添加为 project.json
文件中的依赖项。
<code> "dependencies": {
"Microsoft.Framework.Runtime.Abstractions": "1.0.0-beta6-*"
},
</code>
注意
版本可能会有所不同,在撰写本文时,版本是beta6
。
在所有这些发布之前,版本之间可能会有重大更改。请确保所有 Framework 和 System 包都属于同一个里程碑,例如,不要混合使用 beta 4 和 beta 5 包。
另外,请确保您运行应用程序的DNX
版本与您安装的包的版本相匹配。
现在,我们将这些接口作为参数添加到应用程序的构造函数中。在下面的示例中,我们使用控制台输出来打印这些接口提供的一些信息。
<code>public Program(IApplicationEnvironment app,
IRuntimeEnvironment runtime,
IRuntimeOptions options)
{
Console.WriteLine("ApplicationName: {0} {1}", app.ApplicationName, app.Version);
Console.WriteLine("ApplicationBasePath: {0}", app.ApplicationBasePath);
Console.WriteLine("Framework: {0}", app.RuntimeFramework.FullName);
Console.WriteLine("Runtime: {0} {1} {2}", runtime.RuntimeType, runtime.RuntimeArchitecture, runtime.RuntimeVersion);
Console.WriteLine("System: {0} {1}", runtime.OperatingSystem, runtime.OperatingSystemVersion);
}
public void Main(string[] args) { ... }
</code>
配置
ASP.NET 5 还带有一个新的配置框架。我们不会详细介绍它如何取代 app/web.config
。但总的来说,它是一个字符串键值对的集合。
主要 NuGet 包 Microsoft.Framework.Configuration
带有一个 ConfigurationBuilder
类,可用于将不同的配置源合并到一个键值对集合中。
后续的包,如 Microsoft.Framework.Configuration.EnvironmentVariables
和 Microsoft.Framework.Configuration.Json
,会向 ConfigurationBuilder
添加扩展方法,以访问特定的配置源。
示例
对于我们的示例,我们希望检索所有环境变量,如 PATH
或 USERPROFILE
,并将 key
和 value
打印到控制台输出。
除了上面提到的 Microsoft.Framework.Runtime.Abstractions
之外,我们还将依赖项引用 Microsoft.Framework.Configuration.EnvironmentVariables
添加到 project.json
文件中。
该包已依赖于 Microsoft.Framework.Configuration
,这意味着我们不必显式引用它。
<code> "dependencies": {
"Microsoft.Framework.Runtime.Abstractions": "1.0.0-beta6-*",
"Microsoft.Framework.Configuration.EnvironmentVariables": "1.0.0-beta6-*",
...
},
</code>
在应用程序的构造函数中,我们现在可以实例化一个新的 ConfigurationBuilder
并调用扩展方法。
<code>var configuration = new ConfigurationBuilder()
.AddEnvironmentVariables()
.Build();
</code>
要将所有变量打印到控制台,我们可以简单地迭代所有可用的键值对。
<code>foreach(var config in configuration.GetConfigurationSections())
{
Console.WriteLine("{0}={1}", config.Key, configuration.Get(config.Key));
}
</code>
还有一个名为用户机密的概念。用户机密从应用程序上下文实例化的用户帐户的配置文件中检索,例如,在 Windows 上是 %APPDATA%\microsoft\UserSecrets\<applicationId>\secrets.json
。
在 ASP.NET wiki 页面 上阅读更多关于如何配置用户机密的信息。
其概念与上面提到的环境变量相同,您可以通过调用 ConfigurationBuilder
上的 AddUserSecrets
扩展来将配置的用户机密添加到 key value
集合中。
配置的使用
这两种概念(环境变量和用户机密配置)都可以用来将与安全相关的信息与源代码隔离。
我们绝不希望将数据库密码或 Windows Azure 令牌和密钥提交到 GitHub 或任何其他源代码管理系统。
这样,我们就可以为每个环境定义安全相关的设置并在运行时读取它们,并且永远不要将它们添加到会被提交到源代码管理的文件中!
更多资源和示例
- DNX 概述
- DNX Wiki
- 关于检索类型信息的有趣讨论
- 自定义程序集加载器
注入IAssemblyLoaderContainer
和IAssemblyLoadContextAccessor