.Net 6.0配置文件

8

我一直在开发一个提供数据给VBA应用程序的应用程序,现在正在尝试获取配置文件(appsettings.json和appsettings.Development.Json)。目前它是一个.net6.0控制台应用程序,稍后我会将其制作成一个IconTrayApp。

遇到了一个问题,主要的Program.cs方法获取appsettings.json文件,而工作者则获取appssettings.Developement.json文件。我明白为什么Main()获取无环境JSON文件,因为我特意加载它。但我希望应用程序在IDE内外都使用相同的文件。

这是program.cs文件:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using PostDataService.InterfaceModels;
using Serilog;
using Serilog.Events;
using System;

namespace PostDataService
{
  public class Program
  {
    public static void Main(string[] args)
    {

      var builder = new ConfigurationBuilder()
        .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
      IConfiguration config = builder.Build();
      string _logFQN = config["PostConfig:Basefolder"] + config["PostConfig:LogsFolder"] + config["PostConfig:LogFname"];
      string _LogTemplate = config["PostConfig:LogTemplate"];

      var loggerConfig = new LoggerConfiguration()
        .MinimumLevel.Override("Microsoft", LogEventLevel.Verbose)
        .Enrich.FromLogContext()
        .Enrich.WithThreadId()
        .Enrich.WithEnvironmentUserName()
        .WriteTo.File(_logFQN,
        fileSizeLimitBytes: 524288000,
        rollOnFileSizeLimit: true,
        rollingInterval: RollingInterval.Day,
        outputTemplate: _LogTemplate);

      Log.Logger = loggerConfig.CreateLogger();
      try
      {
        Log.Write(LogEventLevel.Information, "Start USPS Data Server");
        CreateHostBuilder(args).Build().Run();
      }
      catch (Exception ex)
      {
        Log.Fatal(ex, "Host terminated unexpectedly");
      }
      finally
      {
        Log.Information("USPS Server stopped");
        Log.CloseAndFlush();
      }
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .UseSerilog()
            .ConfigureServices((hostContext, services) =>
            {
              IConfiguration configuration = hostContext.Configuration;
              WorkerOptions options = configuration.GetSection("PostConfig").Get<WorkerOptions>();
              services.AddSingleton(options);
              services.AddHostedService<Worker>();
            });

  }
}

这里是 appsettings.json 文件(appsettings.Development.json)。

{
  "PostConfig": {
    "BaseFolder": "./App_Data/",
    "LogsFolder": "logs/",
    "SystemFQN": "C:/Test/PostalDB/PostalData.db",
    "CustFQN": "C:/Test/PostalDB/PostalCustomer.db",
    "LogFname": "USPS_.log",
    "LogTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff}\t{EnvironmentUserName}\t[{Level:u4}]\t<{ThreadId}>\t{Message:lj}{NewLine}{Exception}"
  }
}

我曾尝试在配置生成器中使用 .AddEnvironmentVariables(),但似乎没有改变事情。 我怀疑是因为明确调用了 addjsonfile。


.AddJsonFile($"appsettings.{env.EnvironmentName}.json", true, true); - Guru Stron
@guru; env.EnvironmentName不存在,更具体地说,env未定义。 - Larry
3个回答

1

可能我表达不太清楚了,Worker获取的是appsettings.Development.json文件,这是正确的,因为我在VS中运行。我想要的是在Main()方法中以一种简洁的方式获得相同的行为。

我已经采取了Guru Stron的评论,并强制它包括appsettings.dev...文件,如下所示:

      var builder = new ConfigurationBuilder()
        .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
        .AddJsonFile($"appsettings.{Environments.Development}.json", optional: true, reloadOnChange: true);

这似乎可以正常工作,但感觉我在硬编码应该内置的东西。

另外,如果我从Windows文件浏览器运行应用程序,在主线程中会得到appsettings.development.json的值,但在worker类中是appsettings.json。 这是有道理的,因为根据构建器调用,文件appsettings.development.json会覆盖appsettings.json。这不是理想的。


这基本上是 ASP.NET Core 默认配置注册所做的事情(它还添加了一些其他来源)。相关 - Guru Stron

0
在控制台应用程序中,我建议将配置作为服务进行整合,使用Microsoft.Extensions.Hosting中提供的依赖注入服务。此服务已经预装在ASP.NET Web API和ASP.NET Web App模板中。这种方法可以方便地在应用程序之间重复使用组件和服务,简化单元测试,并有助于实施为这些平台发布的大量示例代码。
以下是在C#控制台应用程序中的基本实现,在Program.cs中。
//Add these packages
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

IHost host = Host.CreateDefaultBuilder(args).Build();

// Request the configuration abstraction from the service provider.
// The default configurtion file and location is appsettings.json in the project root
IConfiguration config = host.Services.GetRequiredService<IConfiguration>();

// Retrieve values from the config using their keys and target types.
int keyOneValue = config.GetValue<int>("KeyOne");
bool keyTwoValue = config.GetValue<bool>("KeyTwo");
string? keyThreeNestedValue = config.GetValue<string>("KeyThree:Message");

// Display the values on the console.
Console.WriteLine($"KeyOne = {keyOneValue}");
Console.WriteLine($"KeyTwo = {keyTwoValue}");
Console.WriteLine($"KeyThree:Message = {keyThreeNestedValue}");

// Application code that depends on the config can commence here.

await host.RunAsync();

{
    "Settings": {
        "KeyOne": 1,
        "KeyTwo": true,
        "KeyThree": {
            "Message": "Oh, that's nice...",
            "SupportedVersions": {
                "v1": "1.0.0",
                "v3": "3.0.7"
            }
        },
        "IPAddressRange": [
            "46.36.198.121",
            "46.36.198.122",
            "46.36.198.123",
            "46.36.198.124",
            "46.36.198.125"
        ]
    }
}

这将输出:
KeyOne = 1
KeyTwo = True
KeyThree:Message = Oh, that's nice...

关于 Windows Forms 应用程序,您可以采用类似的方法来实现配置依赖。以下是有关如何在 .NET 6.0 和 .NET 7.0 中实现依赖注入的链接:
如何在 WinForms 中使用依赖注入 如何在 WinForms 中使用依赖注入

-1

您的主要应用程序(主应用程序 - 第一个)使用任何 appsettings.json ,并且您需要在被调用的控制台应用程序(辅助应用程序 - 第二个)中使用相同的文件。

您可以通过args调用 2nd

1. 来自主程序的设置文件
例如位于“ C:\ appsettings.json”

{
  "AppName": "Value from main/primary/1st program AppSettings.json"
}

2. 从主程序调用
您可以使用参数SettingsFile发送任何文件名

dotnet .\CommandLineArgs.dll --SettingsFile=C:\appsettings.json
或者
.\CommandLineArgs.exe --SettingsFile=C:\appsettings.json

3. 次要程序的代码

public class Program
{
    public static void Main(string[] args)
    {
        var builder = new ConfigurationBuilder()
            .AddJsonFile(args.Where(a => a.Contains("SettingsFile")).First().Split("=")[1], optional: false, reloadOnChange: true);
        IConfiguration config = builder.Build();
        Console.WriteLine(config.GetValue<string>("AppName"));
        Console.ReadLine();
    }
}

输出
模拟PowerShell是主要程序。主要程序以参数SettingsFile并携带值C:\appsettings.json发送给Secondary。 次要程序将json文件名添加到配置构建器中并构建配置对象。

1

2

参考资料

Main()和命令行参数
命令行参数

██████████████████ ██████████████████

另一种实现方式。您可以在https://github.com/JomaStackOverflowAnswers/CommandLineArgs上查看代码。

PrimaryApp 代码
主应用程序目录必须包含次要应用程序的可执行文件。主应用程序使用设置文件名的参数启动次要应用程序。

using System.Diagnostics;

public class Program
{
    public async static Task Main(string[] args)
    {
        Console.WriteLine("██ PrimaryApp Started");
        var secondaryAppExeFilename = Path.GetFullPath("SecondaryApp/SecondaryApp.exe");
        var settingsFilename = Path.GetFullPath("appsettings.json"); // var settingsFilename = Path.GetFullPath("C:\appsettings.json");
        ProcessStartInfo info = new ProcessStartInfo();
        info.FileName = secondaryAppExeFilename;
        info.Arguments = $"--SettingsFile={settingsFilename}";
        info.WindowStyle = ProcessWindowStyle.Normal;
        Process process = new Process();
        process.StartInfo = info;
        process.Start();
        await process.WaitForExitAsync();
        Console.ReadLine();
        Console.WriteLine("█ PrimaryApp Exited");
    }
}

SecondaryAppCode
次要应用程序从命令行参数中捕获SettingsFilename参数,并使用该文件构建配置。

using Microsoft.Extensions.Configuration;

public class Program
{
    public static void Main(string[] args)
    {
        Console.WriteLine("██ SecondaryApp Started");
        string settingsFile = args.Where(a => a.Contains("SettingsFile")).First().Split("=")[1];
        var builder = new ConfigurationBuilder()
            .AddJsonFile(settingsFile, optional: false, reloadOnChange: true);
        IConfiguration config = builder.Build();
        Console.WriteLine($"SettingsFile: {settingsFile}");
        Console.WriteLine($"AppName value: {config.GetValue<string>("AppName")}");
        Console.ReadLine();
        Console.WriteLine("█SecondaryApp Exited");
    }
}

appsettings.json

{
  "AppName": "PrimaryApp"
}

输出
1

2


不错的想法,但我认为这个应用程序需要由最终用户重新启动,所以它可能会失败。是的,我可以构建一个CMD文件,但是一些IT部门出于网络安全考虑完全阻止了CMD文件。 - Larry
从主应用程序(.net应用程序)中,您可以使用Process类调用次要应用程序- https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.process?view=net-6.0 - Joma
你如何在DotNet6中实现这个(提示:没有主方法!) - MC9000
@MC9000,请查看此链接:https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/program-structure/top-level-statements,并查看“隐式入口点方法”部分。 - Joma

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接