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' />" } };
<span style="color: blue">public override void </span>FeatureInstalled(<span style="color: #2b91af">SPFeatureReceiverProperties </span>properties) { } <span style="color: blue">public override void </span>FeatureUninstalling(<span style="color: #2b91af">SPFeatureReceiverProperties </span>properties) { } <span style="color: blue">public override void </span>FeatureActivated(<span style="color: #2b91af">SPFeatureReceiverProperties </span>properties) { <span style="color: #2b91af">SPWebApplication </span>webApp = properties.Feature.Parent <span style="color: blue">as </span><span style="color: #2b91af">SPWebApplication</span>; <span style="color: blue">if </span>(webApp != <span style="color: blue">null</span>) { AddWebConfigModifications(webApp, Modifications); } } <span style="color: blue">public override void </span>FeatureDeactivating(<span style="color: #2b91af">SPFeatureReceiverProperties </span>properties) { <span style="color: #2b91af">SPWebApplication </span>webApp = properties.Feature.Parent <span style="color: blue">as </span><span style="color: #2b91af">SPWebApplication</span>; <span style="color: blue">if </span>(webApp != <span style="color: blue">null</span>) { RemoveWebConfigModificationsByOwner(webApp, WebConfigModificationOwner); } } <span style="color: gray">/// <summary> /// </span><span style="color: green">Add a collection of web modifications to the web application </span><span style="color: gray">/// </summary> /// <param name="webApp"></span><span style="color: green">The web application to add the modifications to</span><span style="color: gray"></param> /// <param name="modifications"></span><span style="color: green">The collection of modifications</span><span style="color: gray"></param> </span><span style="color: blue">private void </span>AddWebConfigModifications(<span style="color: #2b91af">SPWebApplication </span>webApp, <span style="color: #2b91af">IEnumerable</span><<span style="color: #2b91af">SPWebConfigModification</span>> modifications) { <span style="color: blue">foreach </span>(<span style="color: #2b91af">SPWebConfigModification </span>modification <span style="color: blue">in </span>modifications) { webApp.WebConfigModifications.Add(modification); } <span style="color: green">// Commit modification additions to the specified web application </span>webApp.Update(); <span style="color: green">// Push modifications through the farm </span>webApp.WebService.ApplyWebConfigModifications(); } <span style="color: gray">/// <summary> /// </span><span style="color: green">Remove modifications from the web application </span><span style="color: gray">/// </summary> /// <param name="webApp"></span><span style="color: green">The web application to remove the modifications from</span><span style="color: gray"></param> /// <param name="owner"Remove all modifications that belong to the owner></param> </span><span style="color: blue">private void </span>RemoveWebConfigModificationsByOwner(<span style="color: #2b91af">SPWebApplication </span>webApp, <span style="color: blue">string </span>owner) { <span style="color: #2b91af">Collection</span><<span style="color: #2b91af">SPWebConfigModification</span>> modificationCollection = webApp.WebConfigModifications; <span style="color: #2b91af">Collection</span><<span style="color: #2b91af">SPWebConfigModification</span>> removeCollection = <span style="color: blue">new </span><span style="color: #2b91af">Collection</span><<span style="color: #2b91af">SPWebConfigModification</span>>(); <span style="color: blue">int </span>count = modificationCollection.Count; <span style="color: blue">for </span>(<span style="color: blue">int </span>i = 0; i < count; i++) { <span style="color: #2b91af">SPWebConfigModification </span>modification = modificationCollection[i]; <span style="color: blue">if </span>(modification.Owner == owner) { <span style="color: green">// collect modifications to delete </span>removeCollection.Add(modification); } } <span style="color: green">// now delete the modifications from the web application </span><span style="color: blue">if </span>(removeCollection.Count > 0) { <span style="color: blue">foreach </span>(<span style="color: #2b91af">SPWebConfigModification </span>modificationItem <span style="color: blue">in </span>removeCollection) { webApp.WebConfigModifications.Remove(modificationItem); } <span style="color: green">// Commit modification removals to the specified web application </span>webApp.Update(); <span style="color: green">// Push modifications through the farm </span>webApp.WebService.ApplyWebConfigModifications(); } } }
}