如何从外部更新C# VSTO插件的user.config用户配置?
VSTO插件安装程序更新user.config的解决方案
核心问题
你的VSTO Office插件作为.NET应用,其user.config默认存储在AppData\Local\Microsoft_Corporation下的哈希命名文件夹中,外部安装程序难以直接定位;且因VSTO宿主为Office程序,直接调用ConfigurationManager可能无法获取正确路径,同时覆盖app.config不会影响已保存的用户配置。
可行实现思路
1. 在插件运行时记录user.config路径到注册表
利用VSTO插件运行时能正确获取配置路径的特性,在插件启动时将user.config的绝对路径写入注册表,安装程序直接读取该注册表项即可定位目标文件。
插件内代码示例:
private void ThisAddIn_Startup(object sender, System.EventArgs e) { // 获取当前插件的user.config路径 var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal); string userConfigPath = config.FilePath; // 将路径写入注册表(自定义键路径) using (var registryKey = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(@"Software\YourCompanyName\YourVSTOAddinName")) { registryKey.SetValue("UserConfigFilePath", userConfigPath); } }
安装程序代码示例:
// 从注册表读取路径 using (var registryKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(@"Software\YourCompanyName\YourVSTOAddinName")) { if (registryKey != null) { string userConfigPath = registryKey.GetValue("UserConfigFilePath") as string; if (!string.IsNullOrEmpty(userConfigPath) && File.Exists(userConfigPath)) { // 加载并修改user.config var configMap = new ExeConfigurationFileMap { ExeConfigFilename = userConfigPath }; var config = ConfigurationManager.OpenMappedExeConfiguration(configMap, ConfigurationUserLevel.None); // 修改配置项示例 config.AppSettings.Settings["TargetSettingKey"].Value = "NewValue"; config.Save(ConfigurationSaveMode.Modified); } } }
2. 自定义配置存储路径(脱离.NET默认配置系统)
放弃使用.NET自带的user.config,改为自定义固定路径存储用户配置,安装程序直接访问该路径即可。这种方式完全可控,避免依赖默认的复杂路径结构。
自定义配置实现示例:
// 定义配置实体类 public class PluginUserConfig { public string Setting1 { get; set; } public int Setting2 { get; set; } } // 读取配置 public PluginUserConfig LoadUserConfig() { string configPath = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "YourCompanyName", "YourVSTOAddinName", "user.config" ); if (!File.Exists(configPath)) { return new PluginUserConfig(); // 返回默认配置 } var serializer = new System.Xml.Serialization.XmlSerializer(typeof(PluginUserConfig)); using (var reader = new StreamReader(configPath)) { return (PluginUserConfig)serializer.Deserialize(reader); } } // 保存配置 public void SaveUserConfig(PluginUserConfig config) { string configDir = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "YourCompanyName", "YourVSTOAddinName" ); Directory.CreateDirectory(configDir); string configPath = Path.Combine(configDir, "user.config"); var serializer = new System.Xml.Serialization.XmlSerializer(typeof(PluginUserConfig)); using (var writer = new StreamWriter(configPath)) { serializer.Serialize(writer, config); } }
安装程序只需直接读写上述固定路径下的user.config文件即可。
3. 优化遍历定位方案(无插件代码修改需求)
如果无法修改插件代码,可通过遍历AppData\Local\Microsoft_Corporation下的文件夹,结合插件程序集名称、版本号等特征缩小查找范围,再验证配置文件的唯一性(比如读取特定配置项)。
遍历查找示例:
string baseDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Microsoft_Corporation"); string pluginAssemblyName = "YourVSTOAddin.dll"; // 插件程序集文件名 string targetConfigPath = null; foreach (string dir in Directory.GetDirectories(baseDir, $"{pluginAssemblyName}_*")) { string configPath = Path.Combine(dir, "user.config"); if (!File.Exists(configPath)) continue; // 验证配置是否属于目标插件(读取唯一标识项) var configMap = new ExeConfigurationFileMap { ExeConfigFilename = configPath }; var config = ConfigurationManager.OpenMappedExeConfiguration(configMap, ConfigurationUserLevel.None); if (config.AppSettings.Settings["PluginUniqueId"]?.Value == "YourPluginUniqueValue") { targetConfigPath = configPath; break; } } if (!string.IsNullOrEmpty(targetConfigPath)) { // 执行配置修改操作 }
通用实践
- 优先选择注册表记录路径方案:利用插件运行时的上下文获取准确路径,是最可靠的方案,无需改变现有配置逻辑。
- 自定义配置路径适合长期规划:如果插件处于开发初期,自定义配置路径能完全规避.NET默认配置的路径问题,后续维护更简单。
- 遍历方案作为应急备选:仅适用于无法修改插件代码的场景,需注意优化查找逻辑以提升效率和准确性。
内容的提问来源于stack exchange,提问作者Indigo121
相关产品推荐
相关产品推荐

