Cómo obtener el entorno de alojamiento de desarrollo / preparación / producción en ConfigureServices

170

¿Cómo obtengo el entorno de alojamiento de desarrollo / puesta en escena / producción en el ConfigureServicesmétodo de inicio?

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

El ConfigureServicesmétodo solo toma un único IServiceCollectionparámetro.

Muhammad Rehan Saeed
fuente
44
¿Por qué no se IHostingEnvironmentpuede inyectar en ConfigureServices? ¿vigilancia? o una razón que debemos tener en cuenta?
Simon_Weaver

Respuestas:

225

Puede acceder fácilmente a él en ConfigureServices, simplemente consérvelo en una propiedad durante el método de Inicio que se llama primero y lo pasa, luego puede acceder a la propiedad desde 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
fuente
13
Según los documentos , este método no debe usarse. En su lugar, deberías estar usando CurrentEnvironment.IsEnvironment("environmentname").
vaindil
28
o CurrentEnvironment.IsDevelopment()/CurrentEnvironment.IsProduction()
Simon_Weaver
3
@vaindil: los documentos a los que hace referencia no dicen que este método no deba usarse. Su ejemplo simplemente ignora la carcasa, que es preferible en muchos casos pero no un mandamiento
Coruscate5
3
@ Coruscate5 Bien, no dice explícitamente que NO use este método, pero dice que use el otro método EN LUGAR. Eso es prácticamente lo mismo.
vaindil
8
IHostingEnvironment env obsoleto use IWebHostEnvironment env en su lugar
Mark Schultheiss
56

TL; DR

Establezca una variable de entorno llamada ASPNETCORE_ENVIRONMENTcon el nombre del entorno (por ejemplo Production). Luego haz una de dos cosas:

  • Inyectar IHostingEnvironmenten Startup.cs, a continuación, utilizar ese ( envaquí) para comprobar: env.IsEnvironment("Production"). ¡No verifique usando env.EnvironmentName == "Production"!
  • Utilice Startupclases separadas o individuales Configure/ ConfigureServicesfunciones. Si una clase o las funciones coinciden con estos formatos, se utilizarán en lugar de las opciones estándar en ese entorno.
    • Startup{EnvironmentName}() (clase completa) || ejemplo:StartupProduction()
    • Configure{EnvironmentName}()|| ejemplo:ConfigureProduction()
    • Configure{EnvironmentName}Services()|| ejemplo:ConfigureProductionServices()

Explicación completa

Los documentos de .NET Core describen cómo lograr esto . Use una variable de entorno llamada ASPNETCORE_ENVIRONMENTque esté configurada en el entorno que desee, luego tiene dos opciones.

Comprobar nombre del entorno

De los documentos :

El IHostingEnvironmentservicio proporciona la abstracción central para trabajar con entornos. Este servicio es proporcionado por la capa de alojamiento ASP.NET y puede inyectarse en su lógica de inicio a través de Inyección de dependencias. La plantilla del sitio web ASP.NET Core en Visual Studio utiliza este enfoque para cargar archivos de configuración específicos del entorno (si están presentes) y para personalizar la configuración de manejo de errores de la aplicación. En ambos casos, este comportamiento se logra haciendo referencia al entorno especificado actualmente llamando EnvironmentNameo IsEnvironmenten el caso de IHostingEnvironmentpasar al método apropiado.

NOTA: Comprobación del valor real de env.EnvironmentNameque se no se recomienda!

Si necesita verificar si la aplicación se está ejecutando en un entorno en particular, úsela env.IsEnvironment("environmentname")ya que ignorará correctamente las mayúsculas y minúsculas (en lugar de verificar si, env.EnvironmentName == "Development"por ejemplo).

Usa clases separadas

De los documentos :

Cuando se inicia una aplicación ASP.NET Core, la Startupclase se usa para iniciar la aplicación, cargar sus ajustes de configuración, etc. ( obtenga más información sobre el inicio de ASP.NET ). Sin embargo, si existe una clase llamada Startup{EnvironmentName}(por ejemplo StartupDevelopment), y la ASPNETCORE_ENVIRONMENTvariable de entorno coincide con ese nombre, entonces esa Startupclase se usa en su lugar. Por lo tanto, puede configurarlo Startuppara el desarrollo, pero tener uno separado StartupProductionque se usaría cuando la aplicación se ejecute en producción. O viceversa.

Además de utilizar una Startupclase completamente separada basada en el entorno actual, también puede realizar ajustes en la configuración de la aplicación dentro de una Startupclase. Los métodos Configure()y ConfigureServices()admiten versiones específicas del entorno similares a la Startupclase misma, de la forma Configure{EnvironmentName}()y Configure{EnvironmentName}Services(). Si define un método ConfigureDevelopment(), se llamará en lugar de Configure()cuando el entorno esté configurado para el desarrollo. Del mismo modo, ConfigureDevelopmentServices()se llamaría en lugar de ConfigureServices()en el mismo entorno.

vaindil
fuente
29

En la .NET Core 2.0aplicación MVC / Microsoft.AspNetCore.Allv2.0.0, puede tener una clase de inicio específica del entorno según lo descrito por @vaindil, pero no me gusta ese enfoque.

También puede inyectar IHostingEnvironmenten el StartUpconstructor. No necesita almacenar la variable de entorno en Programclase.

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
fuente
1
Los detalles se pueden ver en: docs.microsoft.com/pt-br/aspnet/core/fundamentals/…
André Morales
Aquí está el enlace en inglés publicado por André: docs.microsoft.com/en-us/aspnet/core/fundamentals/…
ahong
1
IHostingEnvironment env obsoleto use IWebHostEnvironment env en su lugar
Mark Schultheiss
21

Esto se puede lograr sin propiedades adicionales o parámetros de método, como sigue:

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

    if (env.IsProduction()) DoSomethingDifferentHere();
}
edicius6
fuente
2
La mejor respuesta de todas. gracias
Shady Sherif
77
Esto arroja la siguiente advertencia en .NET Core 3.0: Llamar a 'BuildServiceProvider' desde el código de la aplicación da como resultado una copia adicional de los servicios singleton que se crean. Considere alternativas como los servicios de inyección de dependencias como parámetros para 'Configurar'.
Eterno21
2
IHostingEnvironment env obsoleto use IWebHostEnvironment env en su lugar
Mark Schultheiss
19

Si necesita probar esto en algún lugar de su base de código que no tenga fácil acceso al entorno IHosting, otra forma fácil de hacerlo es así:

bool isDevelopment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development";
Patricio
fuente
bueno, camino corto! Tenga en cuenta que el nombre de la variable es diferente entre "asp.net core" y "asp.net"
nmDat
15

por los documentos

Configure y ConfigureServices admiten versiones específicas del entorno del formulario Configure {EnvironmentName} y Configure {EnvironmentName} Servicios:

Puedes hacer algo como esto ...

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
}
Zapato
fuente
1
Esta es la mejor convención
Stuart.Sklinar
11

Quería obtener el medio ambiente en uno de mis servicios. ¡Es realmente facil de hacer! Simplemente lo inyecto al constructor así:

    private readonly IHostingEnvironment _hostingEnvironment;

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

Ahora más adelante en el código puedo hacer esto:

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

EDITAR:

El código anterior es para .NET Core 2. Para la versión 3, querrá usar IWebHostEnvironment.

Encadenar
fuente
5

El entorno de alojamiento proviene de la variable de entorno ASPNET_ENV, que está disponible durante el inicio utilizando el método de extensión IHostingEnvironment.IsEnvironment, o uno de los métodos de conveniencia correspondientes de IsDevelopment o IsProduction. Guarde lo que necesita en Startup () o en la llamada ConfigureServices:

var foo = Environment.GetEnvironmentVariable("ASPNET_ENV");
Jeff Dunlop
fuente
IHostingEnvironmentNo está disponible en ConfigureServices.
Muhammad Rehan Saeed
1
No, no es. Refiérase a mi respuesta sobre cómo lidiar con eso.
Jeff Dunlop
8
La variable de entorno ahora es "ASPNETCORE_ENVIRONMENT"
Anthony
IHostingEnvironment env obsoleto use IWebHostEnvironment env en su lugar
Mark Schultheiss
5

Por si acaso alguien también está buscando esto. En .net core 3+ la mayoría de esto es obsoleto. La forma de actualización es:

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

En Dotnet Core 2.0, el constructor de inicio solo espera un parámetro IConfiguration.

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

¿Cómo leer el entorno de alojamiento allí? Lo almaceno en clase de programa durante ConfigureAppConfiguration (uso BuildWebHost completo en lugar 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();
    }

Ant luego lo lee en ConfigureServices así:

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    var isDevelopment = Program.HostingEnvironment.IsDevelopment();
}
toralux
fuente
IHostingEnvironment env obsoleto use IWebHostEnvironment env en su lugar
Mark Schultheiss