Take the 2-minute tour ×
SharePoint Stack Exchange is a question and answer site for SharePoint enthusiasts. It's 100% free, no registration required.

Using SharePoint 2010 I am trying to use the SPWebConfigModification class to make some basic changes to web.config files on applications in the farm, including the Central Administration web.config file using web application scoped features with feature receivers handling the addition/removal of the modifications:

public override void FeatureActivated(SPFeatureReceiverProperties properties)
    {
        SPWebApplication webApp = properties.Feature.Parent as SPWebApplication;
        String ownerId = properties.Feature.DefinitionId.ToString();
        List<SPWebConfigModification> modsToAdd = new List<SPWebConfigModification>();

        #region Authentication Providers

        modsToAdd.Add(new SPWebConfigModification()
        {
            Name = "defaultProvider",
            Owner = ownerId,
            Path = "configuration/system.web/membership",
            Sequence = 0,
            Type = SPWebConfigModification.SPWebConfigModificationType.EnsureAttribute,
            Value = "FBA_AD_MP"
        });

        modsToAdd.Add(new SPWebConfigModification()
        {
            Name = "add [@name=\"FBA_AD_MP\"] [@type=\"System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\"] [@connectionStringName=\"ADFBAConnectionString\"] [@enableSearchMethods=\"true\"] [@attributeMapUsername=\"userPrincipalName\"]",
            Owner = ownerId,
            Path = "configuration/system.web/membership/providers",
            Sequence = 0,
            Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode,
            Value = "<add name=\"FBA_AD_MP\" type=\"System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\" connectionStringName=\"ADFBAConnectionString\" enableSearchMethods=\"true\" attributeMapUsername=\"userPrincipalName\" />"
        });

        #endregion

        #region Connection Strings

        modsToAdd.Add(new SPWebConfigModification()
        {
            Name = "connectionStrings",
            Owner = ownerId,
            Path = "configuration",
            Sequence = 0,
            Type = SPWebConfigModification.SPWebConfigModificationType.EnsureSection,
            Value = "<connectionStrings />"
        });

        modsToAdd.Add(WebConfigModificationsUtility.CreateConnectionStringModification(ownerId, 1, "ADFBAConnectionString", properties.Feature.Properties["ADFBAConnectionString"].Value));

        #endregion

        WebConfigModificationsUtility.AddWebConfigModifications(webApp, modsToAdd.ToArray());
    }

The WebConfigModificationsUtility class is a simple utility shared by these feature receivers:

public static void AddWebConfigModifications(SPWebApplication webApp, params SPWebConfigModification[] modificationsToAdd)
    {
        AddWebConfigModifications(webApp, true, modificationsToAdd);
    }
public static void AddWebConfigModifications(SPWebApplication webApp, Boolean persistChanges, params SPWebConfigModification[] modificationsToAdd)
    {
        foreach (SPWebConfigModification curMod in modificationsToAdd)
        {
            SPWebService.ContentService.WebApplications[webApp.Id].WebConfigModifications.Add(curMod);                
        }

        if (persistChanges)
        {
            PersistWebConfigModifications(webApp);
        }
    }
public static void PersistWebConfigModifications(SPWebApplication webApp)
    {
        SPWebService.ContentService.WebApplications[webApp.Id].Update();                        
        SPWebService.ContentService.ApplyWebConfigModifications();
    }

Everything is working fine on content applications, but when attempting to activate features on the central admin web application, the SPWebConfigModificaiton items are never written to the web.config files. I have verified that the code is executing without exceptions. Additionally, my feature receiver attempts to remove any modifications is had made on deactivation:

public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        {
            SPWebApplication webApp = properties.Feature.Parent as SPWebApplication;
            String ownerId = properties.Feature.DefinitionId.ToString();
            WebConfigModificationsUtility.RemoveWebConfigModifications(webApp, ownerId);
        }
public static void RemoveWebConfigModifications(SPWebApplication webApp, String ownerId, Boolean persistChanges)
        {            
            RemoveWebConfigModifications(webApp, persistChanges, webApp.WebConfigModifications.Where(x => x.Owner == ownerId).ToArray());
        }
public static void RemoveWebConfigModifications(SPWebApplication webApp, Boolean persistChanges, params SPWebConfigModification[] modificationsToRemove)
        {
            foreach (SPWebConfigModification curMod in modificationsToRemove)
            {
                SPWebService.ContentService.WebApplications[webApp.Id].WebConfigModifications.Remove(curMod);                
            }

            if (persistChanges)
            {
                PersistWebConfigModifications(webApp);
            }
        }

When this code runs on the Central Admin web application it finds the four modifications that were created in the feature activation and successfully removes them, but neither of these operations is actually changing the web.config file of the web application; it is not even touched, the time stamp for last edited date remains the same throughout.

I have found various blogs talking about the inherit trickiness of the SPWebConfigModification class, with most problems being around properly using the Name and Owner properties, as well as properly persisting changes using the SPWebService static properties, but as best I can tell I'm following all recommended practices. I'm beginning to suspect there's a bug in the API, but I'm wondering if anyone has done this in SharePoint 2010 successfully or if I should crack open Reflector and try to see what gives?

share|improve this question

3 Answers 3

I am assuming that the feature is web application scoped.

Are you activating the feature through the browser (central admin)?

Try activating it from powershell/stsadm instead. I have always found that if i try to modify the web.config, from the process that is using the web.config, things seem to go bad.

function New-WebConfigMod {
    param(
        [Parameter(Mandatory=$true, ValueFromPipeline=$true, Position=0)][Microsoft.SharePoint.PowerShell.SPWebApplicationPipeBind]$WebApplication,
        [string]$path,
        [string]$name,
        [string]$owner,
        [string]$value,         
        [Microsoft.SharePoint.Administration.SPWebConfigModification+SPWebConfigModificationType]$type=[Microsoft.SharePoint.Administration.SPWebConfigModification+SPWebConfigModificationType]::EnsureChildNode
    )
    process {       
        $WebApp = $WebApplication.Read()

        $mod = New-Object Microsoft.SharePoint.Administration.SPWebConfigModification 
        $mod.Path = $path;
        $mod.Name = $name;
        $mod.Sequence = 0;
        $mod.Owner = $owner;
        $mod.Type = $type;
        $mod.Value = $value;        
        $WebApp.WebConfigModifications.Add($mod) 
        $WebApp.Update() 
        $WebApp.WebService.ApplyWebConfigModifications();

        $WebApplication
    } 
} 

Get-SPWebApplication -IncludeCentralAdministration |? {
        $_.Url -eq "http://xyz:8080/"
    } | New-WebConfigMod -path "configuration" -name "connectionStrings" -owner "connectionStrings" -value "<connectionStrings></connectionStrings>" | 
        out-null

Or convert that to your feature

webApp.WebConfigModifications.Add(curMod);
webApp.Update();
webApp.WebService.ApplyWebConfigModifications();  
share|improve this answer
up vote 1 down vote accepted

I just got a notification from Stack Overflow that I got a badge for this question based on views, and I didn't even remember asking this question on SPOverflow, because it didn't really exist at the time.

The point is, I also asked this question on SO and got a correct answer there:

"Just like ContentService, SPWebService has an AdministrationService object which also has a WebApplications collection. Use the AdministrationService to get to your CentralAdmin web applications."

http://stackoverflow.com/a/3919161/21418

share|improve this answer

Not really sure but try using this code...

    public static void AddWebConfigModifications(SPWebApplication webApp, Boolean persistChanges, params SPWebConfigModification[] modificationsToAdd)    
    {
    foreach (SPWebConfigModification curMod in modificationsToAdd)
        {          
        webApp.WebConfigModifications.Add(curMod);
        webApp.Update();
        webApp.Farm.Services.GetValue<spwebservice></spwebservice>().ApplyWebConfigModifications();  
    }
.
.
.
}
share|improve this answer
1  
Using the static properties of the SPWebService class is recommended over using the factory methods of the SPFarm class, see msdn.microsoft.com/en-us/library/… and social.msdn.microsoft.com/Forums/en-US/sharepointdevelopment/…. Regardless, I did try changing my Update call on the application and the ApplyWebConfigModifications call to not filter through the SPWebService class without any change in behavior before posting. –  OedipusPrime Oct 5 '10 at 16:18

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.