Feb 162007
 

And the SPGeek of the Day award goes to… Tony Bierman, who solves the "why the heck isn’t this working?" question of the day. The answer is in the bottom of this post. I’ll post some more documentation on this very soon, straight out of Inside Windows SharePoint Services 3.0. 


After Tony wrote abou this here, we all got pretty excited about this. Finally, we could use the SPWebApplication class and it’s WebModifications to deploy changes to web.config across the server farm. Combine this with Feature installers and Solution Packages and we had attained no-touch deployment nirvana. But alas, tonight that bubble burst. Unless we missed something. Something obvious. Or– somone just never finished their code.

Why the doom and gloom, you ask? Well– there’s one fatal flaw to the SPWebConfigModification. Again,unless we missed something, the SPWebConfigModification doesn’t remove the configuration change. It provides a way to add the entry, but there is NO WAY to remove the entry. Sucks, doesn’t it? Wel… we have no-touch deployment using this technique. Just NEVER EVER uninstall my application, and you’ll be happy. But try to unintall it and you have a nasty little gremlin that will re-add that entry to web.config when it chooses to, since it thinks that it needs to. And with an extra httpHandler entry to a class that doesn’t exist, and you’ve got a broken web application. Josh likes to call this the Yellow Screen of Death.

So we like WSS Solution Packages. We like WSS Features. We like using SPWebApplication to manage all this. WHY is there such a GREAT feature in the SPWebConfigModification– yet no way to remove it? We’ve gotta be missing something. Internally, the WSS runtime stores this information in the farm configuration database in the Objects table, and uses xml-serialized objects to persist the class. This lets WSS reapply the objects to new web.config files as new sites come online. So without a method to remove it– this sucker is stuck in that database and will be a nasty little bug that will pop back into web.configs whenever it reapplies web config changes. I think this applies to when it manages CAS policies through Solution Package manifests as well. Ouch!!!

Here’s my console application, which can be used as a proof of concept for this. Run the console app once. It will add foo.bar as a handler. Now just try to remove that handler through the console app (using the WSS object model). If you can, I’ll send the first correct answer a copy of my book. And WSS developers everywhere will love you forever. So there’s the challenge, now here’s the code:

using System;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;

class Program {

private const string ScriptResourceHandler =
@"<add verb=""GET,HEAD"" path=""FOO.bar""
type=""System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions""
validate=""false""/>"

static void Main(string[] args) {

SPSite siteCollection = new SPSite("http://localhost");
SPWebApplication webApp = siteCollection.WebApplication;
SPWebConfigModification modification = new SPWebConfigModification();
modification.Path = "configuration/system.web/httpHandlers"
modification.Name = "Example"
modification.Value = value;
modification.Owner = "ExampleOwner"
modification.Sequence = 0;
modification.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
webApp.WebConfigModifications.Add(modification);
// .Remove doesn’t remove it from the web.config, BTW… :(

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


Answer (credit to TB):

Using the following constructor when you create the configuration entry (and not re-setting the name and path….), you can both Add and Remove the config change. (The first param is the Name property, and the second is the Path property.

SPWebConfigModification modification =
new SPWebConfigModification("add[@path='FOO.bar']", "configuration/system.web/httpHandlers");

  7 Responses to “SPWebConfigModification (SPRiddle of the Week)”

  1. Daniel,
     
    I think your contructor is wrong for SPWebConfigModification. 
     
    Try this:
     
    SPWebConfigModification modification = new SPWebConfigModification("add[@path="FOO.bar", "configuration/system.web/httpHandlers");
     
    Then DON’T set the name property manually. 
     
    I think it uses the contructor parameters to build an XPath query for add/remove purposes.
     
    Tony Bierman

  2. oops that first parameter should be @[path='FOO.bar']

  3. I drink Killians, if you’re feeling gracious ;) 

  4. Daniel,
    Tony, thanks for your help! But there are some other issues on this subject.
    Please see my blog post (http://antonzhi.spaces.live.com/blog/cns!76D1A388C70D6997!108.entry)
    – the comment was too long, so I had to post it as a blog entry.

  5. Hi all,
     
    I have run into a bizarre problem that seems similar to this.
     
    If I run the code below, it not only changes the settings on the current website as expected, it also deletes the entries from other websites on the same server.
     
    Any ideas?
     
    // Loop through all keys                foreach (string key in ConfigProcessor.GetAllAppSettingsKeys())                {                    // It will always overwrite, so determine if we are usign new values or old ones                    // According to the following blog article, passign the name and url to the                    // constructor behaves differently than setting the name and path because it                     // cleara out the old mod before adding the new one                    string name = string.Format("add[@key='{0}']", key);                    string path = "configuration/" + _WEBCONFIG_SECTION_APPSETTINGS;
                        SPWebConfigModification mod = new SPWebConfigModification(name, path);                    mod.Owner = webApp.Name;                    mod.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
                        string value = string.Empty;
                        if (appSettings.Settings[key] != null)                    {                        value = appSettings.Settings[key].Value;                    }
                        mod.Value = @"<add key=""" + key + @""" value = """ + value + @""" />";
                        // Add the modification                    webApp.WebConfigModifications.Add(mod);                }
                    // Save the changes                webService.ApplyWebConfigModifications();

  6. I have an update regarding my earlier posting (accidentally posted as anonymous).
     
    The issue regarding multiple sites was due to usign the same owner name for both web sites.
     
    When I changed it to use a combo of featureid and sitename, and then cleared out the old rules, it started working.
     
    I still edits both web,config’s however… it just does not mess them up anymore.
     
    That makes me really nervous so I am not including it our application since blowing up every site on a server would be bad.

  7. welcome to visit RF online blog Mmo blog Mmo guide blog Internet game guideTales of pirates forum ,it will give your some help.EVE online isk cheap EVE isk Guild wars gold Guild wars money GW gold Rs Money Wow gold Wow World of warcraft Gold Wow eu gold Wow us gold Maplestory mesos WOW GOLD worlf of warcrraft  World of warcraft gold Runescape RS gold RF online RF online cp RF online dalant  RF online disena  RF online money RF online gold WOW gold Cheap wow gold on sale.

 Leave a Reply

(required)

(required)

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>