在ASP.NET Core应用中如何设置和获取与执行环境相关的信息?

简介:

HostingEnvironment是承载应用当前执行环境的描述,它是对所有实现了IHostingEnvironment接口的所有类型以及对应对象的统称。如下面的代码片段所示,一个HostingEnvironment对象承载的执行环境的描述信息体现在定义这个接口的6个属性上。ApplicationNameEnvironmentName分别代表当前应用的名称和执行环境的名称。WebRootPathContentRootPath是指向两个根目录的路径,前者指向的目录用于存放可供外界通过HTTP请求访问的资源,后者指向的目录存放的则是应用自身内部所需的资源。至于这个接口的ContentRootFileProviderWebRootFileProvider属性返回的则是针对这两个目录的FileProvider对象。如下所示的HostingEnvironment类型是对IHostingEnvironment接口的默认实现。[本文已经同步到《ASP.NET Core框架揭秘》之中]

   1: public interface IHostingEnvironment
   2: {
   3:     string         ApplicationName { get; set; }
   4:     string         EnvironmentName { get; set; }
   5:     IFileProvider  ContentRootFileProvider { get; set; }
   6:     string         ContentRootPath { get; set; }
   7:     IFileProvider  WebRootFileProvider { get; set; }
   8:     string         WebRootPath { get; set; }
   9: }
  10:  
  11: public class HostingEnvironment : IHostingEnvironment
  12: {
  13:     string         ApplicationName { get; set; }
  14:     string         EnvironmentName { get; set; }
  15:     IFileProvider  ContentRootFileProvider { get; set; }
  16:     string         ContentRootPath { get; set; }
  17:     IFileProvider  WebRootFileProvider { get; set; }
  18:     string         WebRootPath { get; set; }
  19: }

一、ApplicationEnvironment

接下来我们会对HostingEnvironment对象承载的执行环境描述信息的来源进行详细介绍,不过在此之前我们有必要来了解另一个名为ApplicationEnvironment的类型,它定义在 “Microsoft.Extensions.PlatformAbstractions”这个NuGet包中。我们从其命名也可以看出这个对象描述的也是与执行环境相关的信息,而它承载的这些信息提下在如下四个属性成员上,它们分别表示应用的名称、基路径、版本和采用的.NET Framework。

   1: public class ApplicationEnvironment
   2: {
   3:     public string         ApplicationName {  get; }
   4:     public string         ApplicationBasePath {  get; }
   5:     public string         ApplicationVersion {  get; }
   6:     public FrameworkName  RuntimeFramework { get; }
   7: }

如果需要获取一个ApplicationEnvironment对象来描述当前执行环境,我们需要使用到如下这个名为PlatformServices的对象,它的Application属性返回的就是我们所需的ApplicationEnvironment对象。因为该类型并不存在一个公共的构函数,所以我们不能直接实例化一个PlatformServices对象,不过我们可以利用Default属性得到这个单例对象。

   1: public class PlatformServices
   2: {
   3:     private PlatformServices();
   4:     public ApplicationEnvironment     Application { get; }
   5:     public static PlatformServices    Default { get; }
   6: }

对于一个ApplicationEnvironment对象来说,它的ApplicationName、ApplicationVersion和RuntimeFramework属性决定于定义了程序入口Main方法的程序集,具体来说ApplicationName和ApplicationVersion分别返回这个程序集名称和版本,而这个编译这个程序集采用的.NET Framework的版本对应的正是RuntimeFramework属性。至于ApplicationBasePath属性,它返回的实际上是AppContext的BaseDirectoryPath属性对应的路径,运行时使用这个基础路径来解析被加载的目标程序集的真实路径。针对这四个属性的取值可以通过下面这段程序来验证。

   1: public class Program
   2: {
   3:     public static void Main()
   4:     {
   5:         Assembly assembly = typeof(Program).GetTypeInfo().Assembly;
   6:         AssemblyName assemblyName = assembly.GetName();
   7:         ApplicationEnvironment env = PlatformServices.Default.Application;
   8:  
   9:         Debug.Assert(env.ApplicationBasePath == AppContext.BaseDirectory);
  10:         Debug.Assert(env.ApplicationName == assemblyName.Name);
  11:         Debug.Assert(env.ApplicationVersion == assemblyName.Version.ToString());
  12:         Debug.Assert(env.RuntimeFramework.ToString() == assembly.GetCustomAttribute<TargetFrameworkAttribute>().FrameworkName);
  13:     }
  14: }

如果我们没有对应用的名称做显式设置,当前HostingEnvironment的ApplicationName属性体现的应用名称来源于这个ApplicationEnvironment对象的同名属性。HostingEnvironment包括ApplicationName在内的四个属性(不包括WebRootFileProvider和ContentRootFileProvider属性,因为它们决定于对应ContentRootPath和WebRootPath属性)都可以通过WebHostOptions来设置。通过前面一章的介绍我们知道WebHostOptions对象是根据WebHostBuilder的采用的配置来创建的,所以我们可以利用配置的方式来决定执行环境。

二、Configuration和WebHostOptions

对于通过HostingEnvironment的四个属性(ApplicationName、EnvironmentName、WebRootPath和ContentRootPath) 承载的四个与执行环境相关的设置,在WebHostOptions对象上都具有对应的属性,后者是前者的数据来源。由于WebHostOptions对象是WebHostBuilder根据它采用的配置来创建的,所以这些设置最初来源于使用的配置。值得一提的是,如果EnvironmentName属性未作显式设置,它使用的默认值为“Production”。

9

由于WebHostBuilder会采用环境变量作为配置来源,并且采用“ASPNETCORE_”作为环境变量过滤采用的前缀,所以我们完全可以按照如下的方式通过设置环境变量的方式来初始化由HostingEnvironment承载的执行环境选项。

   1: Environment.SetEnvironmentVariable("ASPNETCORE_APPLICATIONNAME", "MyApp");
   2: Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Staging");
   3: Environment.SetEnvironmentVariable("ASPNETCORE_WEBROOT", @"c:\myapp\wwwroot\");
   4: Environment.SetEnvironmentVariable("ASPNETCORE_CONTENTROOT", @"c:\myapp\contentroot");
   5:  
   6: new WebHostBuilder()
   7:     .UseConfiguration(new ConfigurationBuilder().AddJsonFile("weboptions.json"))
   8:     .ConfigureServices(svcs => {
   9:         IHostingEnvironment env = svcs.BuildServiceProvider().GetRequiredService<IHostingEnvironment>();
  10:         Debug.Assert(env.ApplicationName == "MyApp");
  11:         Debug.Assert(env.EnvironmentName == "Staging");
  12:         Debug.Assert(env.WebRootPath == @"c:\myapp\wwwroot\");
  13:         Debug.Assert(env.ContentRootPath == @"c:\myapp\contentroot");
  14:     })
  15:     .UseKestrel()
  16:     .Build();

虽然WebHostBuilder默认使用环境变量作为配置源,但是我们可以显式地创建一个Configuration对象并通过调用它的扩展方法UseConfiguration进行“导入”。对于上面这段程序,如果我们将配置定义在一个具有如下结构的JSON文件(weboptions.json),我们只需要在创建WebHost之前按照如下的方式调用UseConfiguration方法将对应配置导入进来即可。

weboptions.json:

   1: {
   2:   "applicationName": "MyApp",
   3:   "environment"    : "Staging",
   4:   "webRoot"        : "c:\\myapp\\wwwroot",
   5:   "contentRoot"    : "c:\\myapp\\contentroot"
   6: }

Program

   1: new WebHostBuilder()
   2:     .UseConfiguration(new ConfigurationBuilder().AddJsonFile("weboptions.json").Build())
   3:     .ConfigureServices(svcs => {
   4:         IHostingEnvironment env = svcs.BuildServiceProvider().GetRequiredService<IHostingEnvironment>();
   5:         Debug.Assert(env.ApplicationName  == "MyApp");
   6:         Debug.Assert(env.EnvironmentName  == "Staging");
   7:         Debug.Assert(env.WebRootPath       == @"c:\myapp\wwwroot\");
   8:         Debug.Assert(env.ContentRootPath  == @"c:\myapp\contentroot");
   9:     })
  10:     .UseKestrel()
  11:     .Build();

三、特殊的ApplicationName

对于HostingEnvironment的这四个属性来说,表示应用名称的ApplicationName比较特殊。虽然它的初始值来源于配置,当我们调用Configure方法或者UseStartup方法是,这个属性会被覆盖。如下这段程序与上面不同之处在于创建WebHost之前调用Configure方法,我们采用环境变量设置的应用名(“MyApp”)将失效。

   1: Environment.SetEnvironmentVariable("ASPNETCORE_APPLICATIONNAME", "MyApp");
   2: new WebHostBuilder()
   3:     .ConfigureServices(svcs => {
   4:         IHostingEnvironment env = svcs.BuildServiceProvider().GetRequiredService<IHostingEnvironment>();
   5:         Debug.Assert(env.ApplicationName != "MyApp");
   6:     })
   7:     .UseKestrel()
   8:     .Configure(app => {})
   9: .Build();

其实这个问题的答案我们在《应用的入口——Startup》中已经给出了。如下所示的是WebHostBuilder用于注册Startup的两个扩展方法Configure和UseStartup的定义,我们可以清楚地看到在创建并注册Startup之前,它们都会设置当前应用的名称。

   1: public static class WebHostBuilderExtensions
   2: {    
   3:     public static IWebHostBuilder Configure(this IWebHostBuilder hostBuilder, Action<IApplicationBuilder> configureApp)
   4:     {
   5:         var startupAssemblyName = configureApp.GetMethodInfo().DeclaringType.GetTypeInfo().Assembly.GetName().Name;
   6:  
   7:         return hostBuilder
   8:             .UseSetting("applicationName", startupAssemblyName)
   9:
  10:     }
  11:  
  12:     public static IWebHostBuilder UseStartup(this IWebHostBuilder hostBuilder, Type startupType)
  13:     {
  14:         var startupAssemblyName = startupType.GetTypeInfo().Assembly.GetName().Name;
  15:         return hostBuilder
  16:             .UseSetting("ApplicationName", startupAssemblyName)
  17:             ...           
  18:     }
  19: }

如果我们调用WebHostBuilder的UseStartup方法设置了一个启动类,那么这个类型所在的程序集名称将作为当前应用的名称。如果我们通过Configure方法并提供了一个Action<IApplicationBuilder>类型的委托对象,那么这个委托对象对应方法被定义在哪个类型中,这个类型所在的程序基名称将会作为应用名称。对于后一种情况,我们可以采用如下两种方式来提供这个Action<IApplicationBuilder>对象,最终将会导致设置的应用名称完全不同。

   1: public static class Startup
   2: {
   3:     public static void Configure(IApplicationBuilder app);
   4: }
   5:  
   6: //Configure(app=>Startup.Configure(app))
   7: new WebHostBuilder()
   8:     .ConfigureServices(svcs => {
   9:         IHostingEnvironment env = svcs.BuildServiceProvider().GetRequiredService<IHostingEnvironment>();
  10:         Debug.Assert(env.ApplicationName == Assembly.GetEntryAssembly().GetName().Name);
  11:     })
  12:     .UseKestrel()
  13:     .Configure(app=>Startup.Configure(app))
  14:     .Build();
  15:  
  16: //Configure(Startup.Configure)
  17: new WebHostBuilder()
  18:     .ConfigureServices(svcs => {
  19:         IHostingEnvironment env = svcs.BuildServiceProvider().GetRequiredService<IHostingEnvironment>();
  20:         Debug.Assert(env.ApplicationName == typeof(Startup).GetTypeInfo().Assembly.GetName().Name);
  21:     })
  22:     .UseKestrel()
  23:     .Configure(Startup.Configure)
  24:     .Build();
作者:蒋金楠
微信公众账号:大内老A
微博: www.weibo.com/artech
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号 蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
相关文章
|
1月前
|
开发框架 .NET 开发者
简化 ASP.NET Core 依赖注入(DI)注册-Scrutor
Scrutor 是一个简化 ASP.NET Core 应用程序中依赖注入(DI)注册过程的开源库,支持自动扫描和注册服务。通过简单的配置,开发者可以轻松地从指定程序集中筛选、注册服务,并设置其生命周期,同时支持服务装饰等高级功能。适用于大型项目,提高代码的可维护性和简洁性。仓库地址:&lt;https://github.com/khellang/Scrutor&gt;
48 5
|
2月前
|
开发框架 .NET C#
在 ASP.NET Core 中创建 gRPC 客户端和服务器
本文介绍了如何使用 gRPC 框架搭建一个简单的“Hello World”示例。首先创建了一个名为 GrpcDemo 的解决方案,其中包含一个 gRPC 服务端项目 GrpcServer 和一个客户端项目 GrpcClient。服务端通过定义 `greeter.proto` 文件中的服务和消息类型,实现了一个简单的问候服务 `GreeterService`。客户端则通过 gRPC 客户端库连接到服务端并调用其 `SayHello` 方法,展示了 gRPC 在 C# 中的基本使用方法。
50 5
在 ASP.NET Core 中创建 gRPC 客户端和服务器
|
1月前
|
开发框架 缓存 .NET
GraphQL 与 ASP.NET Core 集成:从入门到精通
本文详细介绍了如何在ASP.NET Core中集成GraphQL,包括安装必要的NuGet包、创建GraphQL Schema、配置GraphQL服务等步骤。同时,文章还探讨了常见问题及其解决方法,如处理复杂查询、错误处理、性能优化和实现认证授权等,旨在帮助开发者构建灵活且高效的API。
34 3
|
17天前
|
开发框架 算法 中间件
ASP.NET Core 中的速率限制中间件
在ASP.NET Core中,速率限制中间件用于控制客户端请求速率,防止服务器过载并提高安全性。通过`AddRateLimiter`注册服务,并配置不同策略如固定窗口、滑动窗口、令牌桶和并发限制。这些策略可在全局、控制器或动作级别应用,支持自定义响应处理。使用中间件`UseRateLimiter`启用限流功能,并可通过属性禁用特定控制器或动作的限流。这有助于有效保护API免受滥用和过载。 欢迎关注我的公众号:Net分享 (239字符)
36 0
|
2月前
|
开发框架 监控 .NET
【Azure App Service】部署在App Service上的.NET应用内存消耗不能超过2GB的情况分析
x64 dotnet runtime is not installed on the app service by default. Since we had the app service running in x64, it was proxying the request to a 32 bit dotnet process which was throwing an OutOfMemoryException with requests >100MB. It worked on the IaaS servers because we had the x64 runtime install
|
2月前
|
JSON 算法 安全
JWT Bearer 认证在 .NET Core 中的应用
【10月更文挑战第30天】JWT(JSON Web Token)是一种开放标准,用于在各方之间安全传输信息。它由头部、载荷和签名三部分组成,用于在用户和服务器之间传递声明。JWT Bearer 认证是一种基于令牌的认证方式,客户端在请求头中包含 JWT 令牌,服务器验证令牌的有效性后授权用户访问资源。在 .NET Core 中,通过安装 `Microsoft.AspNetCore.Authentication.JwtBearer` 包并配置认证服务,可以实现 JWT Bearer 认证。具体步骤包括安装 NuGet 包、配置认证服务、启用认证中间件、生成 JWT 令牌以及在控制器中使用认证信息
137 2
|
3月前
mcr.microsoft.com/dotnet/core/aspnet:2.1安装libgdiplus
mcr.microsoft.com/dotnet/core/aspnet:2.1安装libgdiplus
40 1
|
3月前
|
开发框架 JavaScript 前端开发
一个适用于 ASP.NET Core 的轻量级插件框架
一个适用于 ASP.NET Core 的轻量级插件框架
|
4月前
|
开发框架 前端开发 JavaScript
ASP.NET MVC 教程
ASP.NET 是一个使用 HTML、CSS、JavaScript 和服务器脚本创建网页和网站的开发框架。
53 7