从自定义安装程序类操作</appname>更新<appname> .config文件

时间:2009-05-27 23:54:28

标签: c# .net windows-installer

我尝试在安装程序期间更新我的应用程序的.config文件(通过.NET Installer类操作)。但是,我似乎无法让ConfigurationManager列出任何属性或能够设置任何属性。

我从几个stackoverflow帖子中了解到了这一方法,并向我指出了本指南:http://raquila.com/software/configure-app-config-application-settings-during-msi-install/

我已经调查了我的项目和他之间的差异,并注意到我的配置文件格式不同。我相信这与我正在使用“设置”文件的事实有关。

指南中格式化的配置文件如下:

<?xml version="1.0" encoding="utf-8" ?>     
<configuration>     
  <appSettings>      
    <add key="Param1" value="" />      
    <add key="Param2" value="" />      
    <add key="Param3" value="" />      
  </appSettings>      
</configuration> 

我的样子:

   <?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
            <section name="MyAppName.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
            <section name="MyAppName.Settings1" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
        </sectionGroup>
        <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
            <section name="MyAppName.Settings1" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
        </sectionGroup>
    </configSections>
    <userSettings>
        <MyAppName.Properties.Settings>
            <setting name="TESTSETTING" serializeAs="String">
                <value>asdfasdfasdf</value>
            </setting>
        </MyAppName.Properties.Settings>
        <MyAppName.Settings1>
            <setting name="VerboseErrorMode" serializeAs="String">
                <value>False</value>
            </setting>
    <applicationSettings>
        <MyAppName.Settings1>
            <setting name="RunOnStartup" serializeAs="String">
                <value>True</value>
            </setting>
        </MyAppName.Settings1>
    </applicationSettings>
</configuration>

为了解释正在发生的事情......我尝试打印出如下设置列表:

            Configuration config = ConfigurationManager.OpenExeConfiguration(exePath);               

            // Try getting the Settings1 Section
            AppSettingsSection appSettings = (AppSettingsSection)config.GetSection("Settings1");  // Also tried myNamespace.Settings1
            if (appSettings != null)
            {
                valList = "Settings1: ";
                foreach (string key in appSettings.Settings.AllKeys)
                {
                    string value = appSettings.Settings[key].Value;
                    valList += ("Key: '" + key + "' = '" + value + "'\n");
                }
            }
            else
            {
                valList = "appSettings was null";
            }
            MessageBox.Show(valList);

        MessageBox.Show(valList);

我尝试了几种这种排列......在所有情况下输出都是“appSettings为null”。

我也试过用几种不同的方式初始化配置管理器......

            Configuration config = ConfigurationManager.OpenExeConfiguration(exePath);

            MessageBox.Show("Section Count: " + config.Sections.Count);
            MessageBox.Show("Has File: " + config.HasFile);
            MessageBox.Show("Namespace Declared: " + config.NamespaceDeclared);

            config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            MessageBox.Show("Section Count: " + config.Sections.Count);
            MessageBox.Show("Has File: " + config.HasFile);
            MessageBox.Show("Namespace Declared: " + config.NamespaceDeclared);

对于他们每个人,返回的部分计数是20.(我不知道20来自哪里......我原以为它是3)。
HasFile对于第一种情况是正确的而对于第二种情况则是错误的。
在两种情况下,Namespace声明都是false。

谢谢!

编辑(6-18-09):仍然在研究这个问题。其他人有什么想法吗?感谢。

搜索关键字:“对象引用未设置为未设置为实例”&lt; - 尝试写入属性时会发生这种情况。

5 个答案:

答案 0 :(得分:11)

我遇到了同样的问题,经过深入调查,我找到了更新配置文件的任何部分(例如app.config)的最简单方法,即使用XPath。 我们有一个连接到Web服务的应用程序,在安装过程中,用户输入Web服务的URL,这应保存在以下app.config文件中:

        <?xml version="1.0"?>
    <configuration>
      <configSections>
        <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
          <section name="ApplicationServer.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
        </sectionGroup>
      </configSections>

      <applicationSettings>
        <ApplicationServer.Properties.Settings>
          <setting name="ApplicationServer_ApplicationServerUrl" serializeAs="String">
            <value>whatever comes from setup should go here</value>
          </setting>
        </ApplicationServer.Properties.Settings>
      </applicationSettings>
    </configuration>

以下是在安装程序类中执行此操作的代码:

public override void Install(System.Collections.IDictionary stateSaver)
    {
        base.Install(stateSaver);

        string targetDirectory = Context.Parameters["targetdir"];
        string param1 = Context.Parameters["param1"];

        string path = System.IO.Path.Combine(targetDirectory, "app.config");

        System.Xml.XmlDocument xDoc = new System.Xml.XmlDocument();

        xDoc.Load(path);

        System.Xml.XmlNode node = xDoc.SelectSingleNode("/configuration/applicationSettings/Intellisense.ApplicationServer.Properties.Settings/setting[@name='ApplicationServer_ApplicationServerUrl']/value");
        node.InnerText = (param1.EndsWith("/") ? param1 : param1 + "/");

        xDoc.Save(path); // saves the web.config file  
    }

基本上,由于配置文件是基于XML的文档,我使用XPath表达式来定位特定节点并更改其值。

答案 1 :(得分:1)

要尝试的一件事是将其从安装转移到提交以确保在尝试访问文件之前先写入文件。或者,您可以使用自定义操作编写自己的文件,只需更改配置文件以指向备用xml文件。

我参与了一个Sharepoint产品安装,在这里我挖掘了所有这些,我承认工作正常非常繁琐。我正在基于安装参数动态创建配置和批处理文件。

答案 2 :(得分:1)

您可以使用System.Configuration命名空间访问这些设置,但它并不像我想的那么简单,回想起来使用System.Xml.Linq要简单得多。无论如何,这是我如何使它工作。

重要的概念是,applicationSettings部分不是AppSettings,它是ClientSettingsSection类型支持的单独部分。

//Open the application level config file
ExeConfigurationFileMap exeMap = new ExeConfigurationFileMap();
exeMap.ExeConfigFilename = String.Format("{0}.config", 
    Context.Parameters["assemblypath"]);
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(exeMap,
    ConfigurationUserLevel.None);

//Get the settings section
ClientSettingsSection settingsSection =
    config.GetSectionGroup("applicationSettings").Sections
         .OfType<ClientSettingsSection>().Single();

//Update "TheSetting"
//I couldn't get the changes to persist unless
//I removed then readded the element.

SettingElement oldElement = settingsSection.Get("TheSetting");
settingsSection.Settings.Remove(oldElement);

SettingElement newElement = new SettingElement("TheSetting", 
    SettingSerializeAs.String);
newElement.Value = new SettingValueElement();
newElement.Value.ValueXml = oldElement.Value.ValueXml.CloneNode(true);
newElement.Value.ValueXml.InnerText = "Some New Value";
settingsSection.Add(newElement);

//Save the changes
config.Save(ConfigurationSaveMode.Full);

所以,正如你所看到的,简单。 :-S

答案 3 :(得分:0)

您可以通过Settings.Default访问它,而不是通过ConfigurationManager访问您的设置配置。设置更像是Visual Studio功能而不是.NET功能......这种便利性使您可以轻松地直观地设计应用程序配置,而不是手动将其写入appSettings或创建自定义配置部分。但是,使用“设置”时呈现的配置架构是非标准的,并且可能难以手动访问。

Visual Studio应该在构建应用程序时为您生成一个Settings类,并且您应该能够通过Properties.Settings.Default访问该类。它应该具有每个设置的属性,在您的情况下,以下内容:

Properties.Settings.Default.TESTSETTING
Properties.Settings.Default.VerboseErrorMode
Properties.Settings.Default.RunOnStartup

您应该能够读取和写入这些设置。需要注意的一件重要事情......标记为“用户”设置的任何内容都不会被写回{yourapplication} .exe.config文件...它将被写入用户隔离的配置文件存储中的User.config文件区域。这是在XP上的C:\ Documents and Settings {username}和Vista上的C:\ Users {username}下的AppData文件夹中。根据操作系统和用户配置文件,AppData下的子文件夹可能会更改,但它完全唯一,并且可以键入特定版本的应用程序。安装较新版本将导致在同一个键控文件夹下存储一组全新的配置设置,但会生成不同的版本子文件夹。

我希望这会有所帮助。 :)

答案 4 :(得分:0)