I’m not the only one to have run into some massive problems trying to add or remove web.config modifications from my SharePoint web application’s web.config file.

I wrote the following code in my Feature Event Receiver file for a Web Application scoped feature I wrote which, when activated, adds or removes a set of web.config modifications from the web.config.

Here are the “using” statements you’ll need:

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;

And here are the FeatureActivated and FeatureDeactivating methods, along with several helper methods, I used.

public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
  SPWebApplication webApp = properties.Feature.Parent as SPWebApplication;
  try
  {
    RemoveModifications(webApp);
    string owner = @"SHAREPOINT\system";
    webApp.WebConfigModifications.Add(NewWebConfigModification("LDAPRoot", 0, owner, ""));
    webApp.WebConfigModifications.Add(NewWebConfigModification("ErrorEmailToAddress", 1, owner, ""));
   
    //Add more modifications here
    webApp.Update();
    webApp.WebService.ApplyWebConfigModifications();
  }
  catch (Exception ex)
  {    
    throw ex;
  }
}

public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
  SPWebApplication webApp = properties.Feature.Parent as SPWebApplication;

  try
  {
    RemoveModifications(webApp);
    webApp.Update();
    webApp.Farm.Services.GetValue().ApplyWebConfigModifications();
  }
  catch (Exception ex)
  {
    throw ex;
  }
}

private void RemoveModifications(SPWebApplication webApp)
{
  try
  {
    List modsToRemove = new List();
    foreach (SPWebConfigModification mod in webApp.WebConfigModifications)
    {
      if (mod.Owner == @"SHAREPOINT\system")
      {
        modsToRemove.Add(mod);
      }
    }

    if (modsToRemove.Count > 0)
    {
      for (int i = 0; i < modsToRemove.Count; i++)
      {
        webApp.WebConfigModifications.Remove(modsToRemove[i]);
      }
    }
  }
  catch
  {
    throw;
  }
}

private SPWebConfigModification NewWebConfigModification(string keyName, uint sequence, string owner, string value)
{
  try
  {
    SPWebConfigModification webMod = new SPWebConfigModification();
    webMod.Path = "configuration/appSettings";
    webMod.Name = String.Format("add[@key='{0}']", keyName);
    webMod.Sequence = sequence;
    webMod.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
    webMod.Owner = owner;
    webMod.Value = value;
    return webMod;
  }
  catch
  {
    throw;
  }
}

 

Briefly, here’s what the code does:

  • It’s not uncommon for you to try to add a new modification but then some error happens and it doesn’t get flushed out to the web.config file, but it’s still “stuck” in the list of modifications that needs to get made, so the next time you run your code, it’s like SharPoint wants to flush all its entries so you end up getting that entry twice. I basically decided to head that off at the pass by simply removing all modfications right off the bat every time the feature is activated, leaving me with a clean slate. (Note, this approach may not be good in a web app where multiple apps might be writing to the web.config. In this case, I have complete ownership over my app so I know this is the only feature that will ever need to be writing to the web.config.)
  • When the feature is deactivated, all the modifications are removed.
  • This article on MSDN recommended using a new SPWebService.ContentService object to call the ApplyWebConfigModifications method. Strangely enough, this worked in a single-farm setting, but when I went to a load balanced farm, it stopped working. When I changed my code to use SPWebApplication.WebService object instead, it worked. Go figure.

I hope this saves someone else out there a bit of trouble!