So erhalten Sie die Entwicklungs- / Staging- / Produktions-Hosting-Umgebung in ConfigureServices

170

Wie erhalte ich die Entwicklungs- / Staging- / Produktions-Hosting-Umgebung in der ConfigureServicesMethode in Startup?

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

Die ConfigureServicesMethode akzeptiert nur einen einzigen IServiceCollectionParameter.

Muhammad Rehan Saeed
quelle
4
Warum kann nicht IHostingEnvironmenteinfach in ConfigureServices injiziert werden? Aufsicht? oder ein Grund, dessen wir uns bewusst sein müssen?
Simon_Weaver

Antworten:

224

Sie können in ConfigureServices problemlos darauf zugreifen. Behalten Sie es einfach während der Startmethode bei einer Eigenschaft bei, die zuerst aufgerufen und übergeben wird. Anschließend können Sie über ConfigureServices auf die Eigenschaft zugreifen.

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
quelle
13
Gemäß den Dokumenten sollte diese Methode nicht verwendet werden. Sie sollten stattdessen verwenden CurrentEnvironment.IsEnvironment("environmentname").
Vaindil
28
oder CurrentEnvironment.IsDevelopment()/CurrentEnvironment.IsProduction()
Simon_Weaver
3
@vaindil - Die Dokumente, auf die Sie verweisen, sagen nicht, dass diese Methode nicht verwendet werden sollte. Ihr Beispiel ignoriert einfach das Gehäuse, was in vielen Fällen vorzuziehen ist, aber kein Gebot
Coruscate5
3
@ Coruscate5 Okay, es heißt nicht explizit, diese Methode NICHT zu verwenden, aber es heißt, die andere Methode STATT zu verwenden. Das ist praktisch das Gleiche.
Vaindil
8
veraltete IHostingEnvironment env verwenden stattdessen IWebHostEnvironment env
Mark Schultheiss
56

TL; DR

Legen Sie eine Umgebungsvariable fest, die ASPNETCORE_ENVIRONMENTmit dem Namen der Umgebung aufgerufen wird (z Production. B. ). Dann machen Sie eines von zwei Dingen:

  • Inject IHostingEnvironmentin Startup.cs, dann verwenden ( envhier) zu überprüfen: env.IsEnvironment("Production"). Nicht mit prüfen env.EnvironmentName == "Production"!
  • Verwenden Sie entweder separate StartupKlassen oder Einzelpersonen Configure/ ConfigureServicesFunktionen. Wenn eine Klasse oder die Funktionen mit diesen Formaten übereinstimmen, werden sie anstelle der Standardoptionen in dieser Umgebung verwendet.
    • Startup{EnvironmentName}() (gesamte Klasse) || Beispiel:StartupProduction()
    • Configure{EnvironmentName}()|| Beispiel:ConfigureProduction()
    • Configure{EnvironmentName}Services()|| Beispiel:ConfigureProductionServices()

Vollständige Erklärung

In den .NET Core-Dokumenten wird beschrieben, wie dies erreicht wird . Verwenden Sie eine Umgebungsvariable namensASPNETCORE_ENVIRONMENT , die auf die gewünschte Umgebung festgelegt ist. Dann haben Sie zwei Möglichkeiten.

Überprüfen Sie den Umgebungsnamen

Aus den Dokumenten :

Der IHostingEnvironmentDienst bietet die Kernabstraktion für die Arbeit mit Umgebungen. Dieser Dienst wird von der ASP.NET-Hosting-Schicht bereitgestellt und kann über Dependency Injection in Ihre Startlogik eingefügt werden. Die ASP.NET Core-Websitevorlage in Visual Studio verwendet diesen Ansatz, um umgebungsspezifische Konfigurationsdateien (falls vorhanden) zu laden und die Einstellungen für die Fehlerbehandlung der App anzupassen. In beiden Fällen wird dieses Verhalten erreicht, indem auf die aktuell angegebene Umgebung durch Aufrufen EnvironmentNameoder IsEnvironmentauf die Instanz IHostingEnvironmentverwiesen wird, die an die entsprechende Methode übergeben wurde.

HINWEIS: Esenv.EnvironmentName wird nicht empfohlen, den tatsächlichen Wert von zu überprüfen!

Wenn Sie überprüfen müssen, ob die Anwendung in einer bestimmten Umgebung ausgeführt wird, verwenden env.IsEnvironment("environmentname")Sie , da die Groß- und Kleinschreibung korrekt ignoriert wird (anstatt env.EnvironmentName == "Development"beispielsweise zu prüfen, ob dies der Fall ist ).

Verwenden Sie separate Klassen

Aus den Dokumenten :

Wenn eine ASP.NET Core-Anwendung gestartet wird, wird die StartupKlasse verwendet, um die Anwendung zu booten, ihre Konfigurationseinstellungen zu laden usw. ( Weitere Informationen zum Starten von ASP.NET ). Wenn jedoch eine Klasse mit dem Namen Startup{EnvironmentName}(z. B. StartupDevelopment) vorhanden ist und die ASPNETCORE_ENVIRONMENTUmgebungsvariable mit diesem Namen übereinstimmt, Startupwird stattdessen diese Klasse verwendet. Sie können also Startupfür die Entwicklung konfigurieren , haben jedoch eine separate Konfiguration StartupProduction, die verwendet wird, wenn die App in der Produktion ausgeführt wird. Oder umgekehrt.

StartupSie können nicht nur eine vollständig separate Klasse verwenden, die auf der aktuellen Umgebung basiert, sondern auch Anpassungen an der Konfiguration der Anwendung innerhalb einer StartupKlasse vornehmen . Die Methoden Configure()und ConfigureServices()unterstützen umgebungsspezifische Versionen, die der StartupKlasse selbst, der Form Configure{EnvironmentName}()und ähneln Configure{EnvironmentName}Services(). Wenn Sie eine Methode definieren ConfigureDevelopment(), wird diese aufgerufen, anstatt Configure()wenn die Umgebung auf Entwicklung eingestellt ist. Ebenso ConfigureDevelopmentServices()würde statt ConfigureServices()in der gleichen Umgebung aufgerufen werden .

Vaindil
quelle
29

In der .NET Core 2.0MVC-App / Microsoft.AspNetCore.Allv2.0.0 können Sie eine umgebungsspezifische Startklasse haben, wie von @vaindil beschrieben, aber dieser Ansatz gefällt mir nicht.

Sie können auch IHostingEnvironmentin den StartUpKonstruktor injizieren . Sie müssen die Umgebungsvariable nicht in der ProgramKlasse speichern .

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
quelle
1
Details können eingesehen werden unter: docs.microsoft.com/pt-br/aspnet/core/fundamentals/…
André Morales
Hier ist der englische Link von André: docs.microsoft.com/en-us/aspnet/core/fundamentals/…
ahong
1
veraltete IHostingEnvironment-Umgebung verwenden stattdessen IWebHostEnvironment env
Mark Schultheiss
21

Dies kann ohne zusätzliche Eigenschaften oder Methodenparameter wie folgt erreicht werden:

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

    if (env.IsProduction()) DoSomethingDifferentHere();
}
edicius6
quelle
2
Die beste Antwort aller Zeiten. Danke
Shady Sherif
7
Dies löst in .NET Core 3.0 die folgende Warnung aus: Wenn Sie 'BuildServiceProvider' aus dem Anwendungscode aufrufen, wird eine zusätzliche Kopie der Singleton-Dienste erstellt. Betrachten Sie Alternativen wie Abhängigkeitsinjektionsdienste als Parameter für 'Konfigurieren'.
Eternal21
2
veraltete IHostingEnvironment-Umgebung verwenden stattdessen IWebHostEnvironment env
Mark Schultheiss
19

Wenn Sie dies irgendwo in Ihrer Codebasis testen müssen, die keinen einfachen Zugriff auf die IHostingEnvironment hat, können Sie dies auf einfache Weise folgendermaßen tun:

bool isDevelopment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development";
Patrick
quelle
na ja, kurzer weg! Beachten Sie, dass der Variablenname zwischen "asp.net core" und "asp.net" unterschiedlich ist
nmDat
14

gemäß den Dokumenten

Configure and ConfigureServices unterstützen umgebungsspezifische Versionen des Formulars Configure {EnvironmentName} und Configure {EnvironmentName} Services:

Sie können so etwas tun ...

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
}
Schuh
quelle
Dies ist die schönste Tagung
Stuart.Sklinar
11

Ich wollte die Umwelt in einen meiner Dienste einbeziehen. Es ist wirklich einfach zu tun! Ich injiziere es einfach so in den Konstruktor:

    private readonly IHostingEnvironment _hostingEnvironment;

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

Jetzt später im Code kann ich dies tun:

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

BEARBEITEN:

Der obige Code gilt für .NET Core 2. Für Version 3 möchten Sie verwenden IWebHostEnvironment.

Jess
quelle
5

Die Hosting-Umgebung stammt aus der Umgebungsvariablen ASPNET_ENV, die während des Startvorgangs mit der Erweiterungsmethode IHostingEnvironment.IsEnvironment oder einer der entsprechenden praktischen Methoden von IsDevelopment oder IsProduction verfügbar ist. Speichern Sie entweder das, was Sie benötigen, in Startup () oder im Aufruf von ConfigureServices:

var foo = Environment.GetEnvironmentVariable("ASPNET_ENV");
Jeff Dunlop
quelle
IHostingEnvironmentist nicht verfügbar in ConfigureServices.
Muhammad Rehan Saeed
1
Nein, ist es nicht. Beziehen Sie sich auf meine Antwort, wie ich damit umgehen soll.
Jeff Dunlop
8
Die Umgebungsvariable ist jetzt "ASPNETCORE_ENVIRONMENT"
Anthony
veraltete IHostingEnvironment-Umgebung Verwenden Sie stattdessen IWebHostEnvironment env
Mark Schultheiss
5

Nur für den Fall, dass sich auch jemand darum kümmert. In .net Core 3+ ist das meiste davon veraltet. Der Update-Weg ist:

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

In Dotnet Core 2.0 erwartet der Startup-Konstruktor nur einen IConfiguration-Parameter.

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

Wie lese ich dort die Hosting-Umgebung? Ich speichere es in der Program-Klasse während der ConfigureAppConfiguration (verwende den vollständigen BuildWebHost anstelle von 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 liest es dann in ConfigureServices wie folgt:

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    var isDevelopment = Program.HostingEnvironment.IsDevelopment();
}
Toralux
quelle
veraltete IHostingEnvironment-Umgebung verwenden stattdessen IWebHostEnvironment env
Mark Schultheiss