2

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?

3 Answers 3

2

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();  
1

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."

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

0

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();  
    }
.
.
.
}
1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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