Pergunta

Escrevi um pequeno utilitário que me permite alterar uma simples aplicativo para o arquivo app.config de outro aplicativo e salve as alterações:

 //save a backup copy first.
 var cfg = ConfigurationManager.OpenExeConfiguration(pathToExeFile);
 cfg.SaveAs(cfg.FilePath + "." + DateTime.Now.ToFileTime() + ".bak"); 

 //reopen the original config again and update it.
 cfg = ConfigurationManager.OpenExeConfiguration(pathToExeFile);
 var setting = cfg.AppSettings.Settings[keyName];
 setting.Value = newValue;

 //save the changed configuration.
 cfg.Save(ConfigurationSaveMode.Full); 

Isso funciona bem, exceto para um efeito colateral. O arquivo .config recém -salvo perde todos os comentários XML original, mas apenas na área de AppSettings. É possível reter comentários XML na área de AppSettings de arquivo de configuração original?

Aqui está uma pastebin da fonte completa, se você quiser compilar e executá -la rapidamente.

Foi útil?

Solução

Eu pulei para o refletor.net e olhei para a fonte descompilada para esta classe. A resposta curta é não, não manterá os comentários. A maneira como a Microsoft escreveu a classe é gerar um documento XML a partir das propriedades da classe de configuração. Como os comentários não aparecem na classe de configuração, eles não voltam ao XML.

E o que piora isso é que a Microsoft selou todas essas classes para que você não possa derivar uma nova classe e inserir sua própria implementação. Sua única opção é mover os comentários para fora da seção AppSettings ou usar XmlDocument ou XDocument Classes para analisar os arquivos de configuração.

Desculpe. Este é um caso de borda que a Microsoft simplesmente não planejou.

Outras dicas

Aqui está uma função de amostra que você pode usar para salvar os comentários. Ele permite que você edite um par de chave/valor por vez. Também adicionei algumas coisas para formatar o arquivo com base na maneira como eu geralmente uso os arquivos (você pode remover facilmente isso, se desejar). Espero que isso possa ajudar outra pessoa no futuro.

public static bool setConfigValue(Configuration config, string key, string val, out string errorMsg) {
    try {
        errorMsg = null;
        string filename = config.FilePath;

        //Load the config file as an XDocument
        XDocument document = XDocument.Load(filename, LoadOptions.PreserveWhitespace);
        if(document.Root == null) {
            errorMsg = "Document was null for XDocument load.";
            return false;
        }
        XElement appSettings = document.Root.Element("appSettings");
        if(appSettings == null) {
            appSettings = new XElement("appSettings");
            document.Root.Add(appSettings);
        }
        XElement appSetting = appSettings.Elements("add").FirstOrDefault(x => x.Attribute("key").Value == key);
        if (appSetting == null) {
            //Create the new appSetting
            appSettings.Add(new XElement("add", new XAttribute("key", key), new XAttribute("value", val)));
        }
        else {
            //Update the current appSetting
            appSetting.Attribute("value").Value = val;
        }


        //Format the appSetting section
        XNode lastElement = null;
        foreach(var elm in appSettings.DescendantNodes()) {
            if(elm.NodeType == System.Xml.XmlNodeType.Text) {
                if(lastElement?.NodeType == System.Xml.XmlNodeType.Element && elm.NextNode?.NodeType == System.Xml.XmlNodeType.Comment) {
                    //Any time the last node was an element and the next is a comment add two new lines.
                    ((XText)elm).Value = "\n\n\t\t";
                }
                else {
                    ((XText)elm).Value = "\n\t\t";
                }
            }
            lastElement = elm;
        }

        //Make sure the end tag for appSettings is on a new line.
        var lastNode = appSettings.DescendantNodes().Last();
        if (lastNode.NodeType == System.Xml.XmlNodeType.Text) {
            ((XText)lastNode).Value = "\n\t";
        }
        else {
            appSettings.Add(new XText("\n\t"));
        }

        //Save the changes to the config file.
        document.Save(filename, SaveOptions.DisableFormatting);
        return true;
    }
    catch (Exception ex) {
        errorMsg = "There was an exception while trying to update the config value for '" + key + "' with value '" + val + "' : " + ex.ToString();
        return false;
    }
}

Se os comentários forem críticos, pode ser que sua única opção seja ler e salvar o arquivo manualmente (via XmlDocument ou a nova API relacionada ao LINQ). Se, no entanto, esses comentários não forem críticos, eu os deixaria ir ou talvez considerar incorporá -los como elementos de dados (embora redundantes).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top