Can I force the installer project to use the .config file from the built solution instead of the original one?

前端 未结 7 1264
我在风中等你
我在风中等你 2021-02-01 09:41

I am using the solution to this question in order to apply configuration changes to App.config in a Winforms project. I also have an installer project for the proj

7条回答
  •  梦如初夏
    2021-02-01 10:17

    None of the above solutions or any articles worked for me in deployment/setup project. Spent many days to figure out the right solution. Finally this approach worked for me.

    Pre requisites

    I've used utility called cct.exe to transform file explicitly. You can download from here http://ctt.codeplex.com/

    I've used custom installer in setup project to capture installation events.

    Follow these steps to achieve app config transformation

    1) Add your desired config files to your project and modify your .csproj file like these

    
      app.config
    
    
      app.config
    
    
      app.config
     
    

    I've added them as content so that they can be copied to output directory.

    2) Add cct.exe to your project which you downloaded.

    3) Add custom installer to your project which should look like this

      [RunInstaller(true)]
      public partial class CustomInstaller : System.Configuration.Install.Installer
      {
        string currentLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
        string[] transformationfiles = Directory.GetFiles(Path.GetDirectoryNam(Assembly.GetExecutingAssembly().Location), "app.*.config");
    
        public CustomInstaller()
        {
            InitializeComponent();
            // Attach the 'Committed' event.
            this.Committed += new InstallEventHandler(MyInstaller_Committed);
            this.AfterInstall += new InstallEventHandler(CustomInstaller_AfterInstall);
    
        }
    
    
        void CustomInstaller_AfterInstall(object sender, InstallEventArgs e)
        {
            try
            {
    
                Directory.SetCurrentDirectory(currentLocation);
                var environment = Context.Parameters["Environment"];
                var currentconfig = transformationfiles.Where(x => x.Contains(environment)).First();
    
                if (currentconfig != null)
                {
                    FileInfo finfo = new FileInfo(currentconfig);
                    if (finfo != null)
                    {
                        var commands = string.Format(@"/C  ctt.exe s:yourexename.exe.config t:{0} d:yourexename.exe.config ", finfo.Name);
    
                        using (System.Diagnostics.Process execute = new System.Diagnostics.Process())
                        {
                            execute.StartInfo.FileName = "cmd.exe";
                            execute.StartInfo.RedirectStandardError = true;
                            execute.StartInfo.RedirectStandardInput = true;
                            execute.StartInfo.RedirectStandardOutput = true;
                            execute.StartInfo.UseShellExecute = false;
                            execute.StartInfo.CreateNoWindow = true;
                            execute.StartInfo.Arguments = commands;
                            execute.Start();
                        }
    
                    }
                }
            }
            catch
            {
                // Do nothing... 
            }
    
    
        }
    
        // Event handler for 'Committed' event.
        private void MyInstaller_Committed(object sender, InstallEventArgs e)
        {
            XmlDocument doc = new XmlDocument();
            var execonfigPath = currentLocation + @"\yourexe.exe.config";
            var file = File.OpenText(execonfigPath);
            var xml = file.ReadToEnd();
            file.Close();
            doc.LoadXml(FormatXmlString(xml));
            doc.Save(execonfigPath);
    
            foreach (var filename in transformationfiles)
                File.Delete(filename);
    
        }
    
    
    
        private static string FormatXmlString(string xmlString)
        {
            System.Xml.Linq.XElement element = System.Xml.Linq.XElement.Parse(xmlString);
            return element.ToString();
        }
    
    }
    

    Here I am using two event handlers CustomInstaller_AfterInstall in which I am loading correct config file and transforming . In MyInstaller_Committed I am deleting transformation files which we don't need on client machine once we apply has been applied. I am also indenting transformed file because cct simply transforms elements were aligned ugly.

    4) Open your setup project and add project output content file so that setup can copy config files like app.uat.config,app.live.config etc into client machine.

    In previous step this snippet will load all available config files but we need supply right transform file

     string[] transformationfiles = Directory.GetFiles(Path.GetDirectoryNam
    
     (Assembly.GetExecutingAssembly().Location), "app.*.config");
    

    For that I've added UI dialog on setup project to get the current config. The dialog gives options for user to select environment like "Live" "UAT" "Test" etc . Now pass the selected environment to your custom installer and filter them.

    Configure UI to allow user to select option

    enter image description here

    enter image description here

    It will become lengthy article if I explain on how to add dialog,how to set up params etc so please google them. But idea is to transform user selected environment. The advantage of this approach is you can use same setup file for any environment.

    Here is the summary:

    Add config files

    Add cct exe file

    Add custom installer

    Apply transformation on exe.config under after install event

    Delete transformation files from client's machine

    Modify setup project in such a way that

    set up should copy all config files(project output content) and cct.exe into output directory
    
    configure UI dialog with radio buttons (Test,Live,UAT..)
    
    pass the selected value to custom installer
    

    Solution might look lengthy but have no choice because MSI always copy app.config and doesn't care about project build events and transformations. slowcheetah works only with clickonce not setup project

提交回复
热议问题