0

0

C#的配置文件App.config应该如何读写?

畫卷琴夢

畫卷琴夢

发布时间:2025-09-05 09:01:02

|

476人浏览过

|

来源于php中文网

原创

答案:C#中读写App.config需用ConfigurationManager读取,通过OpenExeConfiguration修改并保存。读取时直接访问AppSettings或ConnectionStrings;写入时需加载配置对象,修改后调用Save()并刷新。权限不足可能导致写入失败,建议用户级设置使用Properties.Settings.Default,避免直接修改App.config。自定义配置节可提升结构化与类型安全,适合复杂配置。

c#的配置文件app.config应该如何读写?

在C#中,读写

App.config
配置文件主要通过
System.Configuration
命名空间下的
ConfigurationManager
类来实现。对于简单的键值对,可以直接使用
ConfigurationManager.AppSettings
集合进行读取。而要进行写入操作,尤其是修改已有的或添加新的配置,则需要通过加载应用程序的配置对象,进行修改后再保存。这个过程涉及到对配置文件本身的直接操作,需要注意权限和运行时行为的考量。

解决方案

要读写C#的

App.config
文件,我们通常会区分读取操作和写入操作,并且写入操作需要更谨慎地处理。

1. 读取配置

对于

App.config
节的键值对,读取非常直接:

// 假设App.config中有 
string mySettingValue = System.Configuration.ConfigurationManager.AppSettings["MySetting"];
Console.WriteLine($"读取到的配置:{mySettingValue}");

// 读取连接字符串
// 假设App.config中有   
string connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["MyDb"]?.ConnectionString;
Console.WriteLine($"读取到的连接字符串:{connectionString}");

ConfigurationManager
会自动加载应用程序的默认配置文件(即编译后生成的
YourApp.exe.config
)。

2. 写入/修改配置

直接通过

ConfigurationManager.AppSettings.Add()
ConfigurationManager.AppSettings.Set()
在运行时修改配置,并不能持久化到
App.config
文件中。这是因为
AppSettings
集合在运行时通常是只读的,或者说,它反映的是应用程序启动时的配置状态。要真正修改并保存到磁盘上的
App.config
文件,你需要:

  • 打开配置文件: 使用
    ConfigurationManager.OpenExeConfiguration()
    方法加载应用程序的配置。
  • 获取或创建配置节: 访问或创建
    AppSettingsSection
  • 修改键值对:
    AppSettingsSection
    Settings
    集合进行操作。
  • 保存配置: 调用配置对象的
    Save()
    方法。
  • 刷新配置: 调用
    ConfigurationManager.RefreshSection()
    确保新的配置被应用程序加载。

以下是一个修改或添加

键值对的示例:

using System;
using System.Configuration; // 需要引用 System.Configuration

public class ConfigWriter
{
    public static void UpdateAppSetting(string key, string value)
    {
        try
        {
            // 获取当前应用程序的配置对象
            Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

            // 获取或创建 appSettings 节
            AppSettingsSection appSettings = (AppSettingsSection)config.GetSection("appSettings");

            if (appSettings == null)
            {
                // 如果没有 appSettings 节,就创建一个
                appSettings = new AppSettingsSection();
                config.Sections.Add("appSettings", appSettings);
            }

            // 检查键是否存在,如果存在则修改,否则添加
            if (appSettings.Settings[key] != null)
            {
                appSettings.Settings[key].Value = value;
                Console.WriteLine($"配置项 '{key}' 已更新为 '{value}'。");
            }
            else
            {
                appSettings.Settings.Add(key, value);
                Console.WriteLine($"配置项 '{key}' 已添加,值为 '{value}'。");
            }

            // 保存配置更改
            config.Save(ConfigurationSaveMode.Modified);

            // 强制重新加载 appSettings 节,使更改立即生效
            ConfigurationManager.RefreshSection("appSettings");

            Console.WriteLine("配置已成功保存并刷新。");
        }
        catch (ConfigurationErrorsException ex)
        {
            Console.WriteLine($"写入配置时发生错误: {ex.Message}");
            // 进一步处理,例如日志记录
        }
        catch (Exception ex)
        {
            Console.WriteLine($"发生意外错误: {ex.Message}");
        }
    }

    // 示例用法
    public static void Main(string[] args)
    {
        // 假设 App.config 中有 
        Console.WriteLine($"修改前 TestKey: {ConfigurationManager.AppSettings["TestKey"]}");
        UpdateAppSetting("TestKey", "NewValue_" + DateTime.Now.Ticks);
        Console.WriteLine($"修改后 TestKey: {ConfigurationManager.AppSettings["TestKey"]}");

        // 添加一个新键
        Console.WriteLine($"添加前 NewKey: {ConfigurationManager.AppSettings["NewKey"]}");
        UpdateAppSetting("NewKey", "SomeNewValue");
        Console.WriteLine($"添加后 NewKey: {ConfigurationManager.AppSettings["NewKey"]}");

        // 再次读取确认
        Console.WriteLine($"最终 TestKey: {ConfigurationManager.AppSettings["TestKey"]}");
        Console.WriteLine($"最终 NewKey: {ConfigurationManager.AppSettings["NewKey"]}");
    }
}

请注意,修改

App.config
通常会要求应用程序有写入其部署目录的权限。在某些部署环境下(如Program Files),这可能需要管理员权限。

为什么直接修改App.config在运行时会遇到麻烦?

说实话,我个人觉得很多人在刚接触C#配置时,都会下意识地去尝试

ConfigurationManager.AppSettings["key"] = "newValue";
,然后发现不起作用,或者即便写了也无法持久化。这其实是理解
App.config
生命周期和权限模型的一个关键点。

App.config
在应用程序编译后,会被复制到输出目录并重命名为
[应用程序名].exe.config
。对于一个已经部署的应用程序来说,这个
.config
文件通常被视为应用程序的“静态”配置,即它定义了应用程序启动时的默认行为。在大多数情况下,尤其是在Windows的Program Files目录下,应用程序运行时是不被允许随意修改自身安装目录下的文件的,这涉及到操作系统的安全策略和文件权限。如果你尝试直接修改,很可能会遇到
Access Denied
的权限错误。

更深层次地看,

ConfigurationManager.AppSettings
在运行时提供的是一个已加载配置的内存视图。你对其进行的操作,比如
Add
Set
,确实会改变这个内存中的视图,但这些改变并不会自动同步回磁盘上的
.config
文件。这就是为什么你需要显式地调用
config.Save()
方法来将内存中的更改写入到物理文件中。

在我看来,这种设计是有道理的。它将应用程序的配置分为几个层次:

  1. 应用程序级配置 (
    App.config
    /
    [AppName].exe.config
    ):
    部署时确定,通常由管理员或部署工具维护,不期望在运行时由普通用户修改。
  2. 用户级配置 (
    user.config
    ):
    针对每个用户,存储在用户数据目录(如
    AppData
    )下,允许应用程序在运行时读写,且无需管理员权限。这是通过Visual Studio的“设置”功能或
    ApplicationSettingsBase
    类实现的。
  3. 自定义配置 (
    Custom XML Files
    ):
    对于更复杂或需要独立管理的数据,开发者可能会选择使用
    XmlDocument
    或其他序列化方式,将配置存储在独立的XML文件中。

所以,当你尝试修改

App.config
时,如果你的意图是让更改持久化并影响未来的应用程序启动,那么使用
OpenExeConfiguration
Save
是正确的路径。但如果你的意图是让普通用户在运行时修改自己的偏好设置,那么更推荐的做法是利用C#内置的用户设置机制,它会自动处理
user.config
文件的读写和权限问题,用起来会“顺滑”很多,也更符合应用程序设计的最佳实践。

GNU make 中文手册 pdf版
GNU make 中文手册 pdf版

GNU makefile中文手册 pdf,文比较完整的讲述GNU make工具,涵盖GNU make的用法、语法。同时重点讨论如何为一个工程编写Makefile。阅读本书之前,读者应该对GNU的工具链和Linux的一些常用编程工具有一定的了解。诸如:gcc、as、ar、ld、yacc等本文比较完整的讲述GNU make工具,涵盖GNU make的用法、语法。重点讨论如何使用make来管理软件工程、以及如何为工程编写正确的Makefile。 本手册不是一个纯粹的语言翻译版本,其中对GNU make的一些语法

下载

什么时候应该使用自定义配置节,它有什么优势?

有时候,简单的键值对(

AppSettings
)或者连接字符串(
connectionStrings
)已经无法满足我们对配置的复杂需求了。想象一下,如果你有一组相关的设置,比如一个API客户端的URL、超时时间、认证密钥,或者一个日志系统的不同级别和目标路径,把它们都平铺在
AppSettings
里,代码读取起来会显得有些零散,也不够类型安全。这时候,自定义配置节(Custom Configuration Sections)就显得尤为重要了。

自定义配置节的优势非常明显:

  1. 结构化和组织性: 能够将相关的配置项组织在一起,形成一个清晰的层级结构,就像在
    App.config
    中创建自己的XML节点一样。这使得配置文件更易读、易维护。
  2. 类型安全: 你可以定义自己的配置类,这些类继承自
    ConfigurationSection
    ConfigurationElement
    。这样,在代码中读取配置时,你获取到的是一个强类型的对象,可以直接访问其属性,而不是通过字符串键来获取值,大大减少了运行时类型转换错误的可能性。
  3. 数据验证和默认值: 在自定义配置节的类中,你可以为配置属性添加验证规则(例如,
    IsRequired
    MinValue
    MaxValue
    ),甚至可以设置默认值。这样,如果配置文件中缺少某个项或值不合法,系统会在应用程序启动时抛出错误,而不是在运行时才发现问题,有助于提高应用程序的健壮性。
  4. 复用性: 一旦定义了自定义配置节,可以在多个应用程序中复用相同的配置结构。
  5. 更好的可扩展性: 如果未来需要增加新的配置项,只需修改自定义配置节的类,而不需要大幅改动读取配置的代码逻辑。

举个例子: 假设我们要配置一个邮件发送服务,包括SMTP服务器地址、端口、用户名、密码和是否启用SSL。如果用

AppSettings
,可能是这样:


  
  
  
  
  

代码读取时:

string server = ConfigurationManager.AppSettings["SmtpServer"];
int port = int.Parse(ConfigurationManager.AppSettings["SmtpPort"]);
// ... 还有很多类似的读取和转换

如果使用自定义配置节,它看起来会更优雅:

1. 定义配置类:

using System.Configuration;

// 定义一个配置节,对应 
public class MailSettingsSection : ConfigurationSection
{
    // 定义一个配置元素集合,对应  里面的多个 
    [ConfigurationProperty("accounts", IsDefaultCollection = false)]
    [ConfigurationCollection(typeof(MailAccountCollection), AddItemName = "add")]
    public MailAccountCollection Accounts
    {
        get { return (MailAccountCollection)base["accounts"]; }
    }
}

// 定义一个配置元素集合,包含多个 MailAccountElement
public class MailAccountCollection : ConfigurationElementCollection
{
    protected override ConfigurationElement CreateNewElement()
    {
        return new MailAccountElement();
    }

    protected override object GetElementKey(ConfigurationElement element)
    {
        return ((MailAccountElement)element).Name;
    }

    public MailAccountElement this[int index]
    {
        get { return (MailAccountElement)BaseGet(index); }
    }

    public new MailAccountElement this[string name]
    {
        get { return (MailAccountElement)BaseGet(name); }
    }
}

// 定义一个配置元素,对应 
public class MailAccountElement : ConfigurationElement
{
    [ConfigurationProperty("name", IsRequired = true, IsKey = true)]
    public string Name
    {
        get { return (string)this["name"]; }
        set { this["name"] = value; }
    }

    [ConfigurationProperty("server", IsRequired = true)]
    public string Server
    {
        get { return (string)this["server"]; }
        set { this["server"] = value; }
    }

    [ConfigurationProperty("port", DefaultValue = 25, IsRequired = false)]
    [IntegerValidator(MinValue = 1, MaxValue = 65535)]
    public int Port
    {
        get { return (int)this["port"]; }
        set { this["port"] = value; }
    }

    [ConfigurationProperty("username", IsRequired = true)]
    public string Username
    {
        get { return (string)this["username"]; }
        set { this["username"] = value; }
    }

    [ConfigurationProperty("password", IsRequired = true)]
    public string Password
    {
        get { return (string)this["password"]; }
        set { this["password"] = value; }
    }

    [ConfigurationProperty("enableSsl", DefaultValue = false, IsRequired = false)]
    public bool EnableSsl
    {
        get { return (bool)this["enableSsl"]; }
        set { this["enableSsl"] = value; }
    }
}

2. 在

App.config
中注册和使用:



  
    

(注意:

YourNamespace.MailSettingsSection, YourAssembly
需要替换为你的实际命名空间和程序集名称。)

3. 代码中读取:

MailSettingsSection mailConfig = (MailSettingsSection)ConfigurationManager.GetSection("mailSettings");
if (mailConfig != null)
{
    MailAccountElement defaultAccount = mailConfig.Accounts["Default"];
    if (defaultAccount != null)
    {
        Console.WriteLine($"SMTP Server: {defaultAccount.Server}");
        Console.WriteLine($"SMTP Port: {defaultAccount.Port}");
        Console.WriteLine($"SMTP Username: {defaultAccount.Username}");
        Console.WriteLine($"Enable SSL: {defaultAccount.EnableSsl}");
    }
}

你看,通过自定义配置节,我们不仅让配置文件的结构更清晰,代码在读取时也获得了强类型的好处,再也不用担心字符串转换错误了。这种方式对于管理复杂的、多层次的应用程序配置来说,简直是神器。

如何在C#中优雅地处理App.config的读写权限问题?

处理

App.config
的读写权限问题,其实更多的是一种设计哲学和最佳实践的选择,而不仅仅是代码技巧。在我看来,"优雅"的关键在于,你得先搞清楚你到底想让
App.config
做什么。

  1. 明确

    App.config
    的定位:

    • 应用程序级配置(只读为主): 如果这些设置是应用程序的核心配置,部署后很少变动,或者只有管理员才能修改(例如数据库连接字符串、服务URL),那么就把它当成只读的。应用程序启动时读取,运行时不修改。如果需要修改,通常是通过部署更新、手动编辑
      .config
      文件(在有权限的情况下),或者通过专门的配置工具来完成。这种情况下,你不需要在运行时去写入它,自然也就避开了权限问题。
    • 用户级配置(读写): 如果设置是用户偏好、最近使用的文件列表、窗口位置大小等,这些是用户在使用过程中会经常修改的,并且每个用户都应该有自己独立的设置。这时候,就绝对不应该尝试去修改
      App.config
      。正确的做法是使用C#提供的用户设置(User Settings)功能。
  2. 利用用户设置(User Settings): 这是最优雅、最符合Windows应用程序设计模式的方式。在Visual Studio中,项目属性里有一个“设置”选项卡,你可以定义各种类型的设置(字符串、整数、布尔等),并选择其作用域是“应用程序”还是“用户”。

    • 应用程序作用域: 对应
      App.config
      ,只读。
    • 用户作用域: 对应
      user.config
      ,可读写。 当你定义了用户作用域的设置后,C#会自动生成一个
      Properties.Settings.Default
      对象。
    • 读取:
      Properties.Settings.Default.MyUserSetting
    • 写入:
      Properties.Settings.Default.MyUserSetting = "NewValue"; Properties.Settings.Default.Save();
      这些用户设置会自动存储在每个用户的本地
      AppData
      目录下,应用程序对这个目录有完全的读写权限,所以你永远不会遇到权限问题。这简直是为用户偏好设置量身定制的解决方案。
  3. 如果非要修改

    App.config
    (例如,作为管理工具):

    • 运行时权限提升: 如果你的应用程序是一个管理工具,需要修改系统级的配置,那么在启动时就应该请求管理员权限(通过Manifest文件)。这样,
      OpenExeConfiguration
      Save
      操作就不会因为权限不足而失败。但请注意,普通应用程序不应该随意请求管理员权限,这会给用户带来不便和安全风险。
    • 异常处理: 无论如何,当你尝试写入
      App.config
      时,总是要用
      try-catch
      块来捕获
      ConfigurationErrorsException
      或其他
      IOException
      。这样,即使写入失败,应用程序也能优雅地处理,例如提示用户权限不足,或者将错误记录下来。
    • 独立的配置文件: 对于那些需要在运行时由应用程序修改,但又不属于用户偏好的复杂配置,可以考虑不使用
      App.config
      ,而是自己管理一个独立的XML文件。将这个文件放在应用程序有权限写入的目录(如`Environment.GetFolderPath(Environment

相关专题

更多
pdf怎么转换成xml格式
pdf怎么转换成xml格式

将 pdf 转换为 xml 的方法:1. 使用在线转换器;2. 使用桌面软件(如 adobe acrobat、itext);3. 使用命令行工具(如 pdftoxml)。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

1890

2024.04.01

xml怎么变成word
xml怎么变成word

步骤:1. 导入 xml 文件;2. 选择 xml 结构;3. 映射 xml 元素到 word 元素;4. 生成 word 文档。提示:确保 xml 文件结构良好,并预览 word 文档以验证转换是否成功。想了解更多xml的相关内容,可以阅读本专题下面的文章。

2087

2024.08.01

xml是什么格式的文件
xml是什么格式的文件

xml是一种纯文本格式的文件。xml指的是可扩展标记语言,标准通用标记语言的子集,是一种用于标记电子文件使其具有结构性的标记语言。想了解更多相关的内容,可阅读本专题下面的相关文章。

1021

2024.11.28

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

258

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

209

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1468

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

620

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

550

2024.03.22

Java JVM 原理与性能调优实战
Java JVM 原理与性能调优实战

本专题系统讲解 Java 虚拟机(JVM)的核心工作原理与性能调优方法,包括 JVM 内存结构、对象创建与回收流程、垃圾回收器(Serial、CMS、G1、ZGC)对比分析、常见内存泄漏与性能瓶颈排查,以及 JVM 参数调优与监控工具(jstat、jmap、jvisualvm)的实战使用。通过真实案例,帮助学习者掌握 Java 应用在生产环境中的性能分析与优化能力。

19

2026.01.20

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 7.5万人学习

Excel 教程
Excel 教程

共162课时 | 12.6万人学习

PHP基础入门课程
PHP基础入门课程

共33课时 | 2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号