Modifying app.config via custom msi installer

2019-07-20 14:59发布

问题:

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.

回答1:

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();
    }
    


回答2:

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



回答3:

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);
    }
}


回答4:

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-


回答5:

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

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

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