.NET Core-Konsolenanwendung, wie konfiguriere ich appSettings pro Umgebung?

73

Ich habe eine .NET Core 1.0.0-Konsolenanwendung und zwei Umgebungen. Ich muss den Einsatz in der Lage sein appSettings.dev.jsonund appSettings.test.jsonbasiert auf Umgebungsvariablen ich zur Laufzeit festgelegt. Dies scheint für ASP.NET Core-Webanwendungen über die Abhängigkeitsinjektion und IHostingEnvironment sowie die EnvironmentName-Umgebung recht einfach zu sein. Variable, aber wie soll ich die Dinge für die Konsolenanwendung verkabeln (außer meinen eigenen benutzerdefinierten Code zu schreiben, der verwendet Microsoft.Framework.Configuration.EnvironmentVariables)?

Vielen Dank.

user2916547
quelle

Antworten:

97

So machen wir es in unserer .netcoreKonsolen-App. Der Schlüssel hier ist, die richtigen Abhängigkeiten von Ihrem Projekt aufzunehmen ( möglicherweise nicht alle, überprüfen Sie basierend auf Ihren Anforderungen ) und zu kopieren, um die appSetting.json als Teil Ihrer Build-Optionen auszugeben

  {
    "buildOptions": {
    "emitEntryPoint": true,
    "copyToOutput": {
       "include": [
       "appsettings*.json",
       "App*.config"
                 ]
          }
},

  using Microsoft.Extensions.Configuration;
  namespace MyApp
  {
    public static void Main(string[] args)
    {
        var environmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");


        var builder = new ConfigurationBuilder()
            .AddJsonFile($"appsettings.json", true, true)
            .AddJsonFile($"appsettings.{environmentName}.json", true, true)
            .AddEnvironmentVariables();
        var configuration = builder.Build();
        var myConnString= configuration.GetConnectionString("SQLConn");
    }

}}

Jaya
quelle
4
Vielen Dank. Ich habe schließlich eine verschlungenere Version davon verwendet, verwendet new ConfigurationBuilder().AddEnvironmentVariables()und gefunden ASPNETCORE_ENVIRONMENT.
user2916547
1
Ich denke, Sie sollten ein Nuget- Microsoft.Extensions.Configuration.JsonNuget-Paket hinzufügen : docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/…
Junior Mayhé
2
Wie funktioniert diese Environment.GetEnvironmentVariable ("ASPNETCORE_ENVIRONMENT") ohne Verweis auf Microsoft.AspNetCore.Hosting?
HaBo
2
Mit der neuen csproj-Struktur würden Sie <ItemGroup> <None Update = "appsettings * .json"> <CopyToOutputDirectory> PreserveNewest </ CopyToOutputDirectory> </ None> </ ItemGroup>
Thulani Chivandikwa
1
Bitte aktualisieren Sie Ihre Antwort. Anscheinend gibt es keine Notwendigkeit in json Teil Ihres Codebeispiels ...
Akmal Salikhov
16

Für diejenigen, die .NET Core Version 2.1.0+ und Microsoft.Extensions.Hosting zum Hosten Ihrer Konsolen-App verwenden, können Sie den folgenden Code verwenden (gemäß der Antwort von Feiyu Zhou in einem anderen Thread):

var hostBuilder = new HostBuilder()
    .ConfigureHostConfiguration(config =>
    {
        if (args != null)
        {
            // enviroment from command line
            // e.g.: dotnet run --environment "Staging"
            config.AddCommandLine(args);
        }
    })
    .ConfigureAppConfiguration((context, builder) =>
    {
        builder.SetBasePath(AppContext.BaseDirectory)
            .AddJsonFile("appsettings.json", optional: false)
            .AddJsonFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.json", optional: true);
    })
victorm1710
quelle
9

Es gibt zwei IHostingEnvironmentSchnittstellen, die Sie verwenden sollten. Eine ist für ASP.NET Core-Anwendungen, die andere für .NET Core Console-Anwendungen. Sie können dieses Codebeispiel für beide verwenden:

using System;
using System.IO;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting.Internal;

namespace MyApplication.Common
{
    public static class ConfigurationFactory
    {
        /// <summary>
        /// Use for ASP.NET Core Web applications.
        /// </summary>
        /// <param name="config"></param>
        /// <param name="env"></param>
        /// <returns></returns>
        public static IConfigurationBuilder Configure(IConfigurationBuilder config, IHostingEnvironment env)
        {
            return Configure(config, env.EnvironmentName);
        }

        /// <summary>
        /// Use for .NET Core Console applications.
        /// </summary>
        /// <param name="config"></param>
        /// <param name="env"></param>
        /// <returns></returns>
        private static IConfigurationBuilder Configure(IConfigurationBuilder config, Microsoft.Extensions.Hosting.IHostingEnvironment env)
        {
            return Configure(config, env.EnvironmentName);
        }

        private static IConfigurationBuilder Configure(IConfigurationBuilder config, string environmentName)
        {
            return config
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                .AddJsonFile($"appsettings.{environmentName}.json", optional: true, reloadOnChange: true)
                .AddEnvironmentVariables();
        }

        /// <summary>
        /// Use for .NET Core Console applications.
        /// </summary>
        /// <returns></returns>
        public static IConfiguration CreateConfiguration()
        {
            var env = new HostingEnvironment
            {
                EnvironmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"),
                ApplicationName = AppDomain.CurrentDomain.FriendlyName,
                ContentRootPath = AppDomain.CurrentDomain.BaseDirectory,
                ContentRootFileProvider = new PhysicalFileProvider(AppDomain.CurrentDomain.BaseDirectory)
            };

            var config = new ConfigurationBuilder();
            var configured = Configure(config, env);
            return configured.Build();
        }
    }
}
MovGP0
quelle
Namespace "Version" der Konsolen-App "Microsoft.Extensions.Hosting", Schnittstelle "IHostingEnvironment", Assembly-Datei: "microsoft.extensions.hosting.abstractions \ 2.1.1 \ lib \ netstandard2.0 \ Microsoft.Extensions.Hosting.Abstractions.dll" "
GranadaCoder
1
Hier ist die Liste der Nuget-Pakete, die ich hinzufügen musste, damit dieser Code funktioniert. <PackageReference I = "Microsoft.AspNetCore.Hosting.Abstractions" Version = "2.1.1" /> <PackageReference I = "Microsoft.Extensions.Configuration" Version = "2.1.1" /> <PackageReference Include = "Microsoft.Extensions .Configuration.EnvironmentVariables "Version =" 2.1.1 "/> <PackageReference I =" Microsoft.Extensions.Configuration.Json "Version =" 2.1.1 "/> <PackageReference I =" Microsoft.Extensions.Hosting "Version =" 2.1.1 "/> <PackageReference I =" Microsoft.Extensions.Hosting.Abstractions "Version =" 2.1.1 "/>
granadaCoder
Sollte ich eine Abhängigkeit vom Microsoft.AspNetCore-Namespace in einem Konsolen-App-Projekt erstellen?
Rafael
1
<Project Sdk = "Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework> netcoreapp3.1 </ TargetFramework> </ PropertyGroup> <ItemGroup> <PackageReference Include = "Microsoft.Extensions.Configuration" Version = "3.1.0" /> <PackageReference Include = "Microsoft.Extensions.Configuration.EnvironmentVariables" Version = "3.1.0" /> <PackageReference Include = "Microsoft.Extensions.Configuration.Json" Version = "3.1.0" /> <PackageReference Include = "Microsoft.Extensions.Hosting" Version = "3.1.0" />
granadaCoder
1
</ ItemGroup> <ItemGroup> <FrameworkReference Include = "Microsoft.AspNetCore.App" /> </ ItemGroup> </ Project>
granadaCoder
4

Diese Umweltsachen scheinen für die meisten Menschen zu funktionieren, aber ich bin mit all dem Umweltmanagement überhaupt nicht einverstanden. Ob die Laufzeit oder das Zielsystem weiß, was es ist. Nur Sie als Entwickler oder Bereitstellungsmechanismus kennen das Zielsystem.

Alle reden über die Variable ASPNETCORE_ENVIRONMENT, sogar über die offizielle Dokumentation wie hier https://docs.microsoft.com/en-us/aspnet/core/fundamentals/environments?view=aspnetcore-3.0. Tatsächlich muss jemand ein System explizit als Produktionssystem definieren, indem er beispielsweise ASPNETCORE_ENVIRONMENT einmal manuell einstellt. Möchten Sie wirklich davon ausgehen und sich darauf verlassen, dass dies bereits in jeder von Ihnen verwendeten Umgebung festgelegt ist? Nein, das kannst du nicht. Was ist, wenn Sie eine Konsolen-App auf einem Batch-Server bereitstellen müssen, auf dem keine Website ausgeführt wird? ASPNETCORE_ENVIRONMENT ist nicht verfügbar. Was ist, wenn Sie eine .net Core-Webapi ohne IIS nur mit Turmfalke bereitstellen und ausführen müssen? Keine web.config und keine Umgebungsvariable. Möchten Sie, dass Ihre Administratoren / Ihr Betriebsteam diese irreführende Variable für Ihre Konsolen-App festlegen? In diesem Zusammenhang habe ich viele Projekte gesehen, die Appsettings wie dieses pro Projekt haben:

appsettings.json
appsettings.development.json
appsettings.test.json
appsettings.uat.json
appsettings.staging.json
appsettings.production.json

Beachten Sie, dass standardmäßig jede dieser Dateien veröffentlicht und auch auf dem Zielsystem bereitgestellt wird. Auf den ersten Blick sieht es sehr einfach aus, die Umgebung "entscheiden" zu lassen, welche Konfiguration verwendet werden soll. Sie haben jedoch Konfiguration und möglicherweise auch Anmeldeinformationen auf einem System bereitgestellt, das nicht für dieses System vorgesehen ist.

Fazit

Ich empfehle appsettings.json + appsettings.release.json. Erstens ist nur für Entwickler. Ändere es, spiele damit, wie du willst. Die letzte ist eine GÜLTIGE Konfiguration, die für die Bereitstellung (den Prozess) bereit ist. Transformieren Sie die Konfiguration vor Beginn der Bereitstellung so, dass sie für das Zielsystem bereit ist. Das ist es. Keine Notwendigkeit, sich auf Einstellungen auf dem Zielcomputer zu verlassen, keine unordentlichen Konfigurationen. Behalten Sie die volle Kontrolle über Ihre App, auch wenn sich Server schnell ändern (z. B. Skalierung im Allgemeinen, VMs, Cloud usw.).

Ich freue mich über konstruktives Feedback :-)

Steve Rakebrandt
quelle
Sie verpassen den Punkt etwas und ja, die Bedingung könnte durch einen Konfigurationswert anstelle einer Umgebungsvariablen bestimmt werden. Ich habe ein anderes App-Verhalten in Web-APIs, in denen Entwickler mit swagger Endpunkte untersuchen und testen. Mit einem konsistenten Release-Management-Prozess, bei dem dieselben Binärdateien in eine Produktionsumgebung übertragen werden, muss diese Funktion umgeschaltet werden. Ob dies durch die Konfigurationseinstellung pro App / Umgebung oder durch eine einzelne Umgebungsvariable erreicht wird, spielt keine Rolle, außer dass die Umgebungseinstellungen im Gegensatz zu App-Konfigurationen für alle Apps auf demselben Server gelten.
Antony Booth
3

Sie können dies für die Umgebungsvariable ASP.Net Core (ASPNETCORE_ENVIRONMENT) tun: -

using Microsoft.AspNetCore.Hosting;
using System;

public class Program {
    private static string HostingEnvironment => Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
    private static bool IsEnvironment(string environmentName) => HostingEnvironment?.ToLower() == environmentName?.ToLower() && null != environmentName;

    private static bool Development => IsEnvironment(EnvironmentName.Development);
    private static bool Production => IsEnvironment(EnvironmentName.Production);
    private static bool Staging => IsEnvironment(EnvironmentName.Staging);

    public static void Main(string[] args) { // Your code here }
}

Dann können Sie einfach die Eigenschaft verwenden

    public static void Main(string[] args) {
        if (Development){
            // Blow up the planet
        }
    }
Antony Booth
quelle
4
Die Frage betraf nicht den asp.net-Kern.
Miklós Tóth
1
Ich weiß, aber die einzigen Dinge, die im Zusammenhang mit dem asp.net-Kern stehen, sind der Name der Umgebungsvariablen und die .net-Kernbibliothek, die zum Abrufen der Zeichenfolgenkonstanten für 'Entwicklung', 'Staging' und 'Produktion' verwendet werden. Ich dachte, es wäre nützlich, eine legitime Umgebungsvariable anstelle einer von mir erstellten zu verwenden. Es könnte alles sein und überhaupt nicht in einer asp.net-Kernanwendung.
Antony Booth
1
Ist dieser (und seine Geschwister) mehr "NON asp.net (core)"? docs.microsoft.com/en-us/dotnet/api/…
granadaCoder
3

Wenn Sie wie ich einfach versuchen, eine andere Konfigurationsdatei für den Release- und Entwicklungsmodus zu erstellen, fügen Sie einfach eine Datei appsettings.Development.json hinzu, wobei die Einstellung CopyToOutputDirectory im Eigenschaftenfenster der Datei auf true festgelegt ist.

Um nun abhängig von der Build-Konfiguration auf die Datei zuzugreifen, können Sie die Präprozessor-Direktive #if DEBUG verwenden .

Hier ist ein Beispiel:

static void Main(string[] args)
{

#if DEBUG
    var builder = new ConfigurationBuilder()
            .AddJsonFile($"appsettings.Development.json", true, true);
#else
    var builder = new ConfigurationBuilder()
            .AddJsonFile($"appsettings.json", true, true);
#endif

    var configuration = builder.Build();

    // ... use configuration
}
Chaosifier
quelle
1
Dies ist eine schlechte Lösung, da sie Kompilierungsfehler verbergen kann, die dann sichtbar werden, wenn Sie auf einen Build-Server pushen und die Direktive wahr / falsch wird. Es ist viel besser, eine Umgebungsvariable zu verwenden. Ich urteile jedoch nicht - ich habe dies in der Vergangenheit viele Male getan, es ist nur so, dass ich auf das Problem gestoßen bin, das ich einige Male erwähnt habe.
JCVANDAN
Ich würde empfehlen, dass Sie immer die appsettings.jsonDatei hinzufügen (die das Problem von @ jcvandan behebt, sie niemals zu laden) und #if DEBUG auch die appsettings.Development.json- die Standardmethode besteht darin, der Entwicklung zu erlauben, Einstellungen bei Bedarf zu überschreiben, ohne sie alle angeben zu müssen.
Oatsoda
2

Für eine Dotnet 2.x-Kernkonsolenanwendung ist dies ungefähr so:

        using Microsoft.Extensions.Configuration;
        using Microsoft.Extensions.DependencyInjection;
        using Microsoft.Extensions.Logging;

        [...]
        var configuration = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
            .AddEnvironmentVariables()
            .Build();
        var serviceProvider = new ServiceCollection()
            .AddLogging(options => options.AddConfiguration(configuration).AddConsole())
            .AddSingleton<IConfiguration>(configuration)
            .AddSingleton<SomeService>()
            .BuildServiceProvider();
        [...]
        await serviceProvider.GetService<SomeService>().Start();

Das könnten Sie ILoggerFactory, IConfiguration in die injizieren SomeService.

lnaie
quelle