Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

SharePoint web.config modifications

3.50/5 (2 votes)
23 May 2012CPOL7 min read 44.4K   542  
Using SPWebConfigModification to modify web.config for SharePoint

Introduction

Since SharePoint is based on ASP.NET technology it uses web.config files to store settings used by the WebApplication. There are times when this file may need to be modified to add to setting necessary for a particular feature, such as, database connection strings or web services. Although you could edit the web.config file  manually, in an Enterprise environment with multiple servers and multiple WebApplications this would quickly become an unsupportable and cumbersome technique. To overcome this the SharePoint API includes the SPWebModification class to apply modification to elements or attributes in the web.config.    

Unfortunately very little has been written about how this class functions and how modifications are applied so I will explore how to use it and other techniques to make modifications to web.config files in SharePoint. 

To demonstrate I'll use a simple Console application rather than create a SharePoint feature so it can be easily stepped through in the debugger to see what is happening. Although teh code written using SharePoint 2010 the techniques apply to 2007 also.

SPWebModification class

To registers changes to the web.config file for a Web Application you need to create an instance of Microsoft.SharePoint.Administration.SPWebModification class which is found in the Microsoft.SharePoint.dll assembly. 

SPWebConfigModification EnsureChildNode = new SPWebConfigModification
    {
        Owner = "CodeProject",
        Path = "configuration/appSettings",
        Name = string.Format("add [@key='myAttribute'] [@value='{0}']", 1),
        Value = string.Format("<add key='myAttribute' value='{0}' />", 1),
        Sequence = 1,
        Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode
    };
    

The class has six public properties that we are concerned with. The Owner property is used to identify who made the modification and is typically set to the name of the feature or solution making the modifications. Later, when removing modifications I'll show how to use it. The Path property is an XPath expression used to find the element within the web.config file. In this example the      modification is being made to the appSettings section. The Name property is an XPath expression that is used in conjunction with the path to form a key to a SortedList as I'll show later and to apply modifications. The Value property is the value to be inserted, or removed, from the web.cofig file. The Sequence property tells what order to apply the modification. The Type property tell what type of modification is being made, either a child node, attribute or section as defined by the SPWebConfigModification.SPWebConfigModificationType enumeration. I'll take a closer look at these properties when applying the modifications. 

Modifications being made are added to the SPWebApplication class using the WebConfigModifications property which is, of course, a collection of  SPWebConfigModifications. Once all modifications have been added to the collection they are applied to the  web.config file by calling the ApplyWebConfigModifications method of the SPWebService class.         

SPWebService.ApplyWebConfigModifications

This method will check if a TimerService instance is available, and if so, create a SPWebConfigJobDefinition instance scheduled to run immediately. Otherwise it will iterate through all WebApplications within its scope and call the ApplyWebConfigModifications method for that SPWebApplication. The same process occurs in the Execute method of the SPWebConfigJobDefinition if created.

SPWebApplication.ApplyWebConfigModifications

The first thing that happens in this method is any previous changes that have been made to the web.config file are retrieved from the configuration database as an instance of a SPWebConfigFileChanges class. This class has three SortedLists, one for each of the types of modifications that can be made, WebConfigChildNodes, WebConfigAttrChanges and WebConfigSections. A second instance of a SPWebConfigFileChanges class is created and initialized with the SPWebApplication.

From here the RebuildListModifications method of the SPWebConfigFileChanges class is called with the SPWebConfigModifications collection of the SPWebApplication. This method in turn calls the AddListModifications method with the SPWebConfigModifications collection. Its here where the Path and Name properties of the SPWebConfigModification          object are combined and used as the key for the appropriate modifications collection. If the key is not already present in the collection it will be added. In the case of the EnsureChildNode and EnsureAttribute types if the SPWebConfigModification matching the key is found in the collection the Sequence properties will then be compared. If the Sequence of the modification being added is greater than or equal to the existing modification it will replace the the existing modification.

foreach (SPWebConfigModification modification in changes)
{
    string key = modification.Path + "/" + modification.Name;
    SPWebConfigModification modification2 = null;
    switch (modification.Type)
    {
        case SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode:
        {
            modification2 = (SPWebConfigModification) this.WebConfigChildNodes[key];
            if (modification2 == null)
            {
                break;
            }
            if (modification.Sequence >= modification2.Sequence)
            {
                this.WebConfigChildNodes[key] = modification;
            }
            continue;
        }
        // remainder removed for clarity
    }
}

To illustrate, I'll create two SPWebConfigModification objects and set the Sequence properties to 1 and 2.

public static SPWebConfigModification ChildNode = new SPWebConfigModification
{
    Path = "configuration/appSettings",
    Name = string.Format("add [@key='myAttribute'] [@value='{0}']", 1),
    Sequence = 1,
    Owner = "CodeProject",
    Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode,
    Value = string.Format("<add key='myAttribute' value='{0}' />", 1)
};

public static SPWebConfigModification ChildNode2 = new SPWebConfigModification
{
    Path = "configuration/appSettings",
    Name = string.Format("add [@key='myAttribute'] [@value='{0}']", 1),
    Sequence = 2,
    Owner = "CodeProject",
    Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode,
    Value = string.Format("<add key='myAttribute' value='{0}' />", 2)
};

After applying these modifications only the second one will be added to the web.config file.

webApp.WebConfigModifications.Add(ChildNode);
// Only this one will be added since the sequence is higher than
// the previous modification
webApp.WebConfigModifications.Add(ChildNode2);
webApp.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications();

After the RebuildListModifications method completes the AddListModifications is again called, this time with the WebConfigModifications collection of the SPWebApplications parent, the SPWebSevice.
   
After all of the modifications have been added to the SPWebConfigFileChanges the web.config file will be located the SPIssSettings of the SPWebApplication and loaded into a XmlDocument. Using the XmlDocument the previous ChildNode and Attribute modifications are removed via the RemoveModificationsWebConfigXmlDocument method. Then ApplyModificationsWebConfigXmlDocument is called to add the new modifications to the web.config file.    

Both the RemoveModificationsWebConfigXmlDocument and ApplyModificationsWebConfigXmlDocument very simply use the Path property of the SPWebConfigModification object as the parameter for the SelectSingleNode method. If found, the node is then either removed or in the case of EnsureChildNode the Name property is used in another SelectSingleNode using that node and the InnerXml is appended to with the Value property. In the case of the EnsureAttribute the SetAttribute  method for the node is called using the Value property. For the EnsureSection type the Name property is used in SelectSingleNode for the parent node and if it does not exist it is appended to the InnerXml of the parent node.

// Some code removed for clarity
foreach (SPWebConfigModification modification2 in this.WebConfigChildNodes.Values)
{
    XmlNode node2 = xdWebConfig.SelectSingleNode(modification2.Path);
    if (node2 == null)
    {
        throw new SPException(SPResource.GetString("WebConfigModNodeNotFound", new object[] { filepath, modification2.Path }));
    }
    if (node2.SelectSingleNode(modification2.Name) == null)
    {
        if (modification2.Value.Length == 0)
        {
            throw new SPException(SPResource.GetString("WebConfigEmptyChildNodeValue", new object[] { modification2.Name }));
        }
        node2.InnerXml = node2.InnerXml + modification2.Value;
    }
}
foreach (SPWebConfigModification modification3 in this.WebConfigAttrChanges.Values)
{
    XmlElement element = xdWebConfig.SelectSingleNode(modification3.Path) as XmlElement;
    if (element == null)
    {
        throw new SPException(SPResource.GetString("WebConfigModNodeNotFound", new object[] { filepath, modification3.Path }));
    }
    if (element != null)
    {
        modification3.PreviousAttrValue = element.GetAttribute(modification3.Name);
        element.SetAttribute(modification3.Name, modification3.Value);
    }
}

Notice from this code that current value of the attribute is saved to the PreviousAttrValue property so that it can be restored when removing the modification.

One thing to note is the ApplyModificationsWebConfigXmlDocument method first calls the SPAspConfigurationFile.EnsureSystemWebServerSection method to ensure the webServer modules and handlers elements are in the web.config file. This is the reason that even if ApplyWebConfigModifications is called with no modifications being made the web.config file is still modified.

After the modifications have been applied the web.config file is saved and the original SPWebConfigFileChanges is rebuilt to include the new modifications and persisted for future use.

Removing modifications

As alluded to early the Owner property of the SPWebConfigModification is used when remove modifications to the web.config.

private static void RemoveMods(SPWebApplication webApp)
{
    List<SPWebConfigModification> mods = webApp.WebConfigModifications
        .Where(m => m.Owner == "CodeProject")
        .ToList();

    foreach(SPWebConfigModification mod in mods)
    {
        webApp.WebConfigModifications.Remove(mod);
    }

    webApp.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications();
}

Here I've used Linq to find all the SPWebConfigModification in the SPWebApplication's WebConfigModifications collection that have the Owner equal to "CodeProject". Use the Owner should help to mitigate the possibility of removing modifications that may have been done by others. After finding the modifications I remove them from the WebConfigModifications collection. As described earlier, when  ApplyWebConfigModifications one of the first steps is to remove current settings. Note, however, this will only apply to EnsureChildNode  and EnsureAttribute modifications since this is all the RemoveModificationsWebConfigXmlDocument method handles.

Using Supplemental Config Files

Another way to modify the web.config file for a WebApplication is to make use of a supplemental config file. These xml files have names that begin with webconfig, such as webconfig.codeproject.xml, and are placed in the [SharePoint Root]\Config folder. When a new WebApplication is created SharePoint will merge the web.config file in that folder with supplemental config files to produce the    file web.config file that is placed in the virtual folder for the WebApplication.    

Supplemental config files have an actions element with three types of actions, add, update and remove.

<actions>
  <add path="configuration/appSettings">
    <add key="myAttribute" value="1"/>
  </add>
  <update path="configuration/appSettings">
    <add key="myAttribute" value="42"/>
  </update>
  <remove path="configuration/mySection" />
  <remove path="configuration/appSettings/add[@key = 'myAttribute']" />
</actions>

As you can see from this short example, the path attribute is a XPath for the element that is being added, updated or removed. In the remove action you can see that specific attributes can be removed, not just entire elements. More examples of supplemental config files can be found in the [SharePoint Root]\Config folder

Something to keep in mind when a supplemental config file s that it is applied only when the WebApplication is created, not when a feature is activated. However, supplemental config files have the benefit of being reapplied when an update or service pack is applied, whereas those done using SPWebConfigModification would need to be manually reapplied.

Conclusion

Applying modifications to the web.config file in SharePoint isn't very complicated, however, since there isn't much documentation on these methods it isn't very clear either. I hope this brief exploration helps to clarify the process. 

History

Initial release: 5/23/2012

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)