SPWebConfigModification does not work on Farms with multiple WFEs

Sometime back a customer came up with an issue. He has written a code in FeatureActivated event handler to add an entry into Web.Config file by using SPWebConfigModification API. The same entry was being removed in FeatureDeactivating event handler.

The code is working perfectly fine in the test machine but failed to add or remove then entry when used in their QA environment. Now this QA environment was having 4 WFE’s and SQL server on different box. Rest of the SharePoint configuration was pretty much the same as test machine. But the test environment was a single machine environment, with everything on a single machine.

The code being tested was:

    1: public void AddEntry
    2: { 
    3:             SPSite siteCollection = new SPSite("http://MOSSServer/");
    4:             SPWebApplication webApp = siteCollection.WebApplication;
    5:             
    6:             string value = @"<role DisplayName='MyWeb Financial Controllers' Role='MyWeb Financial Controllers'/>";
    7:             string strName = "role[@DisplayName='MyWeb Financial Controllers']";
    8:  
    9:             SPWebConfigModification modification = new SPWebConfigModification(strName, "configuration/PortalRole");
   10:  
   11:             modification.Value = value;
   12:             modification.Owner = "ExampleOwner";
   13:             modification.Sequence = 0;
   14:             modification.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
   15:  
   16:             webApp.WebConfigModifications.Add(modification); 
   17:  
   18:             webApp.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications();
   19: }

After trying for sometime and debugging, found that there seems to be an issue with getting to the Farm instance using SPWebApplication object. So instead of using SPWebApplication.Farm, we used SPWebService.ContentService to add the changes and call its ApplyWebConfigModifications method to push the changes to the Web.Config file.

The code was updated to:

    1: public void AddEntry
    2: { 
    3:                 string value = @"<role DisplayName='MyWeb Financial Controllers' Role='MyWeb Financial Controllers'/>";
    4:                 string strName = "role[@DisplayName='MyWeb Financial Controllers']"; 
    5:  
    6:                 SPWebConfigModification modification = new SPWebConfigModification(strName, "configuration/PortalRole");
    7:  
    8:                 modification.Value = value;
    9:                 modification.Owner = "ExampleOwner";
   10:                 modification.Sequence = 0;
   11:                 modification.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
   12:  
   13:                 SPWebService.ContentService.WebConfigModifications.Add(modification);
   14:                 SPWebService.ContentService.Update();
   15:                 SPWebService.ContentService.ApplyWebConfigModifications();
   16: }

Instead of adding modifications to WebConfigModifcations of SPWebApplication object, we are using SPWebService.ContentService to call ADD and UPDATE methods. Whenever required, it is always advised to use SPWebService.ContentService to make the modifications rather than accessing Farm instance through SPWebApplication.

Happy Coding…