locked
How Do I Modify Connection String During MSI Install RRS feed

  • Question

  • Hello Experst I used to install my application using Vs Setup Prjects.

     I wanted that during setup let user decide the server name & database name and use it  as connection string

    reading http://raquila.com/software/configure-app-config-application-settings-during-msi-install/

    I could modify my set up project and added this installer class

    usingSystem; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Configuration.Install; using System.Linq; using System.Configuration; using System.Windows.Forms; using System.IO; using KIToolkit; using System.Data.SqlClient; using System.Data.EntityClient; using System.Data; using System.Diagnostics; namespace Kings.ERP { [RunInstaller(true)] public partial class ErpInstall : System.Configuration.Install.Installer { public ErpInstall() { InitializeComponent(); } public override void Install(System.Collections.IDictionary stateSaver) { base.Install(stateSaver); UpdateConnectionString(); } private void UpdateConnectionString() { stringconname = "Kings.ERP.Properties.Settings.kingsConnectionString".ToUpper(), provider = ""; Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); ConnectionStringsSection appcfgsection =config.ConnectionStrings;//app.config ConnectionStrings for (intiRnr = 0; iRnr < appcfgsection.ConnectionStrings.Count; iRnr++) { ConnectionStringSettingscSS = appcfgsection.ConnectionStrings[iRnr]; if (cSS.Name.ToUpper() == conname) { provider = cSS.ProviderName; appcfgsection.ConnectionStrings.Remove(cSS); break; } } stringconString = "Data Source=" + Context.Parameters["Param1"].ToString() + ";Initial Catalog=" + Context.Parameters["Param2"].ToString() + ";Integrated Security=True"; ConnectionStringSettingscsSet = new ConnectionStringSettings(conname, conString, provider); appcfgsection.ConnectionStrings.Add(csSet); config.AppSettings.Settings.Remove("CommanFilePath"); config.AppSettings.Settings.Add("CommanFilePath",Context.Parameters["Param3"].ToString()); config.Save(ConfigurationSaveMode.Modified); ConfigurationManager.RefreshSection("connectionStrings"); EventLog.WriteEntry("InstallerClass", "user Connection String is:" + conString + " Common File Path=" + Context.Parameters["Param3"].ToString()); } } }

    i see in event log

    user Connection String is:Data Source=kings;Initial Catalog=kk;Integrated Security=True Common File Path=d:\kings2012

    every thing happens but I dont see the changes in the final config file

    can u please tell me what would be going wrong



    Thursday, October 25, 2012 2:29 PM

Answers

  • Dear PhilWilson,

    thanks

    upon your indirect hint on OpenExeConfiguration, the step i had missed in

    http://raquila.com/software/configure-app-config-application-settings-during-msi-install/

    solution, becuase it was returning incorrect targetdirectory i corrected its extra \ ( backslash) and yes i changed the line(s) 

    Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

    to

                string exePath = Context.Parameters["exePath"].ToString();
                exePath = exePath.Substring(0,exePath.Length - 1);
                exePath = string.Format(@"{0}bin\debug\Kings Erp.exe", exePath);
                Configuration config = ConfigurationManager.OpenExeConfiguration(exePath); 

    the falut was traced and now things are working fine,

    thanks a lot for your suggestion & here is the correct installer code

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Configuration.Install;
    using System.Linq;
    using System.Configuration;
    using System.Windows.Forms;
    using System.IO;
    using KIToolkit;
    using System.Data.SqlClient;
    using System.Data.EntityClient;
    using System.Data;
    using System.Diagnostics;
    
    
    namespace Kings.ERP
    {
        [RunInstaller(true)]
        public partial class ErpInstall : System.Configuration.Install.Installer
        {
            public ErpInstall()
            {
                InitializeComponent();
            }
            public override void Install(System.Collections.IDictionary stateSaver)
            {
                base.Install(stateSaver);
                //System.Diagnostics.Debugger.Break();
                UpdateConnectionString();
    
                //String exePath = Path.GetDirectoryName(Context.Parameters["AssemblyPath"]);
                //exePath = string.Format(@"{0}\Kings ERP.exe", exePath);
                //http://raquila.com/software/configure-app-config-application-settings-during-msi-install/
                //http://www.codeproject.com/Articles/118532/Saving-Connection-Strings-to-app-config
                ////http://stackoverflow.com/questions/7174604/how-can-i-update-app-config-connectionstring-datasource-value-in-c
    
            }
    
            private void UpdateConnectionString()
            {
                string conname = "Kings.ERP.Properties.Settings.kingsConnectionString".ToUpper(), provider = "";
                string exePath = Context.Parameters["exePath"].ToString();
                exePath = exePath.Substring(0,exePath.Length - 1);
                exePath = string.Format(@"{0}bin\debug\Kings Erp.exe", exePath);
                Configuration config = ConfigurationManager.OpenExeConfiguration(exePath); 
                ConnectionStringsSection appcfgsection =config.ConnectionStrings;
                for (int iRnr = 0; iRnr < appcfgsection.ConnectionStrings.Count; iRnr++)
                {
                    ConnectionStringSettings cSS = appcfgsection.ConnectionStrings[iRnr];
                    if (cSS.Name.ToUpper() == conname)
                    {
                        provider = cSS.ProviderName;
                        appcfgsection.ConnectionStrings.Remove(cSS);
                        break;
                    }
                }
                //provider = "System.Data.SqlClient";
                string conString = "Data Source=" + Context.Parameters["servername"].ToString() + ";Initial Catalog=" + Context.Parameters["dbname"].ToString() +
                                    ";Integrated Security=True";
                ConnectionStringSettings csSet = new ConnectionStringSettings(conname, conString, provider);
                appcfgsection.ConnectionStrings.Add(csSet);
    
                config.AppSettings.Settings.Remove("CommanFilePath");
                config.AppSettings.Settings.Add("CommanFilePath", Context.Parameters["reportpath"].ToString());
                config.Save(ConfigurationSaveMode.Modified);
                ConfigurationManager.RefreshSection("connectionStrings");
                //EventLog.WriteEntry("InstallerClass", "user Connection String is:" + conString + " Common File Path=" + Context.Parameters["reportpath"].ToString());
            }
    
    
                /// <summary>
                /// Adds a connection string settings entry & saves it to the associated config file.
                ///
                /// This may be app.config, or an auxiliary file that app.config points to or some
                /// other xml file.
                /// ConnectionStringSettings is the confusing type name of one entry including: 
                ///			name + connection string + provider entry
                /// </summary>
                /// <param name="configuration">Pass in ConfigurationManager.OpenMachineConfiguration, 
                /// ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None) etc. </param>
                /// <param name="connectionStringSettings">The entry to add</param>
                public static void AddAndSaveOneConnectionStringSettings(
                    System.Configuration.Configuration configuration,
                    System.Configuration.ConnectionStringSettings connectionStringSettings)
                {
                    // You cannot add to ConfigurationManager.ConnectionStrings using
                    // ConfigurationManager.ConnectionStrings.Add(connectionStringSettings) -- This fails.
                    // But you can add to the configuration section and refresh the ConfigurationManager.
    
                    // Get the connection strings section; Even if it is in another file.
                    ConnectionStringsSection connectionStringsSection = configuration.ConnectionStrings;
    
                    // Add the new element to the section.
                    connectionStringsSection.ConnectionStrings.Add(connectionStringSettings);
    
                    // Save the configuration file.
                    configuration.Save(ConfigurationSaveMode.Minimal);
    
                    // This is needed. Otherwise the updates do not show up in ConfigurationManager
                    ConfigurationManager.RefreshSection("connectionStrings");
                }
        }
    }
    

    • Marked as answer by Sushil Agarwal Saturday, October 27, 2012 7:12 AM
    Saturday, October 27, 2012 7:12 AM

All replies

  • I t hink the problem might be this: You've written this code as if you are running in your application environment in your application folder, but you are not. You are running in an installer class being called from a Wiindows msiexec.exe process that knows nothing about any application folder or about any kind of exe config file in some folder somewhere.  What does OpenExeConfiguration mean whwn you're running in an installer class? Which exe?

    Phil Wilson

    Thursday, October 25, 2012 5:07 PM
  • Dear PhilWilson,

    What does OpenExeConfiguration mean when you're running in an installer class?  it is a aplication installer class in application project

    Which exe?  application exe, in this case it is "Kings Erp.Exe"

    user interface & custom action are set in setup project as explained in 

    http://raquila.com/software/configure-app-config-application-settings-during-msi-install/

    the installer is getting fired, I have checked it in debug and following line updates Eventlog

    EventLog.WriteEntry("InstallerClass", "user Connection String is:" + conString + " Common File Path=" + Context.Parameters["Param3"].ToString());

    In event log , the user enterd data is shown as under

    user Connection String is:Data Source=kings;Initial Catalog=kk;Integrated Security=True Common File Path=d:\kings2012

    why the app.config does not get modified

    Friday, October 26, 2012 6:04 AM
  • "What does OpenExeConfiguration mean when you're running in an installer class? " is rhetorical. It's my way of saying that it makes no sense to use an exe config file when you are not running in tour exe's application environment. Once again, you say that you have an installer class, so your Dll installer class is being instantiated from the msiexec process of Windows Installer. None of this is in your applications environment.  That's why your config file does not get updated. That stuff only works when your application exe runs in the application environment. Once again, your installer class Dll is being called from an msiexec.exe process, the install hasn't even finished yet.


    Phil Wilson

    Friday, October 26, 2012 6:09 PM
  • Dear PhilWilson,

    thanks

    upon your indirect hint on OpenExeConfiguration, the step i had missed in

    http://raquila.com/software/configure-app-config-application-settings-during-msi-install/

    solution, becuase it was returning incorrect targetdirectory i corrected its extra \ ( backslash) and yes i changed the line(s) 

    Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

    to

                string exePath = Context.Parameters["exePath"].ToString();
                exePath = exePath.Substring(0,exePath.Length - 1);
                exePath = string.Format(@"{0}bin\debug\Kings Erp.exe", exePath);
                Configuration config = ConfigurationManager.OpenExeConfiguration(exePath); 

    the falut was traced and now things are working fine,

    thanks a lot for your suggestion & here is the correct installer code

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Configuration.Install;
    using System.Linq;
    using System.Configuration;
    using System.Windows.Forms;
    using System.IO;
    using KIToolkit;
    using System.Data.SqlClient;
    using System.Data.EntityClient;
    using System.Data;
    using System.Diagnostics;
    
    
    namespace Kings.ERP
    {
        [RunInstaller(true)]
        public partial class ErpInstall : System.Configuration.Install.Installer
        {
            public ErpInstall()
            {
                InitializeComponent();
            }
            public override void Install(System.Collections.IDictionary stateSaver)
            {
                base.Install(stateSaver);
                //System.Diagnostics.Debugger.Break();
                UpdateConnectionString();
    
                //String exePath = Path.GetDirectoryName(Context.Parameters["AssemblyPath"]);
                //exePath = string.Format(@"{0}\Kings ERP.exe", exePath);
                //http://raquila.com/software/configure-app-config-application-settings-during-msi-install/
                //http://www.codeproject.com/Articles/118532/Saving-Connection-Strings-to-app-config
                ////http://stackoverflow.com/questions/7174604/how-can-i-update-app-config-connectionstring-datasource-value-in-c
    
            }
    
            private void UpdateConnectionString()
            {
                string conname = "Kings.ERP.Properties.Settings.kingsConnectionString".ToUpper(), provider = "";
                string exePath = Context.Parameters["exePath"].ToString();
                exePath = exePath.Substring(0,exePath.Length - 1);
                exePath = string.Format(@"{0}bin\debug\Kings Erp.exe", exePath);
                Configuration config = ConfigurationManager.OpenExeConfiguration(exePath); 
                ConnectionStringsSection appcfgsection =config.ConnectionStrings;
                for (int iRnr = 0; iRnr < appcfgsection.ConnectionStrings.Count; iRnr++)
                {
                    ConnectionStringSettings cSS = appcfgsection.ConnectionStrings[iRnr];
                    if (cSS.Name.ToUpper() == conname)
                    {
                        provider = cSS.ProviderName;
                        appcfgsection.ConnectionStrings.Remove(cSS);
                        break;
                    }
                }
                //provider = "System.Data.SqlClient";
                string conString = "Data Source=" + Context.Parameters["servername"].ToString() + ";Initial Catalog=" + Context.Parameters["dbname"].ToString() +
                                    ";Integrated Security=True";
                ConnectionStringSettings csSet = new ConnectionStringSettings(conname, conString, provider);
                appcfgsection.ConnectionStrings.Add(csSet);
    
                config.AppSettings.Settings.Remove("CommanFilePath");
                config.AppSettings.Settings.Add("CommanFilePath", Context.Parameters["reportpath"].ToString());
                config.Save(ConfigurationSaveMode.Modified);
                ConfigurationManager.RefreshSection("connectionStrings");
                //EventLog.WriteEntry("InstallerClass", "user Connection String is:" + conString + " Common File Path=" + Context.Parameters["reportpath"].ToString());
            }
    
    
                /// <summary>
                /// Adds a connection string settings entry & saves it to the associated config file.
                ///
                /// This may be app.config, or an auxiliary file that app.config points to or some
                /// other xml file.
                /// ConnectionStringSettings is the confusing type name of one entry including: 
                ///			name + connection string + provider entry
                /// </summary>
                /// <param name="configuration">Pass in ConfigurationManager.OpenMachineConfiguration, 
                /// ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None) etc. </param>
                /// <param name="connectionStringSettings">The entry to add</param>
                public static void AddAndSaveOneConnectionStringSettings(
                    System.Configuration.Configuration configuration,
                    System.Configuration.ConnectionStringSettings connectionStringSettings)
                {
                    // You cannot add to ConfigurationManager.ConnectionStrings using
                    // ConfigurationManager.ConnectionStrings.Add(connectionStringSettings) -- This fails.
                    // But you can add to the configuration section and refresh the ConfigurationManager.
    
                    // Get the connection strings section; Even if it is in another file.
                    ConnectionStringsSection connectionStringsSection = configuration.ConnectionStrings;
    
                    // Add the new element to the section.
                    connectionStringsSection.ConnectionStrings.Add(connectionStringSettings);
    
                    // Save the configuration file.
                    configuration.Save(ConfigurationSaveMode.Minimal);
    
                    // This is needed. Otherwise the updates do not show up in ConfigurationManager
                    ConfigurationManager.RefreshSection("connectionStrings");
                }
        }
    }
    

    • Marked as answer by Sushil Agarwal Saturday, October 27, 2012 7:12 AM
    Saturday, October 27, 2012 7:12 AM
  • Dear Sir,

    I have some error in the following code. Please Help me out of this this

    Regards,

    R.Mohamed ansari

    Istep Information Technologies

    Chennai-88

    Coding part,

    I am getting the error in this parts:

               Configuration config = ConfigurationManager.OpenExeConfiguration(exePath);
                ConnectionStringsSection appcfgsection = config.ConnectionStrings;
                for (int iRnr = 0; iRnr < appcfgsection.ConnectionStrings.Count; iRnr++)
                {
                    ConnectionStringSettings cSS = appcfgsection.ConnectionStrings[iRnr];
                    if (cSS.Name.ToUpper() == conname)
                    {
                        provider = cSS.ProviderName;
                        appcfgsection.ConnectionStrings.Remove(cSS);
                        break;
                    }
                }
                //provider = "System.Data.SqlClient";
                string conString = "Data Source=" + Context.Parameters["servername"].ToString() + ";Initial Catalog=" + Context.Parameters["dbname"].ToString() +
                                    ";Integrated Security=True";
                ConnectionStringSettings csSet = new ConnectionStringSettings(conname, conString, provider);
                appcfgsection.ConnectionStrings.Add(csSet);

                config.AppSettings.Settings.Remove("CommanFilePath");
                config.AppSettings.Settings.Add("CommanFilePath", Context.Parameters["reportpath"].ToString());
                config.Save(ConfigurationSaveMode.Modified);
                ConfigurationManager.RefreshSection("connectionStrings");



    Monday, March 3, 2014 8:26 AM