SharePoint, Features and web.config modifications using SPWebConfigModification

SharePoint has a great way for deploying content and functionality using Windows SharePoint Services Solution Packages (WSP's). While developing a powerful new feature for SharePoint Publishing sites I had to deploy a HttpModule "the SharePoint" way. Building a HttpModule , a corresponding feature and the resulting WSP package is easy with our Macaw Solutions Factory. The actual logic in the Http Module and the feature is the difficult part. One of the things I had to do was to create a feature that registers a HTTPModule on feature activation, and removes it from the web.config on the feature deactivation. You can do this using the SPWebConfigModification class.

A good article on this topic is http://www.crsw.com/mark/Lists/Posts/Post.aspx?ID=32. It contains links to other posts as well.

The Microsoft documentation can be found at SPWebConfigModification Class (Microsoft.SharePoint.Administration), I wished I scrolled down before, because a lot of valuable information can be found in the Community Content of this page (keep scrolling!).

Anyway, it took quite some time to get my HttpModule to register/unregister correctly on activation/deactivation of my web application level feature. I post the code below so you have a head-start if you have to do something similar yourself.

 

using System.Collections.Generic;
using System.Collections.ObjectModel;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;

// namespace must be in the form <Company>.<Product>.<FunctionalArea>.SharePoint.Features.<FeatureName>.FeatureReceiver
namespace Macaw.WcmRia.Moss2007.DualLayout.SharePoint.Features.DualLayoutSupport.FeatureReceiver
{
    /// <summary>
    /// Add HttpModule registration to web.config of the web application
    /// </summary>
    class DualLayoutSupportFeatureReceiver : SPFeatureReceiver
    {
        private const string WebConfigModificationOwner = "Macaw.WcmRia.Moss2007.DualLayout";
        private static readonly SPWebConfigModification[] Modifications = {
            // For not so obvious reasons web.config modifications inside collections 
            // are added based on the value of the key attribute in alphabetic order.
            // Because we need to add the DualLayout module after the 
            // PublishingHttpModule, we prefix the name with 'Q-'.
            new SPWebConfigModification()
                { 
                    // The owner of the web.config modification, useful for removing a 
                    // group of modifications
                    Owner = WebConfigModificationOwner, 
                    // Make sure that the name is a unique XPath selector for the element 
                    // we are adding. This name is used for removing the element
                    Name = "add[@name='Q-Macaw.WcmRia.Moss2007.DualLayout']",
                    // We are going to add a new XML node to web.config
                    Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode, 
                    // The XPath to the location of the parent node in web.config
                    Path = "configuration/system.web/httpModules",
                    // Sequence is important if there are multiple equal nodes that 
                    // can't be identified with an XPath expression
                    Sequence = 0,
                    // The XML to insert as child node, make sure that used names match the Name selector
                    Value = "<add name='Q-Macaw.WcmRia.Moss2007.DualLayout' type='Macaw.WcmRia.Moss2007.DualLayout.Business.Components.HttpModule, Macaw.WcmRia.Moss2007.DualLayout.Business.Components, Version=1.0.0.0, Culture=neutral, PublicKeyToken=077f92bbf864a536' />" 
                }
        };

        public override void FeatureInstalled(SPFeatureReceiverProperties properties)
        {
        }

        public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
        {
        }

        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            SPWebApplication webApp = properties.Feature.Parent as SPWebApplication;
            if (webApp != null)
            {
                AddWebConfigModifications(webApp, Modifications);
            }
        }

        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        {
            SPWebApplication webApp = properties.Feature.Parent as SPWebApplication;
            if (webApp != null)
            {
                RemoveWebConfigModificationsByOwner(webApp, WebConfigModificationOwner);
            }
        }

        /// <summary>
        /// Add a collection of web modifications to the web application
        /// </summary>
        /// <param name="webApp">The web application to add the modifications to</param>
        /// <param name="modifications">The collection of modifications</param>
        private void AddWebConfigModifications(SPWebApplication webApp, IEnumerable<SPWebConfigModification> modifications)
        {
            foreach (SPWebConfigModification modification in modifications)
            {
                webApp.WebConfigModifications.Add(modification);
            }

            // Commit modification additions to the specified web application
            webApp.Update();
            // Push modifications through the farm
            webApp.WebService.ApplyWebConfigModifications();
        }

        /// <summary>
        /// Remove modifications from the web application
        /// </summary>
        /// <param name="webApp">The web application to remove the modifications from</param>
        /// <param name="owner"Remove all modifications that belong to the owner></param>
        private void RemoveWebConfigModificationsByOwner(SPWebApplication webApp, string owner)
        {
            Collection<SPWebConfigModification> modificationCollection = webApp.WebConfigModifications;
            Collection<SPWebConfigModification> removeCollection = new Collection<SPWebConfigModification>();

            int count = modificationCollection.Count;
            for (int i = 0; i < count; i++)
            {
                SPWebConfigModification modification = modificationCollection[i];
                if (modification.Owner == owner)
                {
                    // collect modifications to delete
                    removeCollection.Add(modification);
                }
            }

            // now delete the modifications from the web application
            if (removeCollection.Count > 0)
            {
                foreach (SPWebConfigModification modificationItem in removeCollection)
                {
                    webApp.WebConfigModifications.Remove(modificationItem);
                }

                // Commit modification removals to the specified web application
                webApp.Update();
                // Push modifications through the farm
                webApp.WebService.ApplyWebConfigModifications();
            }
        }
    }
}
Published Friday, June 19, 2009 12:47 AM by svdoever
Filed under:

Comments

Friday, June 19, 2009 4:56 AM by webbes

# re: SharePoint, Features and web.config modifications using SPWebConfigModification

Good one. You can find an abstract base class for applying web config modifications over here:

weblogs.asp.net/.../web.config-modifications-with-a-sharepoint-feature.aspx

You'll also find some examples of web config modification features. f.e. a debug switch.

Cheers,

Wes

Friday, June 19, 2009 5:01 AM by Mark van Dijk

# re: SharePoint, Features and web.config modifications using SPWebConfigModification

Nice post Serge, I stored it in my del.icio.us collection.

Friday, June 19, 2009 12:41 PM by Sandeep

# re: SharePoint, Features and web.config modifications using SPWebConfigModification

Trust me , this will only work on your own VM.. never on Production..

Tuesday, June 23, 2009 8:08 AM by Mark Stokes

# re: SharePoint, Features and web.config modifications using SPWebConfigModification

Sandeep, can you give more information on why this will not work in a production environment?

I am currently implementing this and it would help if you said why it won't work in prod so that I can change whatever needs to be changed to ensure it does work.

Wednesday, June 24, 2009 9:29 PM by Mike Knowles

# re: SharePoint, Features and web.config modifications using SPWebConfigModification

Exactly what I needed. Thanks for the article.

Friday, June 26, 2009 6:46 AM by Sander de Koning

# re: SharePoint, Features and web.config modifications using SPWebConfigModification

Hi Serge,

there are some issues with calling: webApp.WebService.ApplyWebConfigModifications();

I don't know if you've tested this in a farm environment, but I never got it to work..

This is the alternative I'm using:

webApp.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications();

See ya!

Sander

Tuesday, July 07, 2009 2:54 AM by William van Strien

# re: SharePoint, Features and web.config modifications using SPWebConfigModification

I've successfully applied the SPWebConfigModifcation functionality in several projects, both for rolling out new or updated versions in local VM, and when rolling out to test, staging and production servers - within a farm setup. The infra setups are various: pure intranet with multiple WFEs, a web app extended in extra zone to internet, web app extended for intra- and extranet. Overall, good and repetive consequent results, both upon adding as removal/retraction.

I did apply a variant of the call to apply the modifications:

SPFarm.Local.Services.GetValue<SPWebService>().ApplyWebConfigModifications();

Leave a Comment

(required) 
(required) 
(optional)
(required)