How To Handle Sitecore Patch Config Files Programmatically?

Hugo Santos - Sitecore Architect

16 Mar 2021

Share on social media

It may not happen all the time, but when it happens, you know for sure that you are going to be wasting a lot of time figuring out how to use code to handle all those Sitecore config files. Well, not anymore. In this blog post, I’m going to show you exactly how to enable, disable, read and write config files easily within 5 minutes. Let’s start by assuming that we have the following config file named App_Config\Include\Blog\Blog.Connector.config.disabled: <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"> <sitecore> <blog> <configs> <entry attributeExample="fistItem"> <Name>fistItem</Name> <Type>remote</Type> <Url>https://www.example.com</Url> </entry> <entry attributeExample="secondItem"> <Name>secondItem</Name> <Type>local</Type> <Url>https://www.dot.com</Url> </entry> </configs> </blog> </sitecore> </configuration>

The first thing I suggest is to start by creating a model structure accordingly to what you have on your config file. In my case, that’s what I’ve come up with:

public class BlogConfiguration { public string Name { get; set; } public string Type { get; set; } public string Url { get; set; } } public class BlogConfigurations { public List<BlogConfiguration> Configs { get; set; } }

Enabling previously disabled config files

As we all know, a new config file triggers an IIS App recycle operation, which can definitely slow down your application. For that reason, it’s a common requirement having to deploy a disabled config file that might be enabled later when the time comes. Here I show how you can check if a given config file is disabled and how to enable it programmatically: public class BlogConfigurationHandler { private const string BLOG_CONFIG_NAME = "Blog.Connector.config"; private const string BLOG_CONFIG_NAME_DISABLED = "Blog.Connector.config.disabled"; private readonly string m_BlogConfigFilePath; private readonly string m_BlogDisabledConfigFilePath; public BlogConfigurationHandler() { m_BlogConfigFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "App_Config\\Include\\Blog\\", BLOG_CONFIG_NAME); m_BlogDisabledConfigFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "App_Config\\Include\\Blog\\", BLOG_CONFIG_NAME_DISABLED); } public void EnableConfigurationFile(string filePath) { if (filePath.EndsWith(".disabled") && File.Exists(filePath)) { File.Move(filePath, filePath.Replace(".disabled", "")); } } public bool IsConfigurationFileEnabled(string filePath) { return File.Exists(filePath); } }

Reading the configuration file

Once you have your config file enabled, you are probably going to need to read it in order to apply those configurations somehow. Here is an easy way of doing so in two useful ways: public BlogConfigurations GetBlogConfigurations() { var config = new BlogConfigurations(); config.Configs = new List<BlogConfiguration>(); var nodes = Factory.GetConfigNodes("Blog/configs/entry"); foreach (XmlNode node in nodes) { var configNode = Factory.CreateObject<BlogConfiguration>(node); if (!string.IsNullOrEmpty(configNode.Name)) { config.Configs.Add(configNode); } } return config; } public Dictionary<string, BlogConfiguration> GetBlogConfigurationsDictionary() { var configs = GetBlogConfigurations(); var dic = new Dictionary<string, BlogConfiguration>(); foreach (var config in configs.Configs) { if (!dic.ContainsKey(config.Name)) { dic.Add(config.Name, config); } } return dic; }

Writing the configuration file

When it comes the time to store information into a config file, things are not that easy as reading or enabling it. Here is how you can add config nodes, add attributes and even add children elements to your configuration file:

public void SetBlogConfigurations(List<BlogConfiguration> models) { if (!IsConfigurationFileEnabled(m_BlogConfigFilePath)) { EnableConfigurationFile(m_BlogDisabledConfigFilePath); } UpdateBlogConfigurationFile(models); } private void UpdateBlogConfigurationFile(List<BlogConfiguration> models) { var configXml = LoadConfigurationFile(m_BlogConfigFilePath); var configsNode = configXml.DocumentElement.SelectSingleNode("sitecore/Blog/configs"); configsNode.RemoveAll(); foreach (var model in models) { if (!string.IsNullOrEmpty(model.Name)) { var newEntryNode = CreateEntryConfigurationNode(configXml, model); configsNode.AppendChild(newEntryNode ); } } configXml.Save(m_BlogConfigFilePath); } private XmlNode CreateEntryConfigurationNode(XmlDocument document, BlogConfiguration model) { var newNameNode = document.CreateNode(XmlNodeType.Element, "Name", ""); newNameNode.InnerText = model.Name; var newTypeNode = document.CreateNode(XmlNodeType.Element, "Type", ""); newTypeNode.InnerText = model.Type; var newUrlNode = document.CreateNode(XmlNodeType.Element, "Url", ""); newUrlNode.InnerText = model.Url; var entryNode = document.CreateElement("entry"); entryNode.SetAttribute("attributeExample", model.Name); entryNode.AppendChild(newNameNode); entryNode.AppendChild(newTypeNode); entryNode.AppendChild(newUrlNode); return entryNode; } private XmlDocument LoadConfigurationFile(string filePath) { XmlDocument xmlDocument = new XmlDocument(); xmlDocument.Load(filePath); return xmlDocument; }

Conclusion

It may not be the most business-oriented feature, but handling your configuration files programmatically might be super useful. From now on, you won’t need to waste a single minute thinking about this. Go ahead and use this precious time to bring value to your client!

Sign up to our newsletter


Tags:

Sitecore

Share on social media

Hugo Santos

Hugo is bright, amiable, and energetic. He is passionate about creating great solutions that don't just follow best practices, but further them. His passion for doing great work is equaled only by his willingness to share his expertise with the Sitecore community by blogging and advocacy, like helping to organize the Quebec Sitecore User Group. In recognition for all that he does for the Sitecore Community, Sitecore awarded him his first, but certainly not last, Sitecore Technology MVP award in 2020. Hugo specializes in search and automation, including testing automation.


Subscribe to newsletter