Como obter o ambiente de hospedagem de desenvolvimento / armazenamento temporário / produção no ConfigureServices

170

Como obtenho o ambiente de hospedagem de desenvolvimento / armazenamento temporário / produção no ConfigureServicesmétodo em Inicialização?

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

O ConfigureServicesmétodo usa apenas um único IServiceCollectionparâmetro.

Muhammad Rehan Saeed
fonte
4
por que não pode IHostingEnvironmentsimplesmente ser injetado no ConfigureServices? supervisão? ou um motivo pelo qual precisamos estar cientes?
Simon_Weaver
3
Consulte os documentos do MSFT docs.microsoft.com/en-us/aspnet/core/fundamentals/environments
RickAndMSFT

Respostas:

225

Você pode acessá-lo facilmente no ConfigureServices, apenas persistir em uma propriedade durante o método Startup, que é chamada primeiro e transferida, e você pode acessar a propriedade no 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...
}
Joe Audette
fonte
13
De acordo com os documentos , esse método não deve ser usado. Você deveria estar usando CurrentEnvironment.IsEnvironment("environmentname").
vaindil
28
ou CurrentEnvironment.IsDevelopment()/CurrentEnvironment.IsProduction()
Simon_Weaver 30/11
3
@vaindil - os documentos que você referencia não dizem que esse método não deve ser usado. Seu exemplo simplesmente ignora caixa, que é preferível em muitos casos, mas não um mandamento
Coruscate5
3
@ Coruscate5 Ok, ele não diz explicitamente para NÃO usar esse método, mas diz para usar o outro método INSTEAD. Isso é praticamente a mesma coisa.
vaindil
8
depredado IHostingEnvironment env usar IWebHostEnvironment env vez
Mark Schultheiss
56

TL; DR

Defina uma variável de ambiente chamada ASPNETCORE_ENVIRONMENTcom o nome do ambiente (por exemplo Production). Depois, faça uma de duas coisas:

  • Inject IHostingEnvironmentpara Startup.cs, em seguida, usar isso ( envaqui) para verificar: env.IsEnvironment("Production"). Não verifique usando env.EnvironmentName == "Production"!
  • Use Startupclasses separadas ou individuais Configure/ ConfigureServicesfunções. Se uma classe ou as funções corresponderem a esses formatos, elas serão usadas em vez das opções padrão nesse ambiente.
    • Startup{EnvironmentName}() (turma inteira) || exemplo:StartupProduction()
    • Configure{EnvironmentName}()|| exemplo:ConfigureProduction()
    • Configure{EnvironmentName}Services()|| exemplo:ConfigureProductionServices()

Explicação completa

Os documentos do .NET Core descrevem como fazer isso . Use uma variável de ambiente chamada ASPNETCORE_ENVIRONMENTdefinida para o ambiente que você deseja, e então você tem duas opções.

Verifique o nome do ambiente

Dos documentos :

O IHostingEnvironmentserviço fornece a abstração principal para trabalhar com ambientes. Este serviço é fornecido pela camada de hospedagem ASP.NET e pode ser injetado na sua lógica de inicialização via Injeção de Dependência. O modelo de site ASP.NET Core no Visual Studio usa essa abordagem para carregar arquivos de configuração específicos do ambiente (se houver) e para personalizar as configurações de tratamento de erros do aplicativo. Nos dois casos, esse comportamento é alcançado consultando o ambiente atualmente especificado chamando EnvironmentNameou IsEnvironmentna instância de IHostingEnvironmentpassado para o método apropriado.

NOTA: Nãoenv.EnvironmentName é recomendável verificar o valor real de !

Se você precisar verificar se o aplicativo está sendo executado em um ambiente específico, use, env.IsEnvironment("environmentname")pois ele ignorará corretamente o caso (em vez de verificar se, env.EnvironmentName == "Development"por exemplo).

Use classes separadas

Dos documentos :

Quando um aplicativo ASP.NET Core é iniciado, a Startupclasse é usada para inicializar o aplicativo, carregar suas definições de configuração etc. ( saiba mais sobre a inicialização do ASP.NET ). No entanto, se existir uma classe chamada Startup{EnvironmentName}(por exemplo StartupDevelopment), e a ASPNETCORE_ENVIRONMENTvariável de ambiente corresponder a esse nome, essa Startupclasse será usada. Assim, você pode configurar Startuppara desenvolvimento, mas ter um separado StartupProductionque seria usado quando o aplicativo for executado em produção. Ou vice-versa.

Além de usar uma Startupclasse totalmente separada com base no ambiente atual, você também pode fazer ajustes na forma como o aplicativo é configurado dentro de uma Startupclasse. Os métodos Configure()e ConfigureServices()suportam versões específicas do ambiente semelhantes à Startupprópria classe, da forma Configure{EnvironmentName}()e Configure{EnvironmentName}Services(). Se você definir um método, ConfigureDevelopment()ele será chamado em vez de Configure()quando o ambiente estiver definido para desenvolvimento. Da mesma forma, ConfigureDevelopmentServices()seria chamado em vez de ConfigureServices()no mesmo ambiente.

vaindil
fonte
29

No .NET Core 2.0MVC app / Microsoft.AspNetCore.Allv2.0.0, você pode ter uma classe de inicialização específica do ambiente, conforme descrito por @vaindil, mas eu não gosto dessa abordagem.

Você também pode injetar IHostingEnvironmentno StartUpconstrutor. Você não precisa armazenar a variável de ambiente na Programclasse.

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());
            }            
        });

        ......
    }
}
David Liang
fonte
1
Os detalhes podem ser vistos em: docs.microsoft.com/pt-br/aspnet/core/fundamentals/...
André Morales
Aqui está o link em inglês publicado por André: docs.microsoft.com/en-us/aspnet/core/fundamentals/…
ahong
1
depredado IHostingEnvironment env usar IWebHostEnvironment env vez
Mark Schultheiss
21

Isso pode ser realizado sem propriedades extras ou parâmetros de método, como:

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

    if (env.IsProduction()) DoSomethingDifferentHere();
}
edicius6
fonte
2
a melhor resposta de sempre. thanx
Shady Sherif
7
Isso lança o seguinte aviso no .NET Core 3.0: Chamar 'BuildServiceProvider' do código do aplicativo resulta em uma cópia adicional dos serviços singleton sendo criados. Considere alternativas como serviços de injeção de dependência como parâmetros para 'Configurar'.
Eternal21
2
depredado IHostingEnvironment env usar IWebHostEnvironment env vez
Mark Schultheiss
19

Se você precisar testar isso em algum lugar da sua base de código que não tenha acesso fácil ao IHostingEnvironment, outra maneira fácil de fazer isso é:

bool isDevelopment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development";
Patrick
fonte
bem, caminho curto! Lembre-se de que o nome da variável é diferente entre "asp.net core" e "asp.net"
nmDat 30/06/19
14

de acordo com os documentos

O Configure e o ConfigureServices suportam versões específicas do ambiente do formulário Configure os Serviços {EnvironmentName} e Configure {EnvironmentName}:

Você pode fazer algo assim ...

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
}
Sapato
fonte
Esta é a convenção mais legal
Stuart.Sklinar
11

Eu queria obter o ambiente em um dos meus serviços. É realmente fácil de fazer! Eu apenas injeto no construtor assim:

    private readonly IHostingEnvironment _hostingEnvironment;

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

Agora, mais tarde, no código, eu posso fazer isso:

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

EDITAR:

O código acima é para o .NET Core 2. Para a versão 3, você desejará usar IWebHostEnvironment.

Jess
fonte
5

O ambiente de hospedagem vem da variável de ambiente ASPNET_ENV, disponível durante a Inicialização, usando o método de extensão IHostingEnvironment.IsEnvironment ou um dos métodos de conveniência correspondentes de IsDevelopment ou IsProduction. Salve o que você precisa em Startup () ou na chamada ConfigureServices:

var foo = Environment.GetEnvironmentVariable("ASPNET_ENV");
Jeff Dunlop
fonte
IHostingEnvironmentnão está disponível em ConfigureServices.
Muhammad Rehan Saeed
1
Não, não é. Consulte minha resposta sobre como lidar com isso.
Jeff Dunlop
8
A variável de ambiente é agora "ASPNETCORE_ENVIRONMENT"
Anthony
deprovado IHostingEnvironment env usar IWebHostEnvironment env vez
Mark Schultheiss
5

Apenas no caso de alguém estar olhando para isso também. No .net core 3+, a maior parte disso é obsoleta. A maneira de atualização é:

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

No Dotnet Core 2.0, o construtor Startup espera apenas um parâmetro IConfiguration.

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

Como ler o ambiente de hospedagem lá? Eu o armazeno na classe Program durante o ConfigureAppConfiguration (use BuildWebHost completo em vez de 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();
    }

O Ant lê-o no ConfigureServices assim:

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    var isDevelopment = Program.HostingEnvironment.IsDevelopment();
}
toralux
fonte
deprecated IHostingEnvironment env use IWebHostEnvironment env em vez disso
Mark Schultheiss