【问题标题】:How to get the Development/Staging/production Hosting Environment in ConfigureServices如何在 ConfigureServices 中获取开发/暂存/生产托管环境
【发布时间】:2015-12-09 12:27:23
【问题描述】:

如何在 Startup 的 ConfigureServices 方法中获取 Development/Staging/production Hosting Environment?

public void ConfigureServices(IServiceCollection services)
{
    // Which environment are we running under?
}

ConfigureServices 方法只接受一个 IServiceCollection 参数。

【问题讨论】:

  • 为什么不能将IHostingEnvironment 注入到ConfigureServices 中?监督?还是我们需要注意的原因?
  • 使用 Microsoft.Extensions.Hosting;如果您使用的是 IWebHostEnvironment。它会给你 IsDevelopment/IsProduction/IsStaging 等检查。

标签: c# asp.net-core asp.net-core-mvc


【解决方案1】:

宿主环境来自 ASPNET_ENV 环境变量,它在启动期间使用 IHostingEnvironment.IsEnvironment 扩展方法或 IsDevelopment 或 IsProduction 的相应便捷方法之一可用。在 Startup() 或 ConfigureServices 调用中保存您需要的内容:

var foo = Environment.GetEnvironmentVariable("ASPNET_ENV");

【讨论】:

  • IHostingEnvironmentConfigureServices 中不可用。
  • 不,不是。关于如何处理它,请参阅我的回答。
  • 环境变量现在是“ASPNETCORE_ENVIRONMENT”
  • 弃用的 IHostingEnvironment env 改用 IWebHostEnvironment env
【解决方案2】:

您可以在 ConfigureServices 中轻松访问它,只需在 Startup 方法期间将其持久化到一个属性中,该方法首先调用并传入它,然后您可以从 ConfigureServices 访问该属性。

public Startup(IWebHostEnvironment env, IApplicationEnvironment appEnv)
{
    ...your code here...
    CurrentEnvironment = env;
}

private IWebHostEnvironment CurrentEnvironment{ get; set; } 
 
public void ConfigureServices(IServiceCollection services)
{
    string envName = CurrentEnvironment.EnvironmentName;
    ... your code here...
}

【讨论】:

  • Per the docs,不应该使用这种方法。你应该改用CurrentEnvironment.IsEnvironment("environmentname")
  • CurrentEnvironment.IsDevelopment() / CurrentEnvironment.IsProduction()
  • @vaindil - 您引用的文档并没有说不应该使用这种方法。您的示例只是忽略了大小写,这在许多情况下是可取的,但不是诫命
  • @Coruscate5 好的,它没有明确说不使用这种方法,但它说使用另一种方法 INSTEAD。这几乎是一回事。
  • 弃用的 IHostingEnvironment env 改用 IWebHostEnvironment env
【解决方案3】:

TL;DR

使用环境名称设置一个名为ASPNETCORE_ENVIRONMENT 的环境变量(例如Production)。然后做以下两件事之一:

  • IHostingEnvironment 注入Startup.cs,然后使用它(此处为env)检查:env.IsEnvironment("Production")不要使用env.EnvironmentName == "Production"进行检查!
  • 使用单独的Startup 类或单独的Configure/ConfigureServices 函数。如果类或函数与这些格式匹配,则将使用它们而不是该环境中的标准选项。
    • Startup{EnvironmentName}() (全班) ||例如:StartupProduction()
    • Configure{EnvironmentName}() ||例如:ConfigureProduction()
    • Configure{EnvironmentName}Services() ||例如:ConfigureProductionServices()

完整解释

.NET Core 文档describe how to accomplish this。使用一个名为ASPNETCORE_ENVIRONMENT 的环境变量设置为您想要的环境,那么您有两个选择。

检查环境名称

From the docs:

IHostingEnvironment 服务提供了用于处理环境的核心抽象。该服务由 ASP.NET 托管层提供,可以通过依赖注入注入到您的启动逻辑中。 Visual Studio 中的 ASP.NET Core 网站模板使用此方法来加载特定于环境的配置文件(如果存在)并自定义应用程序的错误处理设置。在这两种情况下,此行为都是通过在传递给适当方法的IHostingEnvironment 实例上调用EnvironmentNameIsEnvironment 来引用当前指定的环境来实现的。

注意:不建议检查env.EnvironmentName 的实际值!

如果您需要检查应用程序是否在特定环境中运行,请使用env.IsEnvironment("environmentname"),因为它会正确忽略大小写(而不是检查是否为env.EnvironmentName == "Development")。

使用单独的类

From the docs:

当 ASP.NET Core 应用程序启动时,Startup 类用于引导应用程序、加载其配置设置等 (learn more about ASP.NET startup)。但是,如果存在名为 Startup{EnvironmentName} 的类(例如 StartupDevelopment),并且 ASPNETCORE_ENVIRONMENT 环境变量与该名称匹配,则使用该 Startup 类。因此,您可以配置 Startup 用于开发,但有一个单独的 StartupProduction 将在应用程序在生产中运行时使用。反之亦然。

除了基于当前环境使用完全独立的Startup 类之外,您还可以调整应用程序在Startup 类中的配置方式。 Configure()ConfigureServices() 方法支持类似于 Startup 类本身的特定于环境的版本,其形式为 Configure{EnvironmentName}()Configure{EnvironmentName}Services()。如果您定义了一个方法ConfigureDevelopment(),当环境设置为开发时,它将被调用而不是Configure()。同样,ConfigureDevelopmentServices() 将在同一环境中被调用,而不是 ConfigureServices()

【讨论】:

  • 在 .NET 6(非核心)版本中这是否发生了很大变化?
【解决方案4】:

在 Dotnet Core 2.0 中,启动构造函数只需要一个 IConfiguration 参数。

    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

如何读取那里的托管环境? 我在 ConfigureAppConfiguration 期间将它存储在程序类中 (使用完整的 BuildWebHost 而不是 WebHost.CreateDefaultBuilder):

public class Program
{
    public static IHostingEnvironment HostingEnvironment { get; set; }

    public static void Main(string[] args)
    {
        // Build web host
        var host = BuildWebHost(args);

        host.Run();
    }

    public static IWebHost BuildWebHost(string[] args)
    {
        return new WebHostBuilder()
            .UseConfiguration(new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("hosting.json", optional: true)
                .Build()
            )
            .UseKestrel()
            .UseContentRoot(Directory.GetCurrentDirectory())
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                var env = hostingContext.HostingEnvironment;

                // Assigning the environment for use in ConfigureServices
                HostingEnvironment = env; // <---

                config
                  .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                  .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);

                if (env.IsDevelopment())
                {
                    var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
                    if (appAssembly != null)
                    {
                        config.AddUserSecrets(appAssembly, optional: true);
                    }
                }

                config.AddEnvironmentVariables();

                if (args != null)
                {
                    config.AddCommandLine(args);
                }
            })
            .ConfigureLogging((hostingContext, builder) =>
            {
                builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
                builder.AddConsole();
                builder.AddDebug();
            })
            .UseIISIntegration()
            .UseDefaultServiceProvider((context, options) =>
            {
                options.ValidateScopes = context.HostingEnvironment.IsDevelopment();
            })
            .UseStartup<Startup>()
            .Build();
    }

Ant 然后像这样在 ConfigureServices 中读取它:

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    var isDevelopment = Program.HostingEnvironment.IsDevelopment();
}

【讨论】:

  • 弃用的 IHostingEnvironment env 改用 IWebHostEnvironment env
【解决方案5】:

.NET Core 2.0 MVC 应用程序/Microsoft.AspNetCore.All v2.0.0 中,您可以使用@vaindil 描述的特定于环境的启动类,但我不喜欢这种方法。

您也可以将IHostingEnvironment 注入StartUp 构造函数。您不需要将环境变量存储在Program 类中。

public class Startup
{
    private readonly IHostingEnvironment _currentEnvironment;
    public IConfiguration Configuration { get; private set; }

    public Startup(IConfiguration configuration, IHostingEnvironment env)
    {
        _currentEnvironment = env;
        Configuration = configuration;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        ......

        services.AddMvc(config =>
        {
            // Requiring authenticated users on the site globally
            var policy = new AuthorizationPolicyBuilder()
                .RequireAuthenticatedUser()
                .Build();
            config.Filters.Add(new AuthorizeFilter(policy));

            // Validate anti-forgery token globally
            config.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());

            // If it's Production, enable HTTPS
            if (_currentEnvironment.IsProduction())      // <------
            {
                config.Filters.Add(new RequireHttpsAttribute());
            }            
        });

        ......
    }
}

【讨论】:

【解决方案6】:

这可以在没有任何额外属性或方法参数的情况下完成,如下所示:

public void ConfigureServices(IServiceCollection services)
{
    IServiceProvider serviceProvider = services.BuildServiceProvider();
    IHostingEnvironment env = serviceProvider.GetService<IHostingEnvironment>();

    if (env.IsProduction()) DoSomethingDifferentHere();
}

【讨论】:

  • 有史以来最好的答案。谢谢
  • 这会在 .NET Core 3.0 中引发以下警告:从应用程序代码调用“BuildServiceProvider”会导致创建单例服务的额外副本。考虑将依赖注入服务等替代方案作为“配置”的参数。
  • 弃用的 IHostingEnvironment env 改用 IWebHostEnvironment env
  • 不建议拨打BuildServiceProvider!有关详细信息,请参阅this article
【解决方案7】:

根据docs

Configure 和 ConfigureServices 支持环境特定版本 形式为 Configure{EnvironmentName} 和 Configure{EnvironmentName}Services:

你可以做这样的事情......

public void ConfigureProductionServices(IServiceCollection services)
{
    ConfigureCommonServices(services);

    //Services only for production
    services.Configure();
}

public void ConfigureDevelopmentServices(IServiceCollection services)
{
    ConfigureCommonServices(services);

    //Services only for development
    services.Configure();
}

public void ConfigureStagingServices(IServiceCollection services)
{
    ConfigureCommonServices(services);

    //Services only for staging
    services.Configure();
}

private void ConfigureCommonServices(IServiceCollection services)
{
    //Services common to each environment
}

【讨论】:

  • 这是最好的约定
【解决方案8】:

我想在我的一项服务中获得环境。这真的很容易做到!我只是像这样将它注入到构造函数中:

    private readonly IHostingEnvironment _hostingEnvironment;

    public MyEmailService(IHostingEnvironment hostingEnvironment)
    {
        _hostingEnvironment = hostingEnvironment;
    }

现在稍后在代码中我可以这样做:

if (_hostingEnvironment.IsProduction()) {
    // really send the email.
}
else {
    // send the email to the test queue.
}

编辑:

以上代码适用于 .NET Core 2。对于版本 3,您需要使用 IWebHostEnvironment

【讨论】:

  • 我很好奇为什么这会收到反对票。这有什么错误或不好的做法吗?我想学习。
  • 我个人很高兴您将其包含在内,因为它对我的用例有所帮助,但我猜测您为何被否决是因为它没有按要求回答原始问题。
【解决方案9】:

如果您需要在无法轻松访问 IHostingEnvironment 的代码库中进行测试,另一种简单的方法是:

bool isDevelopment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development";

【讨论】:

  • 嗯,很简单!请记住,“asp.net core”和“asp.net”之间的变量名称不同
  • 哇,好主意
【解决方案10】:

以防万一有人也在寻找这个。在 .net core 3+ 中,大部分都已过时。更新方式为:

public void Configure(
    IApplicationBuilder app,
    IWebHostEnvironment env,
    ILogger<Startup> logger)
{
    if (env.EnvironmentName == Environments.Development)
    {
        // logger.LogInformation("In Development environment");
    }
}

【讨论】:

  • 这个问题专门问的是ConfigureServices,而不是Configure。
  • 这对 ConfigureServices 不起作用,因为您不能在 ConfigureServices 中注入 IWebHostEnvironment。所以这并不能回答问题。
【解决方案11】:

由于还没有完整的复制和粘贴解决方案,根据 Joe Audette 的回答:

public IWebHostEnvironment Environment { get; }

public Startup(IWebHostEnvironment environment, IConfiguration configuration)
{
   Environment = environment;
   ...
}

public void ConfigureServices(IServiceCollection services)
{
   if (Environment.IsDevelopment())
   {
       // Do something
   }else{
       // Do something
   }
   ...
}

【讨论】:

    【解决方案12】:

    从 ASP.NET Core 3.0 开始,从ConfigureServicesConfigure 访问环境变量要简单得多。

    只需将IWebHostEnvironment 注入 Startup 构造函数本身。就这样……

    public class Startup
    {
        public Startup(IConfiguration configuration, IWebHostEnvironment env)
        {
            Configuration = configuration;
            _env = env;
        }
    
        public IConfiguration Configuration { get; }
        private readonly IWebHostEnvironment _env;
    
        public void ConfigureServices(IServiceCollection services)
        {
            if (_env.IsDevelopment())
            {
                //development
            }
        }
    
        public void Configure(IApplicationBuilder app)
        {
            if (_env.IsDevelopment())
            {
                //development
            }
        }
    }
    

    参考:https://docs.microsoft.com/en-us/aspnet/core/fundamentals/environments?view=aspnetcore-3.0#inject-iwebhostenvironment-into-the-startup-class

    【讨论】:

    • 但它讲述的是开发还是不开发(Staging、Production、VST.......)。它不知道它是生产还是暂存还是.....?
    【解决方案13】:

    对于一个 blazor 服务器应用,我这样做了:Startup.cs 直接在命名空间声明下添加

    namespace myProjectName.Server
    
    public static class myGlobals
    
    {
        public static bool isDevelopment = true;
    }
    

    Startup.cs 找到Configure 方法和对env.IsDevelopment 的现有检查,并将上面声明的static isDeveloment 设置为truefalse

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
               myGlobals.isDevelopment = true;
            }
            else false
    

    ApplicationUser 初始化数据库连接或其他任何地方时

            if (myGlobals.isDevelopment)
            {
    

    【讨论】:

      【解决方案14】:

      另一种方法是使用Configuration["ASPNETCORE_ENVIRONMENT"] 直接从配置中读取环境名称。这适用于您可以访问配置的任何地方。

      public IConfiguration Configuration { get; }
      
      public Startup(IConfiguration configuration)
      {
          Configuration = configuration;
      }
      public void ConfigureServices(IServiceCollection services)
      {
          Console.WriteLine(Configuration["ASPNETCORE_ENVIRONMENT"]);
      }
      

      先决条件是主机是使用 Programm.cs 中的 Host.CreateDefaultBuilder() 创建的,这是 ASP.NET Core 3.0(和 5.0)Web 应用程序的默认设置。如果使用另一个构建器,可以在 Programm.cs 中使用 AddEnvironmentVariables() 添加 envar。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-12-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-06-04
        • 2023-01-20
        相关资源
        最近更新 更多