in

SharePoint Blogs

The Best Place for SharePoint-related Blogs

This Blog

Syndication

News

Mar 17 2008   Commuting this AM I independently ran into 3 ex-colleagues from the same small firm. Now I know Perth isn't big, but that is just too weird & 'paranoidal'. So Chris, Dan and Sean - stop dabbling in Occult over IpEspFi V6 - it's freaking me out!

Feb 20 2008   Aussie day has been and gone and things have been hectic, but I'm now on a course with the irrepressible Clayton James - with many ideas to blog about!

Jan 21 2008   Back again, with the promised info on moving those web pages in code.

Jan 16 2008   I'm away for a few days for a Geraldton funeral (sniff), but back in Perth I'll have something to say about moving pages between webs...

Jan 14 2008   Happy New Year and a Happy New Blog to all - especially MOSS masters Mr P.CleverWorkarounds and Sezai "Yoda"!

Archives


G'Day MOSSuMS

 
View Mike Stringfellow's profile on LinkedIn  
 
 
Join me, Mike Stringfellow, in the upside down world of the baggy green MOSS. I hope you find my rantings useful, as I search out my own path through the challenges and opportunities that "the other MS" throws out.
 

So you think you can change your Web Config?

or 'Making a Feature of SPWebConfigModifications'

Part 1 - A Winner from SharePoint

I know, we've all done it. Jumped into the web config and messed it about for our own evil ends (and we might even have taken a backup first).

Well in the brave new SharePoint world, beyond your 'playpen' dev box, that just ain't allowed!

So what do you do when there's a must have app setting you can't/won't deploy via a WSP solution (please oh please leave your solution to do all the standard things like safe control entries) and you want them to follow wherever your Feature goes?

NB: MrCleverWorkArounds, the Guru of Governance, tells me there may be some issues with what I'm doing here if the feature isn't at WebApplication or Farm scope (as you would expect messing about with web apps configs), so expect a review of this once he's run his strict ruler over it!

Well, there is a little known (it has been news to a couple of SharePoint Gods I occasionally ask silly questions of) part of the object model to help us.

On each web app (Microsoft.SharePoint.Administration.SPWebApplication) there is a property called WebConfigModifications which is a collection of these guys: Microsoft.SharePoint.Administration.SPWebConfigModification

They are just the ticket! You can add and remove modifications to the collection, they don't break if the entry is already in there or isn't there to be removed. If you want to you can even mess with things like debug settings.

spWebApp.WebConfigModifications.Add(configMod1);
spWebApp.WebConfigModifications.Remove(configMod2);
spWebApp.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications();  // propagate across farm
spWebApp.Update();

So the logical next step is to add them in your FeatureActivated and remove them in your FeatureDeactivating SPFeatureReceiver events.

Ah, this is where we hit some small snags:

1. We don't really want to hardcode the updates
2. We only want to remove those from our feature, so probably need to remember a SPWebConfigModification.Owner property.
3. The SPWebConfigModification Class seems to rely on us setting xPath strings to do its things.
4. There are some other properties we need to set.

But fear not. I wrote some simple XML serialisable classes for the base entries, app settings, sections and connection strings. That way I can build those classes up, and serialise them to a file in code, to give you a nice guaranteed valid starting structure. Here's an example of the XML that results:

<?xml version="1.0"?>
<
SPwebconfigMods xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
     <
Owner>mrwaUtils.UtilsFeatureReceiver</Owner>
     <
Entries>
          <
Entry xsi:type="AppSettingsAddEntry">
               <
Name>mrwaUtils.Logging.Log+DestinationTypes.EventLog</Name>
               <
Value>MACHINE01</Value>
               <
Xpath>//configuration/appSettings</Xpath>
               <
ModificationType>EnsureChildNode</ModificationType>
               <
Sequence>10</Sequence>
               <
SetValueFromEnvVar>true</SetValueFromEnvVar>
          </
Entry>
     </Entries>
</
SPwebconfigMods>

...and this can be deployed with your Feature as a file, so your receiver can find it.

I'll go through this XML from my class, as it also nicely details the properties for the SPWebConfigModification class that does the real work:

The AppSettingsAddEntry class contains all the entries we need for an app setting (specialised from my base Entry class) with properties, such as the xpath, defaulting to the correct value so we don't have to worry about setting them or making a mistake - you can set them to something else if you want to though.

My containing class SPwebconfigMods class has the owner (this could be the feature GUID, but I've just gone with the Feature's Receiver type). This is the one small difference between my object graph and the SPWebConfigModification class - I only put the owner on the container class, SPwebconfigMods, and all mods will use that. Just remember it actually lives on the SPWebConfigModification class.

Name and Value are my base properties for the simplest NVP Entry style, and match those on the SharePoint class. Where my subclasses have more properties (such as connection strings), at serialise time they are concatenated onto the name/value properties using an override and serialised out/in.

The ModificationType can have 3 values: EnsureChildNode, EnsureAttribute and EnsureSection.

The Sequence determines the order they are applied in, so if you have a section you have to add, ensure it's number is lower than the values it contains. In the above example this class defaults to 10 as it is in the second level of the xpath - if there were sub items I'd set those classes to 20 be default, and the parent to 0 etc.

The SetValueFromEnvVar is one of my own additions, so don't worry about it too much. Suffice to say, this allows me to pick up environment variables, from a batch file of via policies, at actiuvation time. This is an optional way I make releasing the same image accross different enviroments more manageable - the downside is you don't have a record of what was set in the SPwebconfig.xml file. Therefore the results in your web config could be different next time the feature is activated. This is different to actually placing a %SomeEnvVar% ref in the web config, which could then vary every time accessed. My preferece is not to do this, but to read from env vars at file creation time, so they are recorded and fixed after the first install. You pays yer money...

NB2: I've seen a project, I think on codeplex, that allows the management of these updates through a web interface - a very nice idea if you are comfortable with the parameters (more of those later). Obviously add/removing features that change these will mean you loose those interactive changes, so if I get a change I'll see if that project has an export/view facility so we can get them back into our feature (perhaps with some XSLT).  I think Ted Pattison is the originator of that project. The Kid also has a page/solution you can download to edit these interactively from within sharepoint.

So how does this end up looking in my feature receiver? Every time I need web config changes in a feature I inherit from my base class like this:

public class UtilsFeatureReceiver : ConfigSPFeatureReceiver
{
   
    public override SPwebconfigMods SPwebconfigModsFeatureActivatedFileEntries(Guid featureGuid)
    {
        // Optional method used to create SPwebConfigMods if xml file not found
        // Try to get the required setting from environment variables:
        string machineNameKey = "mrwaUtils.Logging.Log+DestinationTypes.EventLog";
        string machineName = Environment.GetEnvironmentVariable(machineNameKey);
        if (machineName == null || machineName.Trim().Length == 0)
        machineName =
Diagnose.GetCurrentMachineName();
        AppSettingsAddEntry cmAsae1 = new AppSettingsAddEntry(machineNameKey, machineName);
        cmAsae1.SetValueFromEnvVar =
true;

        Entry[] entries = new Entry[] { cmAsae1 };
        return new SPwebconfigMods(entries);
    }

    public override void FeatureActivated(SPFeatureReceiverProperties properties)
    {
        base.FeatureActivated(properties, true); // Call required for config update addition if inheriting from ConfigSPFeatureReceiver AND overriding this method

        // Do anything else you want to on Activation here

    }

    public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
    {
        base.FeatureDeactivating(properties); // Call required for config update removal if you inherit from ConfigSPFeatureReceiver AND overriding this method

        // Do anything else you want to on Deactivation here

    }
}

That all for now. In Part 2 I'll look a the makeup of my classes behind this, to better illustrate how to use the SharePoint config modifications yourself.

A quick update on part 2 progress:

Ryan McIntyre has also just blogged about similar things he did with this useful little class in the past, and I've been extending my solution a little also (to read/write the xml files to the feature's dir in the vs project and final 12 hive, and to read environment variables that can be pushed out by policies when the person installing the WSP needs different web.config settings per deploy). He mentions codeplex, so if others feel they might make use of a web config mods project, let us know. We'll try to put our heads together and come up with the best bits.

Comments

 

Links (3/18/2008) « Steve Pietrek’s SharePoint Stuff said:

Pingback from  Links (3/18/2008) &laquo; Steve Pietrek&#8217;s SharePoint Stuff

March 18, 2008 8:54 PM
 

Mirrored Blogs said:

As I was reading through my SharePoint feeds I came across a post that struck a cord with me.&#160; The

March 22, 2008 6:11 PM
 

CleverWorkarounds » "Guru of governance?" said:

Pingback from  CleverWorkarounds &raquo; &quot;Guru of governance?&quot;

April 3, 2008 9:44 AM
 

Ryan McIntyre said:

After my previous post outlining my custom Feature Receiver used to update any section of a web.config

July 21, 2008 11:53 AM

Leave a Comment

(required )  
(optional )
(required )  
Add

About MikeS

I'm a freelance consultant with over 15 years in the IT industry, currently specialising in .net and MOSS projects in Perth, Western Australia.

Need SharePoint Training? Attend a SharePoint Bootcamp!

Posts (c) their respective authors. Everything else (c) 2007 SharePoint Experts