SPWebConfigModification and SharePoint 2013

Sometimes it is needed to modify the web.config to change default ASP.NET settings. Within a  SharePoint environment you don’t want to do this manually, because it is error prone and also the changes are not propagated among all web front end servers in a single farm.

Within SharePoint there is a API called SPWebConfigModification which allows you to programmatically modify the web.config using XPath. The changes are automatically applied on the front ends using a built-in timerjob. In SharePoint 2010 it turned out that this API was not always stable. Some weird behavior is sometimes experienced with removing entries programmatically. According to some sounds from the community we can conclude that that has been fixed. Using that article and some others you will be able to create a solution to modify some attributes in the Web.config. Unfortunately there are not much examples and also MSDN documentation lacks some samples with some more complex XPath modifications using SPWebConfigModification class. In this post I want to show a more complex modifications to the web config the web.config instead of a small sample with only modifying an attribute.

Let’s assume that we want to add the following structure to the web.config to increase the execution timeout setting of a specific applicationpage. We want to add this under the node in the web.config file.

<location path="_layouts/15/PathToApplicationPage.aspx ">
    <system.web>
        <httpRuntime executionTimeout="600" />
    </system.web>
</location>

The SPWebConfigModification API provides methods to add/modify/delete sections, child elements and attributes. Unfortunately this API is not very well documented, which makes it hard the to implement this. It uses internally XPath to modify the web.config XML. It uses a Name and Path which needs to be a unique combination to identify the modification. These variables are needed to perform later operations like updating or deleting when you want to programmatically change your settings. Also the owner field is needed so that you identify which application has made the modification. Suggestion here is to use the assembly full name for the owner field, some unique key for the name and the path in XML where the node/section/attribute should be created/modified. The following code shows a sample of a utility class which you can use as basis for doing SPWebConfigModifications in your own full trust solution:

internal abstract class WebConfigUtility
{
	/// <summary>
	/// Holds the owner
	/// </summary>
	private readonly string owner;

	/// <summary>
	/// Gets or sets the sequence
	/// </summary>
	private uint Sequence
	{
		get;
		set;
	}

	protected WebConfigUtility()
	{
		owner = GetType().FullName;
	}

	/// <summary>
	/// Adds a new xml attribute to the web config file.
	/// </summary>
	/// <param name="name">
	/// Name of the attribute.
	/// </param>
	/// parentPath">
	/// The parent of this attribute.
	/// </param>
	/// <param name="value">
	/// The value of the attribute.
	/// </param>
	protected void CreateAttribute(string name, string parentPath, string value)
	{
		var webConfigModification = new SPWebConfigModification(name, parentPath)
		{
			Owner = owner,
			Sequence = Sequence,
			Type = SPWebConfigModification.SPWebConfigModificationType.EnsureAttribute,
			Value = value
		};
		AddConfigModification(webConfigModification);
	} 

	/// <summary>
	/// Adds a new xml node to the web config file.
	/// </summary>
	/// <param name="name">
	/// Name of the node.
	/// </param>
	/// parentPath">
	/// The parent of this node
	/// </param>
	/// <param name="value">
	/// The value of the node.
	/// </param>
	protected void CreateNode(string name, string parentPath, string value)
	{
		var webConfigModification = new SPWebConfigModification(name, parentPath)
		{
			Owner = owner,
			Sequence = Sequence,
			Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode,
			Value = value
		};
		AddConfigModification(webConfigModification);
	}

	/// <summary>
	/// Only use this if you need to add a section that does not have to be removed and may contain child nodes from other solutions.
	/// </summary>
	/// <param name="name">
	/// The name of the section.
	/// </param>
	/// <param name="parentPath">
	/// The parent path in the web.config file.
	/// </param>
	protected void CreateSection(string name, string parentPath)
	{
		var webConfigModification = new SPWebConfigModification(name, parentPath)
		{
			Owner = owner,
			Sequence = Sequence,
			Type = SPWebConfigModification.SPWebConfigModificationType.EnsureSection
		};
		AddConfigModification(webConfigModification);
	}

	/// <summary
	/// Adds the config modification.
	/// </summary>
	/// <param name="modification">
	/// The modification to apply.
	/// </param>
	private void AddConfigModification(SPWebConfigModification modification)
	{
		WebConfigModifications.Add(modification);
		Sequence++;
	}

	/// <summary>
	/// Removes the modifications of the webconfig of the current webapplication.
	/// </summary>
	/// <param name="webApplication">
	/// The web application.
	/// </param>
	internal void RemoveInternal(SPWebApplication webApplication)
	{
		if (webApplication == null)
		{
			throw new ArgumentNullException("webApplication");
		} 

		var toRemove = webApplication.WebConfigModifications.Where(modification => modification != null).Where(modification => string.Compare(modification.Owner, owner, true, CultureInfo.CurrentCulture) == 0).ToList(); 

		foreach (var modification in toRemove)
		{
			webApplication.WebConfigModifications.Remove(modification);
		} 

		UpdateWebConfig(webApplication);
	}

	/// <summary>
	/// Updates the webconfig of the current webapplication with the modifications.
	/// </summary>
	/// <param name="webApplication">
	/// The webapplication that needs to be configured.
	/// </param>
	protected void UpdateWebConfig(SPWebApplication webApplication)
	{
		try
		{
			webApplication.Update();
			webApplication.WebService.ApplyWebConfigModifications();
		}
		catch (Exception ex)
		{
                      // Add your exception handling and logging here
		}
	}
}

Let’s consider our first example and the helper class above to create the modifications:

CreateNode("location[@path='_layouts/15/PathToApplicationPage.aspx']", "configuration", "");

In this sample we add a new node. As name we specify a unique name which can be used to identify it later on. The second parameter is a path. This is configuration as we want to store the node under the configuration key. Please choose a different path when you need to create the node on a different location. The last parameter is the actual value. You can then use the UpdateWebConfig method together with a SPWebApplication object to save the changes. Also methods are included for removal which works in a similar way.

One thought on “SPWebConfigModification and SharePoint 2013

  1. kyle

    This was exactly what I was looking for. Most other posts I’ve found have been lacking detail. and to have a code example is awesome. I think you may be missing the Webapp object in AddConfigModification method. thanks again, solved my issues.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.