如何在ConfigureServices中获取开发/暂存/生产主机环境

Muh*_*eed 134 c# asp.net-core-mvc asp.net-core

如何ConfigureServices在Startup 中的方法中获得开发/暂存/生产主机环境?

public void ConfigureServices(IServiceCollection services)
{
    // Which environment are we running under?
}
Run Code Online (Sandbox Code Playgroud)

ConfigureServices方法仅采用单个IServiceCollection参数.

Joe*_*tte 170

您可以在ConfigureServices中轻松访问它,只需在启动方法中将其持久保存到属性中,该方法首先被调用并传入,然后您可以从ConfigureServices访问该属性

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

private IHostingEnvironment CurrentEnvironment{ get; set; } 

public void ConfigureServices(IServiceCollection services)
{
    string envName = CurrentEnvironment.EnvironmentName;
    ... your code here...
}
Run Code Online (Sandbox Code Playgroud)

  • 或者'CurrentEnvironment.IsDevelopment()`/`CurrentEnvironment.IsProduction()` (19认同)
  • 已弃用 IHostingEnvironment env 使用 IWebHostEnvironment env 代替 (14认同)
  • [根据文档](https://docs.asp.net/en/latest/fundamentals/environments.html#determining-the-environment-at-runtime),不应使用此方法.你应该使用`CurrentEnvironment.IsEnvironment("environmentname")`. (11认同)
  • 从形式上来说,“Startup”不是一个方法,而是一个构造函数。 (3认同)
  • @vaindil - 您引用的文档并未说明不应使用此方法.你的例子只是忽略了套管,这在很多情况下是优选的,但不是诫命 (2认同)
  • @ Coruscate5好的,它没有明确表示不使用此方法,但表示要使用另一种方法INSTEAD。几乎是同一回事。 (2认同)

vai*_*dil 47

TL; DR

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

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

完整的解释

.NET Core文档描述了如何实现这一目标.使用一个名为ASPNETCORE_ENVIRONMENTset of environment的环境变量,然后你有两个选择.

检查环境名称

来自文档:

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

注意:检查的实际值env.EnvironmentName推荐!

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

使用单独的类

来自文档:

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

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

  • .NET 6(非核心)版本对此有何改变? (2认同)

ric*_*888 29

在NET6中,Startup和Program已经合并到一个文件中,ConfigureServicesStartup中不再有方法了。现在您可以简单地使用

builder.Environment.IsProduction() 
builder.Environment.IsStaging()
builder.Environment.IsDevelopment()
Run Code Online (Sandbox Code Playgroud)

就在第一行之后

var builder = WebApplication.CreateBuilder(args);
Run Code Online (Sandbox Code Playgroud)


Dav*_*ang 23

.NET Core 2.0MVC app/Microsoft.AspNetCore.Allv2.0.0中,您可以使用@vaindil所描述的环境特定的启动类,但我不喜欢这种方法.

您也可以注入IHostingEnvironmentStartUp构造函数.您不需要在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());
            }            
        });

        ......
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 已弃用 IHostingEnvironment env 使用 IWebHostEnvironment env 代替 (2认同)

小智 15

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

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

    if (env.IsProduction()) DoSomethingDifferentHere();
}
Run Code Online (Sandbox Code Playgroud)

  • 这会在 .NET Core 3.0 中引发以下警告:从应用程序代码调用“BuildServiceProvider”会导致创建单例服务的附加副本。考虑替代方案,例如依赖注入服务作为“配置”的参数。 (13认同)
  • 有史以来最好的答案。谢谢 (2认同)
  • 已弃用 IHostingEnvironment env 使用 IWebHostEnvironment env 代替 (2认同)
  • 不建议调用`BuildServiceProvider`!有关更多详细信息,请参阅[本文](https://andrewlock.net/access-services-inside-options-and-startup-using-configureoptions/)。 (2认同)

Ros*_*sim 12

从 ASP.NET Core 3.0 开始,从ConfigureServicesConfigure.

只需注入IWebHostEnvironmentStartup 构造函数本身。像这样...

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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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


Pat*_*ick 11

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

bool isDevelopment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development";
Run Code Online (Sandbox Code Playgroud)

  • 好吧,短路!请记住“asp.net core”和“asp.net”之间的变量名称是不同的 (2认同)

Hei*_*aen 8

由于还没有完整的复制和粘贴解决方案,根据 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
   }
   ...
}
Run Code Online (Sandbox Code Playgroud)


Jes*_*ess 6

我想在其中一项服务中获得环境。这真的很容易做到!我只是将其注入到构造函数中,如下所示:

    private readonly IHostingEnvironment _hostingEnvironment;

    public MyEmailService(IHostingEnvironment hostingEnvironment)
    {
        _hostingEnvironment = hostingEnvironment;
    }
Run Code Online (Sandbox Code Playgroud)

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

if (_hostingEnvironment.IsProduction()) {
    // really send the email.
}
else {
    // send the email to the test queue.
}
Run Code Online (Sandbox Code Playgroud)

  • 我个人很高兴您添加了此内容,因为它对我的用例有所帮助,但我猜测您被否决的原因是它没有回答所提出的原始问题。 (3认同)

Jef*_*lop 5

托管环境来自ASPNET_ENV环境变量,该环境变量在启动过程中可以使用IHostingEnvironment.IsEnvironment扩展方法或IsDevelopment或IsProduction的相应便捷方法之一提供。在Startup()或ConfigureServices调用中保存所需的内容:

var foo = Environment.GetEnvironmentVariable("ASPNET_ENV");
Run Code Online (Sandbox Code Playgroud)

  • 环境变量现在为“ ASPNETCORE_ENVIRONMENT” (7认同)

Sho*_*hoe 5

根据文档

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
}
Run Code Online (Sandbox Code Playgroud)