简体   繁体   中英

Modifying app.config via custom msi installer

I need to create an address string in app.config as:

<client>
       <endpoint address="http://ServerName/xxx/yyy.svc"
                    binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IClientIInfoService"
                    contract="DocuHealthLinkSvcRef.IClientIInfoService" name="BasicHttpBinding_IClientIInfoService" />
</client>

The ServerName need to be entered by the user during installation. For that i have created a new UI dialog in the Installer. I have also written an Installer.cs class and overrided the install () as:

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

            base.Install(stateSaver);

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

            string ServerName = Context.Parameters["ServerName"];

            System.Diagnostics.Debugger.Break();

            string exePath = string.Format("{0}myapp.exe", targetDirectory);

           Configuration config = ConfigurationManager.OpenExeConfiguration(exePath);

            config.AppSettings.Settings["ServerName"].Value = ServerName;

            config.Save();
        }
    }

But how do i use this ServerName in my app.config to create the specified string. I'm working on VS2010.

You could use WiX (Windows Installer XML toolset) to build your MSI, in which case you can use the XmlFile utility tag to update the server name:

  <util:XmlFile Id="UpdateServerName" File="[INSTALLLOCATION]AppName.exe.config" Action="setValue" ElementPath="/client/endpoint" Name="address" Value="http://[SERVERNAME]/xxx/yyy.svc" />

You can capture the server name during installation using a WixUI extension form.

Advantages of WiX: WiX is msbuild compliant (unlike .vdproj files), and gives you much finer-grained control over your installer, among other things

Assuming you are using the full ServiceModel section group in the app.config

Essentially you follow these steps:

  1. Load ServiceModel config section
  2. Get Client Section
  3. Get ChannelEndpoint Element
  4. Change Address value by replacing string "ServerName" with entered value
  5. Set Address attribute to new value
  6. Save config

     public override void Install(System.Collections.IDictionary stateSaver) { base.Install(stateSaver); string targetDirectory = Context.Parameters["targetdir"]; string ServerName = Context.Parameters["ServerName"]; System.Diagnostics.Debugger.Break(); string exePath = string.Format("{0}myapp.exe", targetDirectory); Configuration config = ConfigurationManager.OpenExeConfiguration(exePath); config.AppSettings.Settings["ServerName"].Value = ServerName; //Get ServiceModelSectionGroup from config ServiceModelSectionGroup group = ServiceModelSectionGroup.GetSectionGroup (config); //get the client section ClientSection clientSection = group.Client; //get the first endpoint ChannelEndpointElement channelEndpointElement = clientSection.Endpoints[0]; //get the address attribute and replace servername in the string. string address = channelEndpointElement.Address.ToString().Replace("ServerName", ServerName); //set the Address attribute to the new value channelEndpointElement.Address = new Uri(address); config.Save(); } 

At the end of the day, app.config is xml file. You can use Linq To XML or XPathNavigator to replace the address attribute of endpoint element.

Below code uses Linq to Xml

    using System.Xml.Linq;
    public override void Install(System.Collections.IDictionary stateSaver)
    {

        base.Install(stateSaver);

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

        string ServerName = Context.Parameters["ServerName"];

        System.Diagnostics.Debugger.Break();

        string configPath = string.Format("{0myapp.exe.config", targetDirectory);

        XElement root = XElement.Load(configPath);
        var endPointElements = root.Descendants("endpoint");
        foreach(var element in endPointElements)
        {
            element.Attribute("address").Value = ServerName;
        }
        root.Save(configPath);
    }
}

Since you have a windows-installer tag, I assume you either have an MSI package, or can create one...

Then:

  • You can create a public MSI property like ENDPOINTSERVER you require during installation.
  • Add a custom action that modifies app.config to run after "InstallFinalize" with the value of ENDPOINTSERVER

A silent installation will be possible using:

msiexec /i app.msi ENDPOINTSERVER=www.MyServer.com /qb-

try to use below two lines before saving the config file changes:

config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("Section Name");
 root.Save(configPath);

PS: it doesn't update the solution item 'app.config', but the '.exe.config' one in the bin/ folder if you run it with F5.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM