开发者

Modifying App.Config file at the time of installation using c#

<configur开发者_开发问答ation>
  <configSections>
    <section name="ADMIN" type="System.Configuration.DictionarySectionHandler"/>
  </configSections>
  <User>    
    <add key="ExtendTime" value="20"/>
    <add key="Name" value="sss"/>
  </User>
<configuration>

i have to remove first child element in user config section i.e . Reply me if you have any idea for this.

i am using

Configuration config = ConfigurationManager.OpenExeConfiguration(Context.Parameters["assemblypath"]);
ConfigurationSection section = config.GetSection("USER");


This article may have what you're looking for : http://raquila.com/software/configure-app-config-application-settings-during-msi-install/

Excerpt from article:

string exePath = string.Format("{0}MyWindowsFormsApplication.exe", targetDirectory);
Configuration config = ConfigurationManager.OpenExeConfiguration(exePath);
config.AppSettings.Settings["Param1"].Value = param1;
config.AppSettings.Settings["Param2"].Value = param2;
config.AppSettings.Settings["Param3"].Value = param3;
config.Save();

EDIT: Adding additional code sample and blog reference: http://ryanfarley.com/blog/archive/2004/07/13/879.aspx

using System;
using System.Xml;  
using System.Configuration;
using System.Reflection;
//...


public class ConfigSettings
{
    private ConfigSettings() {}

    public static string ReadSetting(string key)
    {
        return ConfigurationSettings.AppSettings[key];
    }

    public static void WriteSetting(string key, string value)
    {
        // load config document for current assembly
        XmlDocument doc = loadConfigDocument();

        // retrieve appSettings node
        XmlNode node =  doc.SelectSingleNode("//appSettings");

        if (node == null)
            throw new InvalidOperationException("appSettings section not found in config file.");

        try
        {
            // select the 'add' element that contains the key
            XmlElement elem = (XmlElement)node.SelectSingleNode(string.Format("//add[@key='{0}']", key));

            if (elem != null)
            {
                // add value for key
                elem.SetAttribute("value", value);
            }
            else
            {
                // key was not found so create the 'add' element 
                // and set it's key/value attributes 
                elem = doc.CreateElement("add");
                elem.SetAttribute("key", key);
                elem.SetAttribute("value", value); 
                node.AppendChild(elem);
            }
            doc.Save(getConfigFilePath());
        }
        catch
        {
            throw;
        }
    }

    public static void RemoveSetting(string key)
    {
        // load config document for current assembly
        XmlDocument doc = loadConfigDocument();

        // retrieve appSettings node
        XmlNode node =  doc.SelectSingleNode("//appSettings");

        try
        {
            if (node == null)
                throw new InvalidOperationException("appSettings section not found in config file.");
            else
            {
                // remove 'add' element with coresponding key
                node.RemoveChild(node.SelectSingleNode(string.Format("//add[@key='{0}']", key)));
                doc.Save(getConfigFilePath());
            }
        }
        catch (NullReferenceException e)
        {
            throw new Exception(string.Format("The key {0} does not exist.", key), e);
        }
    }

    private static XmlDocument loadConfigDocument()
    {
        XmlDocument doc = null;
        try
        {
            doc = new XmlDocument();
            doc.Load(getConfigFilePath());
            return doc;
        }
        catch (System.IO.FileNotFoundException e)
        {
            throw new Exception("No configuration file found.", e);
        }
    }

    private static string getConfigFilePath()
    {
        return Assembly.GetExecutingAssembly().Location + ".config";
    }
}

Then you would use it like this:

// read the Test1 value from the config file
string test1 = ConfigSettings.ReadSetting("Test1");

// write a new value for the Test1 setting
ConfigSettings.WriteSetting("Test1", "This is my new value");

// remove the Test1 setting from the config file
ConfigSettings.RemoveSetting("Test1");


I have come to the conclusion that it is not possible to access a custom configuration section during installation using:

MyCustomConfigurationSection section = (MyCustomConfigurationSection)config.GetSection("MyCustomConfigurationSection");

When the MSI package is installed, the program executed is the Windows Install(MsiExec), not the program which contains the installer class.

'%windir%\system32\msiexec.exe

In order to access the config we need to workaround this issue either by using the context:

Configuration config = ConfigurationManager.OpenExeConfiguration(this.Context.Parameters["assemblypath"]);

Or, by using reflection retrieve the location of the executing assembly:

Configuration config = ConfigurationManager.OpenExeConfiguration(System.Reflection.Assembly.GetExecutingAssembly().Location);

As Chuck suggested, you can access the AppSettings and modify them:

AppSettingsSection appSettings = (AppSettingsSection)config.GetSection("appSettings");
appSettings.Settings["Environment"].Value = _Environment;
config.Save();

This is fine, because the installer knows exactly how to deal with

System.Configuration.AppSettingsSection

because that library is part of .NET. However, when it comes to a custom section, the installer needs to know how to deal with that custom config. More than likely, you have it in a class library (in a DLL) that is referenced by your application and that DLL has now been installed in the install directory.

The problem is, as we know from above, MSIExec.exe isn't running in the context of that directory, so the install fails, when it can't find the appropriate DLL in system32, it throws the error:

An error occurred creating the configuration section handler for 'XXX': Could not load file or assembly 'XXX.dll' or one of its dependencies. The system cannot find the file specified.

The only way therefore, to access the custom config, is to treat the config file as an XML document, and edit it using traditional XML management tools:

// load the doc
XmlDocument doc = new XmlDocument();
doc.Load(Assembly.GetExecutingAssembly().Location + ".config");

// Get the node
XmlNode node =  doc.SelectSingleNode("//MyCustomConfigurationSection");

// edit node here
// ...

// Save
doc.Save(Assembly.GetExecutingAssembly().Location + ".config");

This technique is described on Ryan Farley's blog, as Chuck pointed out in the comments to his original answer.


Good news! I have found a way how to work-around this problem. Solution is to intercept loading of assembly and return one we have. To do so

ResolveEventHandler handler = new ResolveEventHandler(CurrentDomain_AssemblyResolve);
AppDomain.CurrentDomain.AssemblyResolve += handler;
try
{
   section = config.GetSection("mySection") as MySection;
}
catch(Exception)
{
}
AppDomain.CurrentDomain.AssemblyResolve -= handler;

and

Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    if (args.Name == "Dead.Beef.Rocks")
    {
        return typeof(MySection).Assembly;
    }
    return null;
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜