Click here to Skip to main content
Click here to Skip to main content

SPWebConfigModification Tool and Explorations

, 3 Dec 2009 CPOL
Rate this:
Please Sign up or sign in to vote.
An ASP.NET Web Part for testing the effects of SharePoint 2007 SPWebConfigModification changes
screenshot of top of SPWebConfigModification Tool web part

Introduction

When I first bumped into SPWebConfigModification and began researching it, I was amazed at how much confusion was expressed in blogs and articles about how to use this SharePoint class for programmatically making changes to web.config files. After working with it a bit, I'm no longer surprised at the confusion... It is typically used in a Feature receiver, but very awkward to test from a Feature receiver, so I wrote this tool (a web part) to make that easier. In this article, I've tried to highlight many of the usual stumbling blocks, and explain some of the not-so-obvious usage details.

Background

What's SPWebConfigModification?

Nuts spilling out of basketIn a nutshell, it is a collection of changes to be made to web.config files, created using the SharePoint Object Model, to be applied to all Web front end servers. There is minimal amount of official documentation, and I found myself doing an awful lot of digging and experimenting to find out how to use it. In fact, it can make you nuts at first! I learned most from reading articles and blog posts, and to all of those authors, many thanks - especially to Vincent Rothwell, Reza Alirezaei, Mark Wagner, DTerrell. My hope is that combining collected wisdom with new insights and providing a tool for exploration will save the reader much time. We'd better start at the beginning...

A SharePoint Web application is basically the same thing as an IIS web application. SharePoint extends this with the idea of zones. SharePoint Zones (Default, Intranet, Internet, Extranet, Custom) are like different doors opening into the same room- they provide different kinds of access to the same content. Each SharePoint Zone extension is implemented as a separate IIS web site, with its own web.config file. So, one SharePoint Web application may include several IIS web sites – and therefore several web.config files.

Why is that important? Applying the modification collection affects all web.config files for a Web application, but not uniformly- there are quirks. A SharePoint Web application maintains a collection of these modifications in the SharePoint configuration database. The SPWebService class is used to apply the Web application’s modification collection to all Web front ends by scheduling a timer job.

Typically a SharePoint Feature creates and stores the modification in the configuration database, calls a service to apply to WFEs

Typically this is used in a Feature receiver, adding web.config changes during Feature activation, and removing them during Feature deactivation, so everything stays tidy. One quirk that pops up here is that removal of a modification is only applied in the Default Zone, leaving all the other zones untouched. Another quirk is that if different changes are needed for different zones – say for a custom Role Provider - you can't do it – all zones get the same XML.

How does this basically work? Create an instance of the SPWebConfigModification class, and set 6 properties. Add as many of these modifications as needed to the Web application’s modification collection with the Add(modification) method, then call SPWebApplication.Update() to save the collection. Call SPWebService.ContentService.ApplyWebConfigModifications() to propagate the changes to the configuration database and WFEs. Removing is similar - find the modification(s) in the Web application’s collection using the Owner property, call the collection’s Remove(modification) method, then update and apply as before. There are tricky aspects to these 6 properties, so beware! Name and Value property definitions change according to the modification Type. Also, according to MSDN, "you must be an administrator on the front-end Web server for your code to work."

SPWebConfigModification Properties

  • Type
  • EnsureChildNode - The modification will add/remove child node(s)
  • EnsureAttribute - The modification will ensure the value of a particular attribute
  • EnsureSection - The modification will ensure that a section exists and is a singleton
  • Path - An XPath expression that locates the parent node being operated on in this modification

  • Name - Depends on the Type
  • For EnsureAttribute and EnsureSection, the attribute name or section name as a valid XML name (basically alphanumeric plus a few punctuation marks)
  • For EnsureChildNode, an XPath expression that uniquely identifies the child node(s) to be inserted as a child of the 'Path' parent node.
  • Owner - Do not leave this blank, this is critical for identifying modifications to be removed. Choose wisely. Choose something unique - maybe the Feature name or Id.

  • Sequence - This only applies when there are multiple modifications of the same type for the same node or attribute; otherwise it is ignored. If it is used, modifications will be applied in ascending order. Valid range: 0 to 65536. Not used in this article.

  • Value - Depends on the Type
  • For EnsureChildNode, the child node(s) to be added/removed
  • For EnsureAttribute, the value of the attribute
  • For EnsureSection, the name of the section

Using the Tool

The tool is a web part created on a MOSS 2007 development box, using WSPBuilder for deployment (http://www.codeplex.com/wspbuilder). For a brief explanation of .wsp files, and deploying them, see Building and deploying SharePoint Solution packages. It is intended to be used to troubleshoot modifications before using them, and to help understand how the process works. As a best practice, create a throwaway Web application on a development machine, extend it as much as needed for testing purposes, and point the tool there. Modifications can be created that break web sites… or even corrupt the database... all of which we're trying to avoid!

EnsureChildNode Example – A Single Node (the "Hello, World" example)

Select a Web application (use the Change/Set Test WebApp link at the top), preferably one set up expressly for testing modifications.

To add child node

<add key="AcademicYear" value="2009-2010" /> 

to parent node

configuration/appSettings

Fill in the properties like this: (Note – If you use copy & paste, be careful with the quotes- if smart quotes are pasted into the textbox, they create errors.)

left pane of tool displays all 6 SPWebConfigModification propeties and links to validate, add, save and apply

Text version of properties:

Path configuration/appSettings
Name add[@key="AcademicYear"]
Owner AcademicFeature
Sequence 0
Type EnsureChildNode
Value <add key="AcademicYear" value="2009-2010" />

Click Create and validate modification
Messages are displayed just below the Value textbox, with a dashed border. Basic validation will be attempted. Path will be checked for correct XPath syntax, and whether the node exists in the Default Zone web.config. Name will be checked for correct XPath syntax if an EnsureChildNode Type, or valid XML otherwise. Owner will be flagged if it is blank. Value will be tested to see if the XML is well-formed if an EnsureChildNode Type, and valid XML otherwise.

Click Add current modification to local collection
This will create the modification as well as add it, and if all goes well, the modification will then appear in the right pane. Modifications are listed in the order they are found in the collection, with the first one at the top of the list.

Click Save modification collection
This will call SPWebApplication.Update() for the current Web application; the collection visible in the right pane is the entire collection as accessed through code.

Click Apply modifications to Web Front-ends
Calls SPWebService.ContentService.ApplyWebConfigModifications(), which starts a timer job. If all goes well, a Modifications applied message will display, and all web.configs for the selected Web application will have the new node(s), typically just before the end tag of the parent node. In this case, a search for </appSettings> should help find the new < add key="AcademicYear" value="2009-2010" /> child node quickly. The configuration database is updated as well.

Click the show/hide link for the Default Zone web.config.
(I am design-challenged, so please bear with the web.config displays.) The browser’s Find-on-this-page tool will be helpful in finding the new node – the web.configs must be shown before the browser can search them, so expand the ones of interest. Here’s the right pane of the tool showing the new child node in the Default Zone web.config:

right pane of tool showing web.config with new node added

Configuration Database

Just for fun, let’s look in the SharePoint configuration database. A query like this displays a list that appears to be the modification collection. (Caution- I am guessing here.)

USE SharePoint_Config_Nancy
SELECT [O1].[Name]
      ,[O1].[Properties]
      ,[O2].[Name] ParentName
      ,[Classes].[FullName] ParentClassName
      ,[O1].[ParentId]
      ,[O1].[Status]
      ,[O1].[Version]
  FROM [SharePoint_Config_Nancy].[dbo].[Objects] O1
  LEFT OUTER JOIN
   [SharePoint_Config_Nancy].[dbo].[Objects] O2
     ON [O1].[ParentId] = [O2].[Id]
  LEFT OUTER JOIN
   [SharePoint_Config_Nancy].[dbo].[Classes] Classes
     ON [O2].[ClassId] = [Classes].[Id]
  WHERE ([O1].[Name] LIKE '%WebConfigChanges%')
  ORDER BY [O1].[Name]

Table display of SQL query showing WebConfigChanges

Right click in the Properties cell for the Web application of interest, choose Copy from the context menu, and paste the results into Notepad. In Notepad, save the XML with a friendly name like SharePoint3616.xml, and then view it in Internet Explorer.

XML copied from SQL query, saved to text file, displayed in Internet Explorer

Well there it is, I think – along with a bunch of other nodes that don't show up in code. Some articles I read commented that the modifications seem to be applied alphabetically, sorted according to Path+Name. Not sure how to verify this, but since the XML here appears to be a serialization of a SortedList, with the sort field composed of Path+Name, I'm inclined to think that is the case. And this could be very handy - more on that later.

Closing the fld elements gives this view – note the 3 names:

XML copied from SQL query, saved to text file, displayed in Internet Explorer, collapsed to 'fld' elements, showing names 'WebConfigChildNodes', 'WebConfigAttrChanges', 'WebConfigSections'

Back to the Tool

Click Remove modification(s) for current owner from local collection.

Right pane of tool showing no modifications found

The screen refreshes, and now there are no modifications found for this Web application. What about in the database? It is still there! What about the web.config? Still there too! Oops- we never clicked Save modification collection to update the Web application, and we did not click Apply modifications to Web Front-ends.

Let’s try again to actually remove the entry. Add it back. Remove. Update. Apply. Now it is gone from the database. The Default Zone web.config no longer has the AcademicYear element, but the Extranet and Internet Zones do. It worked, in its quirky fashion.

What about Clear local modification collection? Use with caution. This removes all entries, just as usual for any collection. If the empty collection is Updated and Applied to the WFEs, then all the modifications for that Web application will be removed. If there were modifications from a number of different Features, this could break some applications. But since this is pointed at a throwaway test application (right?) - it’s ok to experiment with it.

EnsureChildNode Example - A nodeset

What about adding the XML for a Membership provider? It looks something like this:

<membership defaultProvider="SPListUser">
  <providers>
    <add name="SPListUser" type="
        FBA.MembershipProvider.SPListUser,
        FBA.MembershipProvider,
        Version=1.0.0.0, Culture=neutral,
        PublicKeyToken= 8383efad02158ca5"
        applicationName="/" />
  </providers>
</membership>

This could be added one node at a time:

Path configuration/system.web
Name membership[@defaultProvider="SPListUser"]
Owner MembershipFeature
Sequence 0
Type EnsureChildNode
Value <membership defaultProvider="SPListUser" />

Path configuration/system.web/membership[@defaultProvider="SPListUser"]
Name providers
Owner MembershipFeature
Sequence 0
Type EnsureChildNode
Value <providers />

Path configuration/system.web/membership[@defaultProvider="SPListUser"]/providers
Name add[@name="SPListUser"]
Owner MembershipFeature
Sequence 0
Type EnsureChildNode
Value <add name="SPListUser" type="FBA.MembershipProvider.SPListUser, FBA.MembershipProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken= 8383efad02158ca5" applicationName="/" />

Or all-at-once like this:

Path configuration/system.web
Name membership[@defaultProvider="SPListUser"]
Owner MembershipFeature
Sequence 0
Type EnsureChildNode
Value <membership defaultProvider="SPListUser"> <providers> <add name="SPListUser" type="FBA.MembershipProvider.SPListUser, FBA.MembershipProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken= 8383efad02158ca5" applicationName="/" /> </providers> </membership> >

How to Make the Removal Fail (or "How This Can Make You Nuts")

For many developers, XPath is learned on an as-needed basis; that is, learning just enough to accomplish the current task, so the ability to detect slight inconsistencies may not be well developed. If we change the Name property on the all-at-once version of the membership provider modification above by just one character- delete the "@" so that it becomes membership[defaultProvider="SPListUser"], it will still validate, and it will still add the nodeset. Not only will it add the nodeset, it will keep adding it when modifications are applied, so that multiple copies are in the web.config, resulting in a 'PARSER ERROR MESSAGE: Sections must only appear once per config file' error.

Screenshot of browser showing error 'PARSER ERROR MESSAGE: Sections must only appear once per config file'

Worse, the removal now fails! So while it is critical to use the Owner property to identify the modifications for removal, it is also critical that Path+Name correctly identify the node(s) in the Value property. There are many excellent XPath tutorials and references; here’s one of my favorites: http://www.w3schools.com/xpath/ (I usually keep an XPath tutorial or two open in the browser when working with SPWebConfigModification.)

EnsureSection Example - What Exactly is a Section? (and More on Sorting)

A number of blog posts mentioned that sections cannot be removed by the removal method - but first, what is a section? Thanks to DTerrell, it looks like a section is an element node with no attributes that is not the innermost child node, or a child of a child node. I suspect EnsureSection comes in handy when needing to be sure parent nodes exist exactly once. (If you try adding a child node to a non-existent parent, it fails.) I tried adding a connectionStrings section as an EnsureSection Type, removing it- and it was still there. EnsureSection additions are permanent. But as long as EnsureSection modifications are used only for standard sections, that shouldn't be a problem- child nodes can always be removed, empty sections do no harm.

What if there are 2 or more modifications to add the same section? Only one section is created, so the singleton aspect seems true.

Remember the type=SortedList when looking at the database? If the modifications are sorted into order according to Path+Name, then the modifications will be in the correct order to build the parent nodes in the correct sequence. Looking at the 3 "fld"s in the database, if EnsureSection modifications are applied first, then EnsureChildNode, then EnsureAttribute, all sorted by Path+Name- then parent nodes will be built before child nodes are added, child nodes added before attributes are edited. This is a guess. I tried a few experiments to test this. The following experiment adds parent nodes one at a time with EnsureSection, and a child node with EnsureChildNode, but adds them to the modification collection out of order, with Sequence=0 for all.

In the following example, if they are sorted and applied as expected, then this XML should be added as a child of the configuration/system.web node:

<webParts>
  <personalization>
    <authorization>
      <allow users="*" verbs="modifyState" />
    </authorization>
  </personalization>
</webParts>

Here is the collection (the authorization element is added before the personalization element, and the child node is before all that – totally out of order):

Right pane of tool showing modifications, using EnsureSection, entered out of order

This works!

Another example, using EnsureChildNode only, adding the nodes out of order, and attempting to add the same node twice. Note second attempt has a different "duration" attribute value of 120. When multiple Features each add modifications to the collection, this scenario is quite possible.

Right pane of tool showing modifications, using EnsureChildNode, entered out of order

This worked, and only added the nodeset one time, with the duration attribute set to 120. I think it is clear that sorting is happening.

So why would one ever want to use EnsureSection rather than EnsureChildNode? The 2 outstanding characteristics seem to be that EnsureSection guarantees the node will only be created once, and that it cannot be removed. When using EnsureChildNode, it is possible for the same node to be created multiple times, resulting in a broken web site.

EnsureAttribute Example

A typical web.config has many appSettings entries, like this:

Right pane of tool showing modifications, showing web.config appSettings section

Let’s change the value of the FeedCacheTime to 450. First identify the target node in the Path, and remember Name and Value depend on the Type- Name is now the target attribute name, Value the attribute value to be assigned - like this:

Path configuration/appSettings/add[@key="FeedCacheTime"]
Name value
Owner FeedCacheAttributeFeature
Sequence 0
Type EnsureAttribute
Value 450

Don't forget that XML is case sensitive. The first time I tried this, I keyed in "Value" for the Name (note the capital "V"), and it added a second attribute, named "Value", with a value of 450. The result looked like this:

   <add key="FeedCacheTime" value="300" Value="450" /> 

Oops.

Tried it with Name = “value” and it worked - result:

   <add key="FeedCacheTime" value="450" />

Whew.

Miscellaneous Valuable Quotes

From http://msdn.microsoft.com/en-us/magazine/cc507633.aspx

SafeControl and CAS entries
For Web Part SafeControl entries and custom access control policies, rely on the SharePoint solution packaging framework.

Manually editing web.config when SPWebConfigModifications are in use
Manually removing or changing the entries in web.config that are managed by SharePoint won't do you any good in the long term. SharePoint tracks these entries and ensures that they are in web.config each time the WSS service restarts.

From http://www.crsw.com/mark/Lists/Posts/Post.aspx?ID=32

Development vs Production
It is important to remember that when developing and testing on a single server installation of SharePoint there are many activities that are able to complete instantly. However, when that same section of code executes on a SharePoint farm with multiple servers, the time it takes to complete a given task is longer. This is due to timer jobs and farm synchronization events that must occur.

For this reason, you should only execute the ApplyWebConfigModifications() method only once within a feature activation or event handler. If more than one call to the ApplyWebConfigModifications() method is made in close succession you will likely get the following error: A web configuration modification operation is already running.

[applying changes across the Farm – this code works]

myWebApp.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications(); 

Note: This code did not work across the farm (I could not tell you why).

SPFarm.Local.Services.GetValue<SPWebService>().ApplyWebConfigModifications(); 

Coda

In summary, SPWebConfigModification can be difficult to work with. The definition of the Name and Value properties vary according to the Type property, XML and XPath expressions must be precise, requiring a good bit of general knowledge about both, and general usage requirements are still a bit murky. I hope that the tool will make testing modifications and understanding SPWebConfigModification easier and faster. Happy coding!

License

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

Share

About the Author

N W Brown
Web Developer
United States United States
N W Brown has been programming/coding/developing for over 18 years, divided. About 8 years B.C. (before children), and 10+ years A.C. (after children finally went to high school and beyond). During the break (the "children" period), major changes took place in software development- like the introduction of the internet... Which just shows that the joy of playing with puzzles all day and getting paid for it never gets old!
 
When not coding, she is often a freelance flutist for events, musical theater or churches, or hikes one of the many local trails.

Comments and Discussions

 
AnswerAccess Denied error PinmemberN W Brown16-Sep-13 15:30 
QuestionAccess Denied error Pinmemberchakravarthys15-Sep-13 20:00 
QuestionRemoving Entries from Non-Default Zone PinmemberComplex Cipher19-Feb-10 9:30 
AnswerRe: Removing Entries from Non-Default Zone PinmemberN W Brown19-Feb-10 13:19 
GeneralEnsureSection not being deleted PinmemberMichael Vasquez25-Jan-10 11:30 
GeneralRe: EnsureSection not being deleted PinmemberN W Brown25-Jan-10 14:26 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.1411028.1 | Last Updated 3 Dec 2009
Article Copyright 2009 by N W Brown
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid