bin/Debug/App.exe.config:執行期實際讀寫的檔案,修改會持久化bin/Debug/App.vshost.exe.config:VS 宿主進程用,同步自原始碼,執行期不修改App.exe.config,部署時隨 EXE 一起發布System.Configuration.dllusing System.Configuration;
public static string GetConnectionString(string name)
{
var cs = ConfigurationManager.ConnectionStrings[name];
if (cs == null) throw new ConfigurationErrorsException($"找不到連線字串: {name}");
return cs.ConnectionString;
}
// 使用
var connStr = GetConnectionString("DefaultConn");
public static void UpdateConnectionString(string name, string newConnectionString, string providerName = "System.Data.SqlClient")
{
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var cs = config.ConnectionStrings.ConnectionStrings[name];
if (cs == null)
{
// 新增
config.ConnectionStrings.ConnectionStrings.Add(
new ConnectionStringSettings(name, newConnectionString, providerName));
}
else
{
// 修改:需先移除再加入 (ConnectionString 唯讀)
config.ConnectionStrings.ConnectionStrings.Remove(name);
config.ConnectionStrings.ConnectionStrings.Add(
new ConnectionStringSettings(name, newConnectionString, providerName));
}
config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("connectionStrings"); // 重新整理快取
}
// 簡單讀取
string title = ConfigurationManager.AppSettings["AppTitle"];
int maxRetry = int.Parse(ConfigurationManager.AppSettings["MaxRetryCount"] ?? "3");
// 強型別輔助
public static T GetAppSetting(string key, T defaultValue = default)
{
var val = ConfigurationManager.AppSettings[key];
if (val == null) return defaultValue;
return (T)Convert.ChangeType(val, typeof(T));
}
public static void SetAppSetting(string key, string value)
{
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var settings = config.AppSettings.Settings;
if (settings[key] == null)
settings.Add(key, value);
else
settings[key].Value = value;
config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("appSettings");
}
public static class ConfigInitializer
{
public static void EnsureDefaults()
{
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
// 確保連線字串存在
if (config.ConnectionStrings.ConnectionStrings["DefaultConn"] == null)
{
config.ConnectionStrings.ConnectionStrings.Add(
new ConnectionStringSettings("DefaultConn",
"Data Source=.;Initial Catalog=MyDB;Integrated Security=True",
"System.Data.SqlClient"));
}
// 確保 AppSettings 存在
var defaults = new Dictionary
{
["AppTitle"] = "我的應用程式",
["MaxRetryCount"] = "3",
["LogLevel"] = "Information"
};
foreach (var kv in defaults)
{
if (config.AppSettings.Settings[kv.Key] == null)
config.AppSettings.Settings.Add(kv.Key, kv.Value);
}
config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("connectionStrings");
ConfigurationManager.RefreshSection("appSettings");
}
}
// 定義區段類別
public class MySettingsSection : ConfigurationSection
{
[ConfigurationProperty("apiUrl", DefaultValue = "https://api.example.com", IsRequired = true)]
public string ApiUrl => (string)this["apiUrl"];
[ConfigurationProperty("timeout", DefaultValue = 30, IsRequired = false)]
public int Timeout => (int)this["timeout"];
[ConfigurationProperty("endpoints")]
public EndpointCollection Endpoints => (EndpointCollection)this["endpoints"];
}
[ConfigurationCollection(typeof(EndpointElement), AddItemName = "endpoint")]
public class EndpointCollection : ConfigurationElementCollection
{
protected override ConfigurationElement CreateNewElement() => new EndpointElement();
protected override object GetElementKey(ConfigurationElement element) => ((EndpointElement)element).Name;
}
public class EndpointElement : ConfigurationElement
{
[ConfigurationProperty("name", IsRequired = true, IsKey = true)]
public string Name => (string)this["name"];
[ConfigurationProperty("url", IsRequired = true)]
public string Url => (string)this["url"];
}
// 註冊於 configSections
//
// 使用
var section = (MySettingsSection)ConfigurationManager.GetSection("mySettings");
Console.WriteLine(section.ApiUrl);
foreach (EndpointElement ep in section.Endpoints)
Console.WriteLine($"{ep.Name}: {ep.Url}");
| 項目 | 建議 |
|---|---|
| 修改後重新整理 | 必須呼叫 ConfigurationManager.RefreshSection,否則後續讀取仍為舊值 |
| 執行緒安全 | ConfigurationManager 內部有鎖,但頻繁寫入會效能不佳,建議啟動時一次性讀取快取 |
| 權限問題 | 寫入 Program Files 下的 config 需管理員權限,建議將可寫入設定存放於 Environment.GetFolderPath(SpecialFolder.LocalApplicationData) |
| 加密敏感資料 | 連線字串密碼建議使用 aspnet_regiis -pef connectionStrings 或 DPAPI 加密 |
| .NET Core / 5+ | 改用 appsettings.json + IConfiguration,不再使用 System.Configuration |
| 使用者層級設定 | 用 userSettings / Settings.Settings (專案屬性 → Settings),自動產生強型別類別,支援使用者/應用程式範圍 |
// 唯讀快取讀取
ConfigurationManager.AppSettings["key"]
ConfigurationManager.ConnectionStrings["name"].ConnectionString
// 讀寫並持久化
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
config.AppSettings.Settings["key"].Value = "value";
config.ConnectionStrings.ConnectionStrings["name"].ConnectionString = "..."; // 唯讀,需 Remove/Add
config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("sectionName");
掌握 App.config 讀寫,能讓應用程式具備靈活的部署時配置與執行期自適應調整能力。