FileNotFoundException in Visual Studio Setup and Deployment Project when trying to load custom config

偶尔善良 提交于 2019-12-06 01:56:11

I managed to find some code on MSDN that provides a working (albeit hacked) way to do this. Link is here: ConfigurationManager, custom config, and installutil / path searching problem.

Wouldn't have found it if not for being able to debug with help from suggestions so thanks to both of you for that.

For reference, my final install code is:

public override void Install(IDictionary stateSaver)
{
    base.Install(stateSaver);

    string targetDirectory = Context.Parameters["DP_TargetDir"];
    stateSaver.Add("TargetDir", targetDirectory);

    string exePath = Path.Combine(targetDirectory, "MyApp.exe");

    System.Diagnostics.Debugger.Break();

    ResolveEventHandler tempResolveEventHandler =
        (sender, args) =>
            {
                string simpleName = new AssemblyName(args.Name).Name;
                string path = Path.Combine(targetDirectory, simpleName + ".dll");
                return File.Exists(path)
                    ? Assembly.LoadFrom(path)
                    : null;
            };

    try
    {
        // hook up asm resolve handler  
        AppDomain.CurrentDomain.AssemblyResolve += tempResolveEventHandler;

        System.Configuration.Configuration config = ConfigurationManager.OpenExeConfiguration(exePath);
        Configuration.MyApp section = (Configuration.MyApp) config.Sections["MyApp"];

        if (section != null)
        {
            // "ApplicationSettings.DefaultDatabasePath" is the custom config value I'm updating
            section.ApplicationSettings.DefaultDatabasePath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
            config.Save();
        }
    }
    finally
    {
        // remove asm resolve handler.  
        AppDomain.CurrentDomain.AssemblyResolve -= tempResolveEventHandler;
    }

}

Check that 'MyCompany.MyApp.Configuration' is marked with copy local=true.

Check also that your project also references the dll's that 'MyCompany.MyApp.Configuration' depend upon.

The Setup Project will call all installer classes that it finds in the project assembly files.

I must admit that I tend to override the Install method within the Installer class.

Here's a direct cut and paste from some code that I have here:

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

   // System.Diagnostics.Debugger.Break();
    string targetDirectory = Context.Parameters["targetdir"];

    string param1 = Context.Parameters["Param1"];
    string param2 = Context.Parameters["Param2"];
    string param3 = Context.Parameters["Param3"];
    string param4 = Context.Parameters["Param4"];

    string exePath = string.Format("{0}AlarmMonitor.exe", "[SystemFolder]");

    PHPCCTVClassLibrary.CctvSite site = new PHPCCTVClassLibrary.CctvSite();
    site.Name = param1;
    site.EndPoint = string.Format(@"tcp://{0}:5005", param2);
    site.Password = param4;
    site.Username = param3;
    site.AutoReconnect = true;
    site.AlarmHandling = new PHPCCTVClassLibrary.CctvSiteAlarmHandling();
    site.AlarmHandling.Audio = new PHPCCTVClassLibrary.AudioSetup();
    site.AlarmHandling.Audio.AlarmAddedFile = "alarmadded.wav";
    site.AlarmHandling.Audio.AlarmDeletedFile = "alarmdeleted.wav";
    site.AlarmHandling.Audio.AlarmUpdatedFile = "alarmupdated.wav";

    PHPCCTVClassLibrary.CctvSites sites = new PHPCCTVClassLibrary.CctvSites();
    sites.Site = new PHPCCTVClassLibrary.CctvSite[] { site };
    System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(PHPCCTVClassLibrary.CctvSites));
    //System.Diagnostics.Debugger.Break();

    System.IO.TextWriter tw = new System.IO.StreamWriter(@"CCTVAlarmConfig.xml", false);
    serializer.Serialize(tw, sites);
    tw.Close();

}

It creates an xml config file, being called by a Custom action that runs at install and has the following CustomActionData: /Param1="[EDITA1]" /Param2="[EDITA2]" /Param3="[EDITA3]" /Param4="[EDITA4]" /targetdir="[TARGETDIR] "

EDITA1 etc come from a user interface with 4 text boxes. I have deliberately included a space after [TARGETDIR] as without it you'll get some quite odd behaviour as it can't then find the installation directory.

The System.Diagnostics.Debugger.Break() comment allows you to debug from this point if the line is uncommented.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!