如何强制Dotnet6桌面Winforms应用程序使用appsettings.json而不是Settings.settings?

2023-12-05

如何强制 Dotnet6 桌面 Winforms 应用程序使用 appsettings.json 而不是 Settings.settings[App.config]?

如果我在 Visual Studio 2022 中创建一个新的桌面应用程序以使用 Dotnet6.0,默认情况下,它会动态创建一个 Settings.settings 文件,然后也会创建一个 App.config 文件(这很奇怪,因为据说该文件已被弃用)在 Dotnet5.0 及更高版本中!)。

不幸的是,所有设置在安装/发布后都嵌入到应用程序中,并且一旦安装,就无法在应用程序文件夹中的任何位置进行更改。

对于较旧的 DotNet4.72 桌面应用程序,app.config 始终位于发布输出中,如果发生更改,应用程序将在执行时很好地读取任何更改。

我想像 Web 应用程序 (dotnet6.0) 一样使用 appsettings.json,并且有很多关于如何使用控制台应用程序 (dotnet6.0) 执行此操作的信息,但不适用于桌面窗口。

我有很多想要转换的 DotNet4.72 桌面应用程序,但它们仍然需要能够通过动态编辑文件(如果条件发生变化)来简单地更改配置设置。虽然我可以自己滚动解决方案,我想像在我的网络应用程序(appsettings.json)中那样执行此操作。更好的是,我希望看到一个 VS2022 桌面模板,每次为 DotNet6 和 7 创建新的桌面应用程序时都会执行此操作。

有任何想法吗?


基本上你可以使用Microsoft.Extensions.Configuration但你也可以利用Microsoft.Extensions.Hostingnuget 包也是如此。

这是一个经过测试的工作示例,也可以处理配置更改。

Steps:

  • Add an appsettings.json file to the project.
    • Set Build Action to None.
    • Set Copy to Output Directory to Copy always.
  • 为您的选项创建一个类。 (在此示例中:SampleOptions)
  • 配置您的选项appsettings.json.
  • Add Microsoft.Extensions.Hostingnuget 包到您的项目中。
  • Modify Program.cs:
    • 配置并构建主机。 (例如,将您的表格、选项注册到 DI 中)
    • 启动主机。
    • Resolve IHostApplicationLifetime.
    • 创建一个IServiceScope使用主机的IServiceProvider.
    • 解决你的MainForm.
    • Call Application.Run()方法与你解决的MainForm实例。
  • Modify MainForm.cs:
    • Inject IOptionsMonitor<SampleOptions>进入.ctor
    • 注册一个监听器,每当SampleOptions changes
      using IOptionsMonitor<SampleOptions>.OnChange method.

这是文件。

应用程序设置.json

{
  "Logging": {
    "LogLevel": {
      "Default": "Information"
    }
  },
  "SampleOptions": {
    "SampleStringKey": "Sample value",
    "SampleIntegerKey": 42
  }
}

示例选项.cs

namespace WinFormsAppNet6;

public class SampleOptions
{
    public string SampleStringKey { get; set; } = "N/A";

    public int SampleIntegerKey { get; set; }
}

程序.cs

using System;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace WinFormsAppNet6;

internal static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static async Task Main() // <-- 'async Task' instead of 'void'
    {
        // To customize application configuration such as
        // set high DPI settings or default font,
        // see https://aka.ms/applicationconfiguration.
        ApplicationConfiguration.Initialize();

        using IHost host = CreateHost();
        await host.StartAsync();

        IHostApplicationLifetime lifetime = 
            host.Services.GetRequiredService<IHostApplicationLifetime>();

        using (IServiceScope scope = host.Services.CreateScope())
        {
            var mainForm = scope.ServiceProvider.GetRequiredService<MainForm>();

            Application.Run(mainForm);
        }

        lifetime.StopApplication();
        await host.WaitForShutdownAsync();
    }

    private static IHost CreateHost()
    {
        string[] args = Environment.GetCommandLineArgs().Skip(1).ToArray();

        HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

        builder.Services.AddSingleton<MainForm>();

        builder.Services.Configure<SampleOptions>(
            builder.Configuration.GetSection(nameof(SampleOptions))
        );

        return builder.Build();
    }
}

MainForm.cs

控制:

  • Button: UpdateConfigurationButton
  • Button: ExitButton
  • RichTextBox: AppLog
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Windows.Forms;

using Microsoft.Extensions.Options;

namespace WinFormsAppNet6;

public partial class MainForm : Form
{
    private readonly IOptionsMonitor<SampleOptions> optionsMonitor;

    private readonly JsonSerializerOptions jsonSerializerOptions =
        new(JsonSerializerDefaults.Web)
        {
            WriteIndented = true
        };

    public MainForm(IOptionsMonitor<SampleOptions> optionsMonitor)
    {
        InitializeComponent();

        this.optionsMonitor = optionsMonitor;
        optionsMonitor.OnChange(OnOptionsChange);

        LogOptions(optionsMonitor.CurrentValue);
    }

    private void OnOptionsChange(SampleOptions options)
    {
        LogOptions(options);
    }

    private void LogOptions(
        SampleOptions options,
        [CallerMemberName] string? callerMemberName = null
    )
    {
        AppendLog(
            Environment.NewLine + JsonSerializer.Serialize(options),
            callerMemberName
        );
    }

    private void AppendLog(
        string message,
        [CallerMemberName] string? callerMemberName = null
    )
    {
        if (AppLog.InvokeRequired)
        {
            AppLog.Invoke(() => AppendLog(message, callerMemberName));
            return;
        }

        AppLog.AppendText(
            $"{DateTimeOffset.Now:yyyy-MM-dd HH:mm:ss.ffffff} [{nameof(MainForm)}]::[{callerMemberName ?? "Unknown"}] {message}{Environment.NewLine}"
        );
    }

    private void UpdateConfigurationButton_Click(object sender, EventArgs e)
    {
        const string AppSettingsJsonFileName = "appsettings.json";

        if (!File.Exists(AppSettingsJsonFileName))
        {
            AppendLog(
                $"{nameof(FileNotFoundException)}: {AppSettingsJsonFileName}"
            );

            return;
        }

        string jsonContent = File.ReadAllText(AppSettingsJsonFileName);
        JsonNode? rootNode = JsonNode.Parse(jsonContent);

        if (rootNode is null)
        {
            AppendLog($"{nameof(JsonException)}: File parse failed.");
            return;
        }

        AppendLog(
            $"Finding key: {nameof(SampleOptions)}:{nameof(SampleOptions.SampleStringKey)}"
        );

        JsonObject rootObject = rootNode.AsObject();
        JsonObject? optionsObject = rootObject[nameof(SampleOptions)]?.AsObject();

        if (optionsObject is null)
        {
            AppendLog(
                $"{nameof(KeyNotFoundException)}: {nameof(SampleOptions)}:{nameof(SampleOptions.SampleStringKey)}"
            );

            return;
        }

        AppendLog(
            $"Updating key: {nameof(SampleOptions)}:{nameof(SampleOptions.SampleStringKey)}"
        );

        optionsObject[nameof(SampleOptions.SampleStringKey)] =
            JsonValue.Create(
                $"Value modified at {DateTimeOffset.Now:yyyy-MM-dd HH:mm:ss.ffffff}"
            );

        AppendLog($"Saving file: {AppSettingsJsonFileName}");

        using var stream =
            new FileStream(
                AppSettingsJsonFileName,
                FileMode.OpenOrCreate,
                FileAccess.Write,
                FileShare.None
            );

        jsonContent = rootObject.ToJsonString(jsonSerializerOptions);

        stream.Write(Encoding.UTF8.GetBytes(jsonContent));
        stream.Flush();
    }

    private void ExitButton_Click(object? sender, EventArgs e)
    {
        Application.Exit();
    }
}

Screenshot Running the sample application

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何强制Dotnet6桌面Winforms应用程序使用appsettings.json而不是Settings.settings? 的相关文章

  • 使用 Unity 在构造函数中使用属性依赖注入

    好的 我在基类中定义了一个依赖属性 我尝试在其派生类的构造函数内部使用它 但这不起作用 该属性显示为 null Unity 在使用 container Resolve 解析实例后解析依赖属性 我的另一种选择是将 IUnityContaine
  • 启动时出现 OData v4 错误:找不到段“Whatever”的资源

    我正在构建新的 v4 服务 一切进展顺利 直到我为新模型 实体添加了新控制器 并在启动站点进行测试运行时收到此错误 控制器似乎编码正确 就像其他控制器一样 控制器 CustomersOData 中的操作 GetFeed 上的路径模板 Cus
  • 如何在 C# 中从 UNIX 纪元时间转换并考虑夏令时?

    我有一个从 unix 纪元时间转换为 NET DateTime 值的函数 public static DateTime FromUnixEpochTime double unixTime DateTime d new DateTime 19
  • 单元测试一起运行时失败,单独运行时通过

    所以我的单元测试遇到了一些问题 我不能只是将它们复制并粘贴到这里 但我会尽力而为 问题似乎是 如果我一项一项地运行测试 一切都会按预期进行 但如果我告诉它一起运行测试 则 1 5 将通过 TestMethod public void Obj
  • 如何在 Linq 中获得左外连接?

    我的数据库中有两个表 如下所示 顾客 C ID city 1 Dhaka 2 New york 3 London 个人信息 P ID C ID Field value 1 1 First Name Nasir 2 1 Last Name U
  • Rx 中是否有与 Task.ContinueWith 运算符等效的操作?

    Rx 中是否有与 Task ContinueWith 运算符等效的操作 我正在将 Rx 与 Silverlight 一起使用 我正在使用 FromAsyncPattern 方法进行两个 Web 服务调用 并且我想这样做同步地 var o1
  • 未经许可更改内存值

    我有一个二维数组 当我第一次打印数组的数据时 日期打印正确 但其他时候 array last i 的数据从 i 0 到 last 1 显然是一个逻辑错误 但我不明白原因 因为我复制并粘贴了 for 语句 那么 C 更改数据吗 I use g
  • PlaySound 可在 Visual Studio 中运行,但不能在独立 exe 中运行

    我正在尝试使用 Visual Studio 在 C 中播放 wav 文件 我将文件 my wav 放入项目目录中并使用代码 PlaySound TEXT my wav NULL SND FILENAME SND SYNC 我按下播放按钮 或
  • C++:.bmp 到文件中的字节数组

    是的 我已经解决了与此相关的其他问题 但我发现它们没有太大帮助 他们提供了一些帮助 但我仍然有点困惑 所以这是我需要做的 我们有一个 132x65 的屏幕 我有一个 132x65 的 bmp 我想遍历 bmp 并将其分成小的 1x8 列以获
  • Visual Studio 中的测试单独成功,但一组失败

    当我在 Visual Studio 中单独运行测试时 它们都顺利通过 然而 当我同时运行所有这些时 有些通过 有些失败 我尝试在每个测试方法之间暂停 1 秒 但没有成功 有任何想法吗 在此先感谢您的帮助 你们可能有一些共享数据 检查正在使用
  • 如何将自定义 JSON 文件添加到 IConfiguration 中?

    我正在使用 asp net Autofac 我正在尝试加载自定义 JSON 配置文件 并基于该文件创建 实例化 IConfiguration 实例 或者至少将我的文件包含到默认情况下构建的 IConfiguration asp net 中
  • std::async 与重载函数

    可能的重复 std bind 重载解析 https stackoverflow com questions 4159487 stdbind overload resolution 考虑以下 C 示例 class A public int f
  • 有人可以提供一个使用 Amazon Web Services 的 itemsearch 的 C# 示例吗

    我正在尝试使用 Amazon Web Services 查询艺术家和标题信息并接收回专辑封面 使用 C 我找不到任何与此接近的示例 所有在线示例都已过时 并且不适用于 AWS 的较新版本 有一个开源项目CodePlex http www c
  • .NET中的LinkedList是循环链表吗?

    我需要一个循环链表 所以我想知道是否LinkedList是循环链表吗 每当您想要移动列表中的 下一个 块时 以循环方式使用它的快速解决方案 current current Next current List First 电流在哪里Linke
  • Server.MapPath - 给定的物理路径,预期的虚拟路径

    我正在使用这行代码 var files Directory GetFiles Server MapPath E ftproot sales 在文件夹中查找文件 但是我收到错误消息说 给定物理路径但虚拟路径 预期的 我对在 C 中使用 Sys
  • 编译时“strlen()”有效吗?

    有时需要将字符串的长度与常量进行比较 例如 if line length gt 2 Do something 但我试图避免在代码中使用 魔法 常量 通常我使用这样的代码 if line length gt strlen Do somethi
  • 英特尔 Pin 与 C++14

    问题 我有一些关于在 C 14 或其他 C 版本中使用英特尔 Pin 的问题 使用较新版本从较旧的 C 编译代码很少会出现任何问题 但由于 Intel Pin 是操作指令级别的 如果我使用 C 11 或 C 14 编译它 是否会出现任何不良
  • memset 未填充数组

    u32 iterations 5 u32 ecx u32 malloc sizeof u32 iterations memset ecx 0xBAADF00D sizeof u32 iterations printf 8X n ecx 0
  • 防止在工厂方法之外实例化对象

    假设我有一个带有工厂方法的类 class A public static A newA Some code logging return new A 是否可以使用 a 来阻止此类对象的实例化new 那么工厂方法是创建对象实例的唯一方法吗 当
  • 如何正确使用 std::condition_variable?

    我很困惑conditions variables以及如何 安全 使用它们 在我的应用程序中 我有一个创建 gui 线程的类 但是当 gui 是由 gui 线程构造时 主线程需要等待 情况与下面的函数相同 主线程创建互斥体 锁和conditi

随机推荐

  • 在 JSON.NET 中将整数序列化为十六进制

    JSON NET 支持反序列化十六进制数 e g 0xffff 但是怎么样序列化 以下有效 但似乎太复杂 public sealed class HexJsonConverter JsonConverter public override
  • java Regex - 分割但忽略引号内的文本?

    仅使用正则表达式方法 方法 String replaceAll 和 ArrayList 如何将字符串拆分为标记 但忽略引号内存在的分隔符 分隔符是非字母数字或引用文本的任何字符 例如 字符串 你好 世界 这个 有两个令牌 应该输出 hell
  • Google Cloud CDN 以存储桶为后端签署 cookie

    作为替代方案签名网址带有 url 前缀 我试图获取签名cookie在职的 Google Cloud CDN 设置了一个后端存储桶 该存储桶已配置并适用于标准签名网址 使用这些去例子我在nodejs typescript 中实现了一个cook
  • 使用 -lpthread 标志时对“pthread_init”的未定义引用:

    我正在编译使用 gcc o outfile infile c lpthread 唯一未定义的参考是pthread init 我尝试过使用 pthread代替 lpthread 根据网上的一些建议 I am包括
  • 更改 Firemonkey StringGrid 中的文本大小

    如何更改 stringgrid 标题中的文本大小 你可以写一个OnApplyStyleLookup事件处理程序与此类似 procedure TForm1 StringGrid1ApplyStyleLookup Sender TObject
  • 从代码隐藏中打开 jQuery 对话框

    所以我必须从代 码隐藏中显示一个 jquery UI 对话框 我已经尝试了一切 this this this 并且还更改了这些答案以测试它是否适用于我但不起作用 我使用第一个解决方案 因为它是有组织的 如果我使用alert whatever
  • 使用默认触发器在窗口中消耗无限数据

    我有一个Pub Sub主题 订阅 并希望在一个订阅中消费和聚合无限数据Dataflow 我使用固定窗口并将聚合写入 BigQuery 读取和写入 没有窗口和聚合 工作正常 但是 当我将数据通过管道传输到固定窗口 以计算每个窗口中的元素 时
  • 如何在 OCaml 中使用列表实现二叉堆?

    我正在实施一个binary heap在 OCaml 中使用列表 只是为了提高我的 OCaml 技能 我觉得使用列表非常困难 经过两天的努力 我必须来这里寻求建议和提示 到目前为止 这是我的想法 显然我不能使用原来的array based使用
  • Android - AutoCompleteTextView 仅在退格时有效

    我有一个AutoCompleteTextView当用户键入时动态更新建议列表 我的问题是 当我输入时 列表会更新 但下拉列表不会显示 但是当我删除一个字符 退格键 时 会出现下拉菜单 我什至尝试明确地调用autoText showDropD
  • Python Tkinter 坐标函数不会在循环内移动画布对象

    我有一个函数 它从文本文件中读取位置 解析它们 然后使用 coords 函数将相应的对象移动到 tkinter 画布上列出的位置 正在从文件中读取数据并正确解析数据 但由于某种原因 coords 函数仅将对象移动到循环的最后一次迭代中文件中
  • WordPress:一页滚动 JQuery 脚本不起作用?

    尝试创建一个简单的一页滚动 在 WordPress 中 我有这样的导航标签 a href contact Contact a a href about About a 两个链接对应的 div 是这样的 div class bg 1 wrap
  • Grails 安全插件自定义重定向

    我是 Groovy 和 Grails 的新手 我使用 Spring Security 插件使用数据库请求的请求映射开发了一个应用程序 我想要根据角色自定义重定向到主页 如果用户是 ROLE ADMIN 他将被重定向到视图 adminUser
  • 从 https 中删除 www

    我正在尝试找到一个 htaccess 重写来删除 www 仅来自 https 页面 我发现的每篇文章都删除了所有页面的 www 我需要在 htaccess 中添加什么来执行此操作 https www mydomain com应该https
  • 当行值等于“yes”时连接 Google 表格中的标题值的数组公式

    I saw this问题但无法让它为我工作 因为它已经得到回答 并且从一年前开始 我觉得最好发布一个新问题 我有一个样本表 https docs google com spreadsheets d 1EqNfTWcNFgkv2gdovnH7
  • 返回多个变量以在 Laravel 中查看的最佳方法

    我有一个操作方法 其主体中有多个变量 如下所示 bus Bus all user User all employer employer all 将这些变量对象返回到视图正在做的事情是使用这样的代码 return view create gt
  • 使用 Nodejs 的 SendGrid 模板中的变量替换不起作用

    继USE CASE在 SendGrids github 上确实设法向我发送带有正确模板的电子邮件 但替换显然不起作用 并且在生成的电子邮件中留空 服务器端 const sgmailer require sendgrid mail sgmai
  • 使用 Protractor 设置 Angular 模型

    我正在尝试使用 Protractor 在我的网站上模拟用户故事 用户必须输入使用自动完成功能的输入 在现实生活中 用户必须在输入中键入一些文本 然后使用鼠标或更自然地使用向下箭头键选择正确的命题 问题是我似乎无法用 Protractor 来
  • 什么是 WINAPI_FAMILY_ONECORE_APP?

    我正在 GitHub 上查看 Microsoft 的 OpenSSL 端口 有一个提交引起了我的注意 那就是添加Win10通用平台支持 在提交中 一个名为WINAPI FAMILY ONECORE APP出现 然而 我在搜索时并没有找到太多
  • 如何禁用来自其他域的WebService调用

    我想避免其他人访问我的网络服务 我有一个名为 WebService asmx 的 Web 服务 它托管在 www xyz com 上 我们知道我们可以访问该服务 例如http www xyz com WebService asmx 如何避免
  • 如何强制Dotnet6桌面Winforms应用程序使用appsettings.json而不是Settings.settings?

    如何强制 Dotnet6 桌面 Winforms 应用程序使用 appsettings json 而不是 Settings settings App config 如果我在 Visual Studio 2022 中创建一个新的桌面应用程序以