MOSS Web.Config Modification – Beware the XPath

Today I finally got around to diagnosing an interesting and simple (but critical) problem with web.config settings. Here's the scenario:

Every time web.config modifications are done, multiple entries get added to the web.config file. In this case, to retrieve data from a web service, the MOSS farm uses a <proxy> entry to specify the outbound proxy server for the application.

However, every time SPWeb.ApplyWebConfigModifications() was called, an additional <proxy> entry is added to the web.config file. You can't have more than one proxy entry, and therefore causes these components (or the entire requests) to fail because of an invalid web.config.

(For more information about Web.Config Modifications in MOSS - http://sharepointsolutions.blogspot.com/2006/12/using-spwebconfigmodificat_116736917110571614.html)

Well, the MOSS web.config modification entries looked something like this:

Owner: ProxySettings
Name: proxy[@autoDetect='true']
Value: <proxy proxyaddress="http://someproxy:8080" />

The problem lies in the fact that MOSS does not do any validation to make sure that the value you're putting in matches the name's XML Xpath. So, MOSS says "OK, got a new modification for me? Alright... I'll put it in. No problem." and it works fine.

The next time SPWeb.ApplyWebConfigModifications() is called, MOSS does the following:

  1. Looks at the existing web.config file, and makes an XML DOM inventory of what is already in it.
  2. Enumerates through the Web.Config Modifications (which, by the way, are persistently stored in the SharepointConfig database) that should be applied.
  3. Gets to this proxy modification entry, and tries to match the name - proxy[@autoDetect='true'] - which in XML-ese is slang for: "Let me see if I already have a tag (element) that starts with <proxy and has an attribute in it of autoDetect='true'.

    So, if our modification value looked like this: <proxy autoDetect='true' /> then MOSS would have found this entry and not added a new one. The problem is, our value has no autoDetect='true' attribute inside it, so every time MOSS tries to match the value, it never will match.

  4. Match fails, so MOSS assumes that the entry doesn't exist yet, and adds another one.
  5. MOSS site goes down in flames due to multiple proxy entries, users scream, riots happen, etc.

Really, the setting should have looked like this:

Owner: ProxySettings
Name: proxy
Value: <proxy proxyaddress="http://someproxy:8080" />

That way, any element/tag starting with <proxy... would be matched and correctly handled.

Unfortunately, even before or after this is corrected, there is one more important thing: The original never matched, so it's now orphaned and MOSS will not remove it. Once the web.config modifications are removed from the persisted MOSS object model, the entries are still there in the web.config. The proper way to do this is as follows:

  1. Delete the SPWebConfigModification entry in the object model.
  2. Apply web config modification settings with SPWeb.ApplyWebConfigModifications().
  3. Manually remove all entries (in this case, all entries starting with <proxy...) from the web.config file and save.
  4. Add the correct SPWebConfigModification entry and apply modifications again.

Now, the web.config modifications should be matched by MOSS.