Tuesday, May 4, 2021

Uncomment section in XML file using C#.Net

Requirement 

As part of the installation, some XML fragments (eg: <authentication>) need to be uncommented in web.config file based on the environment,. This can be done either via PowerShell or C#.Net as this has to be triggered from MSI installation. Never during the runtime of the application.

Alternatives

We can either do string-based detection and replace it. Or use XML parser of .Net. Since the string parser is complex, let us stick with the .Net library to replace it.

Solution

The below code snippets is replacing the commented <authentication> tag in XML with its uncommented version.

private static XDocument ReadXMLFileWithoutLocking(string absoluteSourcePath)
{
    XmlReaderSettings readerSettings = new XmlReaderSettings()
    {
        IgnoreComments = false
    };
    using (XmlReader reader = XmlReader.Create(absoluteSourcePath, readerSettings))
    {
        XDocument xDoc = XDocument.Load(reader);
        return xDoc;
    }
}

This code snippet is used to read any XML file including the commented sections in it. Note the IgnoreComments=false setting. In this scenario, the path will be to a web.config file. Below goes the code to find commented code, uncomment and save to the same file.

private static bool TryUncommentingAuthenticationNode(string absoluteSourcePath)
{
    XDocument xDoc = ReadXMLFileWithoutLocking(absoluteSourcePath);
    var result = xDoc.DescendantNodes()
        .Where (node => node.NodeType == XmlNodeType.Comment)
        .Select(node=> node as XComment)
        // Kind of bad way to check string. Better parse the value and make sure its <authentication> node. Or atleast use RegEx
        .Where(node => node.Value.StartsWith("<authentication"))
        .FirstOrDefault();
    if (result == null)
    {
        return false;
    }
    else
    {
        Output.WriteLine(ConsoleColor.Cyan, $"Going to replace as its <authentication> node :  {result.Value}");
        result.ReplaceWith(XElement.Parse(result.Value));
        xDoc.Save(absoluteSourcePath);
        return true;
    }
}
The code to detect whether the commented node has the actual content is a little tricky as seen in the code. This is just giving the idea, not production code. Write production code by thinking of all scenarios to sleep well in the night and enjoy weekends.
The working sample can be found in GitHub.

Happy coding.

No comments: