This is the first in a series of posts about the SPWebModification class. I’ve been doing a lot of work with this class recently as part of the process of improving solution deployment. As I mentioned in this post on keeping track of SharePoint solutions one of my aims is to keep solution deployment “no touch” as much as possible and one of the big challenges is to handle changes to the web.config file. The SPWebModification class in the SharePoint object model is for making changes to the web.config of a SharePoint web application programatically.
Despite the power of this class the documentation about SPWebModification on MSDN is rather sparse. There are a lot of useful comments against this article which were the starting point for my experiments with the class. You’ll also find comments that (despite the examples showing this on MSDN) you should not use SPWebModification to update the SafeControls entries. SafeControls are added/removed automatically when the WSP is deployed or retracted. SPWebModification connects to the SharePoint configuration database to propagate changes to the web.config automatically around all the SharePoint servers in the farm – even to new servers that are joined to the farm later.
Working with SPWebModification is fairly complex, involving a lot of work with XML elements and string parsing. I wanted to build an object structure to represent and process modifications to the web.config file in a simpler way. Something that would represent a modification in a simple form and that I could re-use and extend every time I needed my projects to make changes to the web.config file, and which hides the detailed interaction with of working with SPWebModification down in the bottom of the inheritance tree . The result is I have a set of classes that provide a friendly wrapper around SPWebModification.
Example Project Introduction
I’ll show how to use these by walking through a SharePoint development project. The idea is to create a SharePoint feature that will set up a proxy server in the web.config of a web application. Why would you want to do that? Well, if you have a proxy server running in an organisation then you’ll find you start to run into problems when you try to use the RSS Viewer web part on your pages. Users will face a similar problem if they try to set up an RSS feed in their MySite. After you configure the web part RSS feed, you save your web part page and after waiting for a while for the RSS web part to update you see an error within the web part, something like this:
An unexpected error occured processing your request. Check the logs for details and correct the problem.
This will happen if you try to connect to an anonmyous RSS feed without setting up the proxy server in the web.config file of the web application(s) – the resolution is to change the web.config to use the proxy server. There are several posts on how to do this manually but then you have the scaling problems – you have to remember to edit the live web.config of the right web applications on every server. Using SharePoint’s SPWebModification infrastructure you can create a feature that will carry out the same update on the web.config files accurately and automatically across all the servers.
The change that needs to be made is to the proxy element in the web.config file which looks like this:
<system.net> <defaultProxy> <proxy autoDetect="True" /> </defaultProxy> </system.net>
In the proxy element, new attributes need to be added for the proxy server address and to tell it to bypass the proxy for local address, and there’s also an attribute to force it not to use the system default proxy server. The end result is a setting something like this:
<system.net> <defaultProxy> <proxy bypassonlocal="True" proxyaddress="http://10.40.50.60:2000" usesystemdefault="False" /> </defaultProxy> </system.net>
What’s happened here is that the proxy element has been modified. So to implement this change I model the proxy element with a class called ProxyConfigModification and add properties for the attributes like bypassonlocal and proxyaddress. This class depends on a set of lower level classes to do its work, but at the top level it becomes a simple 3-step process to effect the changes for the proxy server:
- Create an instance of ProxyConfigModification
- Set the properties: bypassonlocal, proxyaddress and usesystemdefault as appropriate
- Call a couple of methods to write the changes to the web.config files
In the next post I’ll look at the ProxyConfigModification class and the other set of classes that support it. Before that, though, it’s important to understand the basics of how SharePoint manages changes to the web.config file.
How SharePoint uses SPWebModification with web.config
Every web application in SharePoint (represented in the object model by SPWebApplication) has a list of modifications made to its web.config file. Each of those changes is an SPWebModification object. Each modification has an owner property which is a string that identifies what caused the change. Typically if you’re adding a new modification you’ll do it via a feature receiver (I’ll show this later) and the owner will be the GUID of the feature. Each change has a type as well, which varies depending on whether it is adding a whole new section to the web.config, or adding new element (for example, adding a new connection string), or just changing the attributes on an existing version (which is what we’re doing in this project, we’re changing the proxy setting).
When you add a new item to the list of web.config changes, or when you remove an item, it does not immediately cause the web.config file to be updated. That happens only when you write the changes out via a system method that I’ll cover later. SharePoint writes out all the changes to all the web.config files across all the servers.
The idea behind this is that within a feature activation, you build up the list of all the changes you need, and then when you’re done, you make a call once (and once only) to write those changes out. Updating all the web.config files can take some time so it’s better not to write each change out one by one, but instead queue them up and do them all in one go.