SPWebConfigModification

This is part two of a two part article. In the first part I reported on a couple of findings when working with the SPWebConfigModification API, in the this part I will introduce a simulator tool that allows to learn, experiment and generate code for SPWebConfigModification related tasks.

The utility can be downloaded from codeplex, it can be found here: http://wcms.codeplex.com.

This utility is applicable for SharePoint 2007 and SharePoint 2010. It has been compiled with a reference to the SharePoint 2010 assembly (hence the .NET 3.5 framework requirement), by changing the SharePoint version in the options screen a binding redirect is added in the configuration file so we can make it work with SharePoint 2007. Changing this setting requires a restart of the application.

WebConfigModificationSimulator – Some Features

  • Work with SPWebConfigModification without changing the configuration database or Web.Config – (avoid corrupt property bags, duplicate entries, …)
  • Work with actual artifacts (SharePoint Web.config, SPWebConfigFileChanges property bag entries) – (needs SharePoint Permissions, read-only)
  • Work on empty xml (or xml of own choice) to have clearer view.
  • Drag and Drop of entries between the two entry lists.
  • Auto lookup and complete when entering modification paths into the Web.config (avoids mistakes or typos).
  • Wizard like entry form that allows to easily create SPWebConfigModification entries, the system composes the name and value properties.
  • Code generation with possibility to save either in VB.NET or C#.
  • Save list entries to disk for later use.

WebConfigModificationSimulator – Introduction

This utility lets you experiment with SPWebConfigModification without the risk of messing up the content configuration database or the Web.config file. The main UI looks like this:

MainUI

When the window is loaded the utility tries to get a list of SPWebApplication instances in the local farm. If the user has not the necessary privileges to perform this action the text part of the web.config dropdown will show the message “Error – Could not load SharePoint WebApplications.“. The utility is fully functional but no live information can be retrieved from SharePoint. In this case you can add entries yourself (and maybe save them to file for later retrieval).

Adding SPWebConfigModification entries is done in the left part of the window, when these modifications are ‘applied’ the config file on the right will be updated. You can see that there are two lists where you can enter new SPWebConfigModification entries. This is to simulate the entries stored in the SPWebConfigFileChanges and SPWebApplication property bag (hence the Database icon) and the ones added or removed by code. You do not have to use the first list to experiment with SPWebConfigModification entries, but using the two will provide a more realistic view on what SharePoint is doing behind the scenes.

On the right part of the window you can see a Code tab, this is where you can generate code for the SPWebConfigModification entries in the two lists, this will be explained further in this article.

The entry area below the second list allows you to add new entries or modify existing ones. The name and value properties have to be added as they are written to the SharePoint system.

The utility provides a way to abstract this by using a kind of wizard entry form. This makes it really easy to add new SPWebConfigModification entries, no guessing anymore what needs to be entered. This will be shown in the next topic.

This code works exactly as the code SharePoint executes behind the scenes. I used reflector to extract the relevant parts, I mocked up some internal classes and the whole is an exact simulation of what happens when you work with SPWebConfigModification entries.

WebConfigModificationSimulator – Add SPWebConfigModification

Let’s do a first test with the simulator. We want to start simple and add a new node to the Web.config. Let’s call the node myFeatureConfig. It will be a node under our control, no one else should add nodes to it outside the scope of the feature itself so it is going to be an EnsureChildNode entry.

Start by clicking on the green plus icon (Add) in the header of the second list (or use the context menu on the second list), a new window will open:

AddEntry

The default Modification type is set to EnsureChildNode. We leave it as it is.

I already started typing in the Modification path textbox and you can see that I implemented auto lookup and auto complete. Since the node I want to add is directly under the configuration node I can just press Tab.

In the Node name textbox I type myFeatureConfig.

I then have the option to enter one or more attributes. Let’s just add one for fun, call it level and give it a value of 5.

Optionally you can enter then an xml fragment that is the innerXml of the new node. We do not have a need for that now so let’s leave it empty. The window should look now like:

AddEntry1

Notice that the name and value textbox contain automatically the correct value. In this way we are sure that these values are in sync.

Click OK.

This is the window as it will look like:

MainUI1

Now simulate ApplyWebConfigModifications of by clicking on the Apply Modifications icon (Apply). now the window looks like this:

MainUI2

The SPWebConfigModification entry has been applied and can be seen in the config file on the right. The entry is also shown in the first list now (which simulates that it has been stored in the SPWebConfigFileChanges and SPWebApplication property bags.

Remark:

A small note on the use of the checkboxes.

What I am trying to do here is simulate the process that is performed by custom code on one side (adding/removing SPWebConfigModification instances) and by SharePoint (the ApplyWebConfigModifications internal code). I gave it some thought but did not find an easy visual metaphor to represent this whole process. So enter the checkboxes…

The checkbox on the entries in the first list indicate whether we use either only the entry from the SPWebConfigFileChanges property bag (unchecked) or both from the SPWebConfigFileChanges and SPWebApplication property bags (checked). I use this to simulate the removal of SPWebConfigModification entries via code. Unchecking the checkbox in the previous scenario would be equal to:

SPWebService webService = SPWebService.ContentService;
SPWebApplication webApplication = webService.WebApplications[“SharePoint – 80”];
Collection<SPWebConfigModification> webConfigModifications = webApplication.WebConfigModifications;

webConfigModifications.Remove(webConfigModifications[0]);

///……

Once an entry exist in the first list a link becomes available in the first item of the second list (details). If you click on this link a new window will open that details what will be executed during the simulation, suppose we click on it when the first item in the first list is checked, we will see the following:

Details

This window shows indeed that the selected node will be first removed (as entry in the SPWebConfigFileChanges property bag) and then re-added as entry in the SPWebApplication property bag)

If the entry would be unchecked we would see:

Details2

The checkbox on the entries in the second list indicate only whether we ignore the selected entry from the ApplyWebConfigModifications process.

The utility has following context menu on the two lists:

ContextMenu

  • Get from ‘xxxx’: this menu item tries to retrieve the entries of the SPWebConfigFileChanges property bag. If the user has no access this option is not available. This menu item is only available on the first list.
  • Add WebConfigModification: shows the wizard entry form.
  • Delete WebConfigModification: deletes the currently selected entry from the list.
  • Load WebConfigModifications: loads the entries from a file into the selected list.
  • Save WebConfigModifications: saves the entries from the selected list to a file.
  • Apply WebConfigModifications: simulates the ApplyWebConfigModifications.
  • Clear All: removes all the entries from the selected list.

WebConfigModificationSimulator – Remove SPWebConfigModification

Now let’s continue with the previous scenario and simulate the removal of the SPWebConfigModification. When you remove a SPWebConfigModification entry through code you actually change the WebConfigModifications collection from either an SPWebApplication or SPWebService instance after which you call Update. This updates modifies actually the property bags in the configuration database. When you then call ApplyWebConfigModifications SharePoint uses these property bags to initiate the process.

This is what you can simulate by checking or unchecking the checkboxes in the first list. If you want to simulate the removal of a SPWebConfigModification entry all you have to do is uncheck the checkbox of that entry in the first list (remember this list represents the property bags in the configuration database)

Let’s do this in our example, uncheck the checkbox in the first list and either uncheck the checkbox in the second list or remove the entry by deleting it (if you leave this entry you simulate the addition of a new SPWebConfigModification entry and this is not what we try to do). This is what you should have now:

MainUI3

As you can see the entry has been removed from the Web.config file.

InfoThis utility allows you to verify whether the SPWebConfigModification properties are balanced in such a way that adding and removing nodes works correctly without having to modify a live environment.

WebConfigModificationSimulator – Code generation

The utility also allows to generate code for the entries currently defined. There is a choice between VB.NET and C#. Go to the Code tab, select you programming language and click on Generate. The utility will generate code using a preprocessed T4 template (new feature in Visual Studio 2010).

MainUI4

Here you see some auto generated code in C# for adding and removing SPWebConfigModification entries:

using System;
using System.Collections.ObjectModel;
using Microsoft.SharePoint.Administration;

namespace Wilke.SharePoint.Tools
{
public static class WebConfigModificationsHelper
{
private static SPWebService contentService = null;
private static SPWebApplication webApplication = null;

public static bool ApplyWebConfigModifications(string webAppUri)
{
bool result = false;

try
{
contentService = SPWebService.ContentService;
webApplication = SPWebApplication.Lookup(new Uri(webAppUri));

AddWebConfigModifications();
}
catch (Exception exception)
{
//TODO
//Provide appropriate exception handling.
}

return result;
}

private static bool AddWebConfigModifications()
{
bool result = false;

try
{
SPWebConfigModification spWebConfigModification = null;
spWebConfigModification = new SPWebConfigModification();
spWebConfigModification.Owner = “[WebConfigModificationTester]”;
spWebConfigModification.Path = “configuration”;
spWebConfigModification.Name = “myFeatureConfiguration[@level=’5′]”;
spWebConfigModification.Value = “<myFeatureConfiguration level=’5’/>”;
spWebConfigModification.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
spWebConfigModification.Sequence = 0;
webApplication.WebConfigModifications.Add(spWebConfigModification);

spWebConfigModification = new SPWebConfigModification();
spWebConfigModification.Owner = “[WebConfigModificationTester]”;
spWebConfigModification.Path = “configuration/myFeatureConfiguration[@level=’5′]”;
spWebConfigModification.Name = “useDatabase”;
spWebConfigModification.Value = “<useDatabase/>”;
spWebConfigModification.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
spWebConfigModification.Sequence = 0;
webApplication.WebConfigModifications.Add(spWebConfigModification);

webApplication.Update();
contentService.ApplyWebConfigModifications();
}
catch
{
throw;
}

return result;
}

private static bool RemoveWebConfigModificationsInternal(string owner, string path, string name)
{
bool result = false;
bool needsUpdate = false;

try
{
Collection<SPWebConfigModification> webConfigModifications = webApplication.WebConfigModifications;

int modificationCount = webConfigModifications.Count;
for (int index = modificationCount – 1; index > -1; index–)
{
if (webConfigModifications[index].Owner == owner &&
webConfigModifications[index].Path == path &&
webConfigModifications[index].Name == name)
{
webConfigModifications.Remove(webConfigModifications[index]);
needsUpdate = true;
}
}
if (needsUpdate)
{
webApplication.Update();
contentService.ApplyWebConfigModifications();
}
}
catch
{
throw;
}

return result;
}

private static bool RemoveWebConfigModificationsInternal(string owner)
{
bool result = false;
bool needsUpdate = false;

try
{
Collection<SPWebConfigModification> webConfigModifications = webApplication.WebConfigModifications;

int modificationCount = webConfigModifications.Count;
for (int index = modificationCount – 1; index > -1; index–)
{
if (webConfigModifications[index].Owner == owner)
{
webConfigModifications.Remove(webConfigModifications[index]);
needsUpdate = true;
}
}
if (needsUpdate)
{
webApplication.Update();
contentService.ApplyWebConfigModifications();
}
}
catch
{
throw;
}

return result;
}
}
}

Remarks:

  • Namespace and SPWebConfigModification owner can be changed via the options.
  • In this first version the T4 template is already preprocessed, in a future version I might make it as a configurable feature.

WebConfigModificationSimulator – Options

Options

  • SharePoint version: The version of the Microsoft.SharePoint assembly to use, changing this requires a restart of the application.
  • Path to SharePoint config files: the path where SharePoint stores its configuration files. Normally this inside the wss folder in the C:inetpub folder but this can be also in a different location.
  • Namespace for code generation: the namespace used when the code is generated.
  • Default modification owner: the owner set when creating SPWebConfigModification instances.
  • Frequently used node names: a list of node names frequently used in config files. This list is used for auto lookup in the node name textbox.
  • Nodes to ignore in auto lookup: SharePoint config files contain lots of entries that are not suitable for serving as parent node (e.g. SafeControls entries). During the collection of nodes to present in the auto lookup these nodes will not be included.
  • Auto lookup differentiating attributes: Some parent nodes have one or more attributes, when the node is selected as path we need to be able to uniquely identify this node. For this we use a differentiating attribute. This list represent attribute names that are frequently used to differentiate parent nodes with the same tag name.

WebConfigModificationSimulator – Known limitations

The auto lookup feature tries to enumerate the available nodes in the current config file (the one in the right part of the window). In order to identify nodes that contain attributes uniquely the utility uses following approach:

  • If the attribute has one of the following names: name, path or id, it will be used as differentiator of the node.
  • If the condition above is not met the first attribute is selected as differentiator.

This means that it is possible that a node with attributes is not found in the dropdown. In that case you can just type the path in the textbox.The options screen allows you to add additional attribute names tat should be recognized during the collection of the nodes to add for auto lookup.

WebConfigModificationSimulator – Acknowledgements

The code generation feature makes use of the ColorCode.dll. This library provides syntax coloring for several programming languages. The codeplex project can be found here: http://colorcode.codeplex.com/.

In order to keep a single executable package I used ILMERGE to merge the primary executable with the ColorCode.dll into one new merged executable. Using ILMERGE-GUI did help me not having to remember the command line arguments for ILMERGE. The codeplex project can be found here: http://ilmergegui.codeplex.com/.

WebConfigModificationSimulator – Feedback

This is the first time I publish a utility for a broader audience so I’m still in the process of fine tuning this process. If you have some constructive feedback please leave me a message, this might be about the articles on the utility or the utility itself.

Introduction

This is part one of a two part article. In the first part I will report on a couple of findings when working with the SPWebConfigModification API, in the second part I will introduce a simulator tool that allows to learn, experiment and generate code for SPWebConfigModification related tasks. This topic is not in any way a replacement for the official documentation, it only serves to highlight a couple tricky aspects.

Abstract

The SharePoint SPWebConfigModification API allows the developer to write code that updates the web.config in a semi transactional way. By semi transactional I mean that changes made to the web.config can be rolled back when a certain condition is met. SharePoint will also take care of making the changes to all web front ends in the SharePoint farm. The uneasy part of working with this API is that it is not that transparent to use and is not that well documented (although for the SharePoint 2010 version this seems to be somewhat better).

The basic steps for modifying the web.config are:

  • Get the current list of modifications
  • Remove existing entries if required
  • Add new entries if required
  • Update modifications
  • Apply modifications

As you can see these basic steps are easy to follow but in real life they can lead sometimes to unexpected situations.

Closer Look

Let’s go over the basic steps and look at these steps from a SharePoint point of view.

Get the current list of modifications

You can store SPWebConfigModification entries on the level of a SPWebService or SPWebApplication. In the former case the changes will be applied to all SPWebApplication instances in the farm, in the latter case the changes will be applied only to the selected SPWebApplication.

Where does SharePoint store the SPWebConfigModification entries for a SPWebService or SPWebApplication? Short answer: in the SharePoint configuration database. Longer answer: in two property bags that are persisted in the ‘Objects’ table in the SharePoint configuration database.

There are indeed two property bags where these modifications are stored, both in the Object table in the farm’s configuration database.

Let’s give an example:

Clean Situation

Suppose I have a farm with one SPWebApplication instance, and no SPWebConfigModification entries have been added. This is the initial clean situation.

I will look up information in the Object table with following SQL statement:

SELECT ParentId, ClassId,Name, CONVERT(xml, Properties) AS Properties
FROM [SharePoint2010_Config].[dbo].[Objects]
WHERE Name LIKE ‘%WebConfigChanges%’

Starting from the initial situation I would get:

tcz3kayz

Why did I use ‘%WebConfigChanges%’ in the query, because this is how SharePoint identifies the property bag that contains changes applied to the web.config.

Some remarks about the resultset:

– I did not print out the full content of the Properties field as this would be too long. But by using CONVERT(xml, Properties) I can click on the link in the properties field and a new window will open with the xml. This avoids you of having to go through the field as text (which is also limited in size).

The default xml looks as follows:

<object type=Microsoft.SharePoint.Administration.SPWebConfigFileChanges, Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c>
<fld type=System.Collections.SortedList, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 name=WebConfigChildNodes />
<fld type=System.Collections.SortedList, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 name=WebConfigAttrChanges />
<fld type=System.Collections.SortedList, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 name=WebConfigSections />
<fld type=System.Collections.Hashtable, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 name=m_UpgradedPersistedFields />
<fld name=m_Properties type=null />
<sFld type=String name=m_LastUpdatedUser>WKS-HERMESWilke</sFld>
<sFld type=String name=m_LastUpdatedProcess>psconfigui (3024)</sFld>
<sFld type=String name=m_LastUpdatedMachine>WKS-HERMES</sFld>
<sFld type=DateTime name=m_LastUpdatedTime>2010-08-25T20:59:06</sFld>
</object>

– The name WebConfigChanges – <Guid> is created by the API as follows:

internal class SPWebConfigFileChanges : SPPersistedObject
{
private static string s_BaseName;
static SPWebConfigFileChanges()
{
s_BaseName = “WebConfigChanges – “;
}
///
///
///
internal static string GenerateName(Guid serverId)
{
return (s_BaseName + serverId.ToString());
}
///
///
///
}

So the Guid is actually the id of the SharePoint server (farm).

– The ClassId is an identifier that tells you what class this property bag is associated with, in this case the ClassId points to the SPWebConfigFileChanges class in the Microsoft.SharePoint.Administration namespace, this can be seen also with reflector, look at the Guid attribute on this class definition:

[Obfuscation(Exclude = true, Feature = “renaming”, StripAfterObfuscation = true), Guid(“9B0E7DE4-847D-42cf-A84F-99CD76D4F1E6”)]
internal class SPWebConfigFileChanges : SPPersistedObject
{
/// <summary>
///
/// </summary>
}

Why are there two property bags although I only have one SPWebApplication instance? The second property bag comes from the Central Administration SPWebApplication. This can be traced back by taking the ParentId and executing a query to retrieve the property bag associated with that Id and then looking at the ClassId.

This is a list of some common ClassId’s

SPWebService 45AD2BF2-4E3E-46A1-B477-126944C0ACEF
SPWebApplication 113FB569-7520-4651-8FC4-E9F4F5887618
SPAdministrationWebApplication 4C0FA7BC-0812-4ED2-80AB-89D752898BC6
SPWebConfigFileChanges 9B0E7DE4-847D-42CF-A84F-99CD76D4F1E6
Apply one SPWebConfigModification

Let’s look at the situation where we apply one SPWebConfigModification to the SPWebApplication instance. This is done as follows:

SPWebService contentService = SPWebService.ContentService;
SPWebApplication webApplication = SPWebApplication.Lookup(new Uri(“SharePoint – 80”));

SPWebConfigModification spWebConfigModification = null;
spWebConfigModification = new SPWebConfigModification();
spWebConfigModification.Owner = “[WebConfigModificationTester]”;
spWebConfigModification.Path = “configuration”;
spWebConfigModification.Name = “connectionStrings”;
spWebConfigModification.Value = “<connectionStrings/>”;
spWebConfigModification.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
spWebConfigModification.Sequence = 0;
webApplication.WebConfigModifications.Add(spWebConfigModification);

webApplication.Update();
contentService.ApplyWebConfigModifications();

Now execute our query again but this time change the WHERE clause a bit:

SELECT ParentId, ClassId,Name, CONVERT(xml, Properties) AS Properties
FROM [SharePoint2010_Config].[dbo].[Objects]
WHERE Properties LIKE ‘%WebConfigModificationTester%’

This is because as you can see from the code snippet that adds the SPWebConfigModiciation we have set the Owner to [WebConfigModificationTester].

This is the new resultset:

qdpjmvwu

We have two rows in the resultset:

The first row is the property bag of the SPWebApplication (verify ClassId in ClassId table)

The second row is the updated property bag of the SPWebConfigFileChanges instance, the xml looks as follows:

<object type=Microsoft.SharePoint.Administration.SPWebConfigFileChanges, Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c>
<fld type=System.Collections.SortedList, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 name=WebConfigChildNodes>
<sFld type=String>configuration/connectionStrings</sFld>
<fld type=Microsoft.SharePoint.Administration.SPWebConfigModification, Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c>
<object type=Microsoft.SharePoint.Administration.SPWebConfigModification, Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c>
<sFld type=String name=m_Name>connectionStrings</sFld>
<sFld type=UInt32 name=m_Sequence>0</sFld>
<sFld type=String name=m_XPath>configuration</sFld>
<sFld type=String name=m_Owner>[WebConfigModificationTester]</sFld>
<sFld type=String name=m_Value>&lt;connectionStrings/&gt;</sFld>
<fld type=Microsoft.SharePoint.Administration.SPWebConfigModification+SPWebConfigModificationType, Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c name=m_Type>EnsureChildNode</fld>
<sFld type=String name=m_PreviousAttrValue />
</object>
</fld>
</fld>
<fld type=System.Collections.SortedList, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 name=WebConfigAttrChanges />
<fld type=System.Collections.SortedList, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 name=WebConfigSections />
<fld type=System.Collections.Hashtable, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 name=m_UpgradedPersistedFields />
<fld name=m_Properties type=null />
<sFld type=String name=m_LastUpdatedUser>WKS-HERMESWilke</sFld>
<sFld type=String name=m_LastUpdatedProcess>ConsoleApplication2.vshost (10408)</sFld>
<sFld type=String name=m_LastUpdatedMachine>WKS-HERMES</sFld>
<sFld type=DateTime name=m_LastUpdatedTime>2010-11-09T15:12:52</sFld>
</object>

Here you see that a new fld element is added with the information added by the SPWebConfigModification entry.

Why is the SPWebConfigModification stored in two places?

The entry in the property bag associated with the SPWebApplication is coming from the statement:

webApplication.Update();

The entry in the property bag associated with the SPWebConfigFileChanges is coming from the statement:

contentService.ApplyWebConfigModifications();

So this means if you only call the first statement no change will be made at that time to the actual web.config file. The entry is only stored in the property bag of the SPWebApplication instance. If at a later stage the ApplyWebConfigModifications is called the changes will be stored in the SPWebConfigFileChanges property bag and propagated to the actual Web.config file.

If you do not call the Update statement strange things can happen, the first time you call ApplyWebConfigModifications the entry will be stored in the SPWebConfigFileChanges property bag and the entry will be added to the Web.config, nothing will be stored in the SPWebApplication property bag though. If you call a second time ApplyWebConfigModifications (without invoking the code that modifies the WebConfigModifications collection) you will notice that the entry will be removed from the SPWebConfigFileChanges property bag and also removed from the Web.Config. An explanation can be found when we look how SharePoint processes the SPWebConfigModification entries.

This means that:

  • Update saves the entries to the property bag associated with SPWebApplication or SPWebService.
  • ApplyWebConfigModifications stores the entries to the property bag associated with the SPWebConfigFileChanges instance and makes the changes to the Web.config.

How does SharePoint apply SPWebConfigModifications?

We have seen that changes to the actual Web.config file are made by the call to ApplyWebConfigModifications. So let’s focus on this method.

Each time you call ApplyWebConfigModifications there are a couple of steps that are performed:

ApplyWebConfigModification

Let’s go over the scenario again where ApplyWebConfigModifications was called without a prior Update in the case where only one SPWebConfigModification is added to the WebConfigModifications collection of the SPWebApplication instance.

If you look at this process you can now understand why the Web.Config change is removed the second time you call ApplyWebConfigModifications without having called Update. The first time you invoke the code, the entry is found in the WebConfigModifications collection of the SPWebApplication instance you are working with and that you changed via code (although it has not yet been updated it is available in memory). So these changes will be applied to the Web.config file and stored in the SPWebConfigFileChanges property bag.

The next time you call ApplyWebConfigModifications (if you did not invoke the code that makes a change to the WebConfigModifications collection) the entry will be removed from the Web.config file (assuming the entry can be found and it is not an EnsureSection entry) and since it is not to be found in the SPWebApplication property bag (either from config database and/or via code) it will not be reapplied. Since at this time the new entries collection is empty an the SPWebConfigFileChanges property bag will not contain any entries anymore.

What’s the difference between EnsureSection and EnsureChildNode

Conceptually EnsureSection is used when you want to be sure that a parent node to which additional nodes have to be added exist. Since in some cases you are not the only one that will add nodes to this parent node it can not be removed. A good example is the connectionStrings node, if you need to add a connectionString as part of a feature deployment you must be sure that the parent node in this case connectionStrings exists. But once the node has been added it is very well possible that other developers have added connectionString nodes to this parent node. If the feature you created is deactivated (assuming the SPWebConfigModification logic is in the feature event receivers) the parent node can not be removed without further complications for other parts of environment.

So EnsureSection should be used for single nodes, only the Path and Name property of the SPWebConfigModification are used.

EnsureChildNode is used when:

  • You need to add a single node, e.g. add connection string entry to connectionStrings tag. This node is under your control and should be able to be removed again.
  • You need to add a xml fragment to a parent node.
Adding and EnsureChildNode entry

When an EnsureChildNode entry is added: Path, Name and Value properties are used. Process flow for modifying the Web.config file:

EnsureChildNode-Add

WarningImportant to note is that SharePoint does not validate whether the Name property can be used to remove the node added by the Value property.
Removing and EnsureChildNode entry

When an EnsureChildNode entry is removed: Path and Name properties are used. Process flow for modifying the Web.config file:

EnsureChildNode-Remove

So here you see that the Name and Value property must be aligned, if not it is possible that you can add an EnsureChildNode entry but never remove it again, or you add multiple times the same node.

In the following article I will introduce an small utility that will allow developers to learn, experiment and generate code for working with SPWebConfigModification entries without writing to the configuration database or changing the Web.config file. It allows you also to get the actual entries stored in the different property bags to provide a more life like experience.