Come ottenere l'ambiente di hosting di sviluppo / staging / produzione in ConfigureServices


171

Come ottenere l'ambiente di hosting di sviluppo / staging / produzione nel ConfigureServicesmetodo in avvio?

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

Il ConfigureServicesmetodo accetta solo un singolo IServiceCollectionparametro.


4
perché non può essere IHostingEnvironmentsemplicemente iniettato in ConfigureServices? svista? o un motivo di cui dobbiamo essere consapevoli?
Simon_Weaver,

Risposte:


226

È possibile accedervi facilmente in ConfigureServices, semplicemente perseverare su una proprietà durante il metodo Startup che viene chiamato per primo e lo fa passare, quindi è possibile accedere alla proprietà da 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...
}

13
Secondo i documenti , questo metodo non dovrebbe essere usato. Dovresti invece utilizzare CurrentEnvironment.IsEnvironment("environmentname").
vaindil,

28
oppure CurrentEnvironment.IsDevelopment()/CurrentEnvironment.IsProduction()
Simon_Weaver il

3
@vaindil: i documenti a cui fai riferimento non dicono che questo metodo non dovrebbe essere usato. Il tuo esempio ignora semplicemente l'involucro, che è preferibile in molti casi ma non un comandamento
Coruscate5

3
@ Coruscate5 Va bene, non dice esplicitamente di NON usare questo metodo, ma dice di usare l'altro metodo INSTEAD. È praticamente la stessa cosa.
vaindil

8
deprecato IHostingEnvironment env usa invece IWebHostEnvironment env
Mark Schultheiss

56

TL; DR

Imposta una variabile d'ambiente chiamata ASPNETCORE_ENVIRONMENTcon il nome dell'ambiente (es Production.). Quindi fai una delle due cose:

  • Iniettare IHostingEnvironmentin Startup.cs, quindi utilizzare tale ( envqui) per controllare: env.IsEnvironment("Production"). Non controllare usando env.EnvironmentName == "Production"!
  • Utilizzare Startupclassi separate o singole Configure/ ConfigureServicesfunzioni. Se una classe o le funzioni corrispondono a questi formati, verranno utilizzate al posto delle opzioni standard in quell'ambiente.
    • Startup{EnvironmentName}() (intera classe) || esempio:StartupProduction()
    • Configure{EnvironmentName}()|| esempio:ConfigureProduction()
    • Configure{EnvironmentName}Services()|| esempio:ConfigureProductionServices()

Spiegazione completa

I documenti .NET Core descrivono come ottenere questo risultato . Utilizzare una variabile d'ambiente chiamataASPNETCORE_ENVIRONMENT impostata sull'ambiente desiderato, quindi sono disponibili due opzioni.

Controlla il nome dell'ambiente

Dai documenti :

Il IHostingEnvironmentservizio fornisce l'astrazione principale per lavorare con gli ambienti. Questo servizio è fornito dal livello di hosting ASP.NET e può essere inserito nella logica di avvio tramite Dependency Injection. Il modello di sito Web ASP.NET Core in Visual Studio utilizza questo approccio per caricare file di configurazione specifici dell'ambiente (se presenti) e per personalizzare le impostazioni di gestione degli errori dell'app. In entrambi i casi, questo comportamento si ottiene facendo riferimento all'ambiente attualmente specificato chiamando EnvironmentNameo IsEnvironmentsull'istanza di IHostingEnvironmentpassato nel metodo appropriato.

NOTA: nonenv.EnvironmentName è consigliabile verificare il valore reale di !

Se è necessario verificare se l'applicazione è in esecuzione in un determinato ambiente, utilizzare env.IsEnvironment("environmentname")poiché ignorerà correttamente il caso (anziché verificare se, env.EnvironmentName == "Development"ad esempio).

Usa classi separate

Dai documenti :

All'avvio di un'applicazione ASP.NET Core, la Startupclasse viene utilizzata per avviare l'applicazione, caricarne le impostazioni di configurazione, ecc. ( Ulteriori informazioni sull'avvio di ASP.NET ). Tuttavia, se esiste una classe denominata Startup{EnvironmentName}(ad esempio StartupDevelopment) e la ASPNETCORE_ENVIRONMENTvariabile di ambiente corrisponde a quel nome, Startupviene invece utilizzata quella classe. Pertanto, è possibile configurare Startupper lo sviluppo, ma avere uno separato StartupProductionche verrebbe utilizzato quando l'app viene eseguita in produzione. O vice versa.

Oltre a utilizzare una Startupclasse completamente separata basata sull'ambiente corrente, è anche possibile apportare modifiche alla configurazione dell'applicazione all'interno di una Startupclasse. I metodi Configure()e ConfigureServices()supportano versioni specifiche dell'ambiente simili alla Startupclasse stessa, del modulo Configure{EnvironmentName}()e Configure{EnvironmentName}Services(). Se si definisce un metodo, ConfigureDevelopment()questo verrà chiamato anziché Configure()quando l'ambiente è impostato per lo sviluppo. Allo stesso modo, ConfigureDevelopmentServices()verrebbe chiamato invece che ConfigureServices()nello stesso ambiente.


29

Nell'app .NET Core 2.0MVC / Microsoft.AspNetCore.Allv2.0.0, puoi avere una classe di avvio specifica per l'ambiente come descritta da @vaindil, ma questo approccio non mi piace.

Puoi anche iniettare IHostingEnvironmentnel StartUpcostruttore. Non è necessario archiviare la variabile di ambiente in 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());
            }            
        });

        ......
    }
}

1
I dettagli possono essere visualizzati in: docs.microsoft.com/pt-br/aspnet/core/fundamentals/…
André Morales

Ecco il link in inglese pubblicato da André: docs.microsoft.com/en-us/aspnet/core/fundamentals/…
ahong

1
deprecato IHostingEnvironment env usa invece IWebHostEnvironment env
Mark Schultheiss

21

Questo può essere realizzato senza ulteriori proprietà o parametri del metodo, in questo modo:

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

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

2
la migliore risposta di sempre. grazie
Shady Sherif,

7
Ciò genera il seguente avviso in .NET Core 3.0: La chiamata a "BuildServiceProvider" dal codice dell'applicazione comporta la creazione di una copia aggiuntiva dei servizi singleton. Considera le alternative come i servizi di iniezione di dipendenza come parametri per "Configura".
Eterno21

2
deprecato IHostingEnvironment env usa invece IWebHostEnvironment env
Mark Schultheiss

19

Se devi testarlo da qualche parte nel tuo codebase che non ha un facile accesso a IHostingEnvironment, un altro modo semplice per farlo è come questo:

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

bene, breve! Tieni presente che il nome della variabile è diverso tra "asp.net core" e "asp.net"
nmDat

15

secondo i documenti

Configura e ConfiguraServizi supportano versioni specifiche dell'ambiente del modulo Configura {EnvironmentName} e Configura {EnvironmentName} Servizi:

Puoi fare qualcosa del genere ...

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
}

1
Questa è la convention più bella
Stuart.Sklinar

11

Volevo ottenere l'ambiente in uno dei miei servizi. È davvero facile da fare! L'ho solo iniettato nel costruttore in questo modo:

    private readonly IHostingEnvironment _hostingEnvironment;

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

Ora più avanti nel codice posso fare questo:

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

MODIFICARE:

Il codice sopra è per .NET Core 2. Per la versione 3 che vorrai usare IWebHostEnvironment.


5

L'ambiente di hosting proviene dalla variabile d'ambiente ASPNET_ENV, disponibile durante l'avvio utilizzando il metodo di estensione IHostingEnvironment.IsEnvironment o uno dei metodi di convenienza corrispondenti di IsDevelopment o IsProduction. Salvare ciò che è necessario in Startup () o nella chiamata ConfigureServices:

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

IHostingEnvironmentnon è disponibile in ConfigureServices.
Muhammad Rehan Saeed,

1
No non lo è. Fai riferimento alla mia risposta su come gestirla.
Jeff Dunlop,

8
La variabile d'ambiente è ora "ASPNETCORE_ENVIRONMENT"
Anthony

deprecato IHostingEnvironment env usa invece IWebHostEnvironment env
Mark Schultheiss

5

Nel caso in cui qualcuno stia guardando anche a questo. In .net core 3+ la maggior parte di questo è obsoleta. Il modo di aggiornamento è:

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

2

In Dotnet Core 2.0 il costruttore di avvio prevede solo un parametro IConfiguration.

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

Come leggere l'ambiente di hosting lì? Lo memorizzo in Program-class durante ConfigureAppConfiguration (usa BuildWebHost completo invece di 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 quindi lo legge in ConfigureServices in questo modo:

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

deprecato IHostingEnvironment env usa invece IWebHostEnvironment env
Mark Schultheiss
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.