Monday, February 23, 2009

Adding Web Config Entries using WSPBuilder

I'm using WSPBuilder to package Web Parts for Sharepoint. It really does make things easier in deploying stuff to Sharepoint. The big challenge using this tool is how to do things that should be rather simple, or at least are in outside of the Sharepoint Framework.

Recently, I had need to modify the web.config for a Sharepoint instance I'm working with. I found lots of information about adding items to the AppSettings section of a web config. I didn't find anything about adding new custom sections to the web.config. I also didn't find anything with the WSPBuilder (including the documentation) that indicated how to make those changes to the config when using a WebPartWithFeature project type. This is a bummer.

The first thing to figure out was to how to add a feature receiver type into the part and "wire it up" to the web part I had created. I noticed two parameters within the Feature.xml file:

ReceiverAssembly=""
ReceiverClass=""


This means that I just needed to create a Folder named FeatureCode and then a class under it that corresponded to the values in these parameters. I also needed to add those parameters to the Feature.xml file so the underlying feature stuff on the server knows there's something it needs to do when activating or installing the feature. This made it easier... once I figured out I needed to inherit from the SPFeatureReceiver base class for my Feature Reciever class. This also gave methods to handle activation, deactivation, installation and removal. Now I had a way to tie the configuration changes to the feature's events. Sweetness!

Then came the idea of how to add the modification changes to the web config. I know how to add the stuff to the AppSettings:

Modifications.Add(
new ModificationEntry(
"MyWebPart" //Owner of the Modification
, "configuration/appSettings" //where to make the modification
, "add[@key=\"ServiceNameSpace\"]" //identifying name of the modification
, "" //The value of the modification
, 0 //the sequence of the modification
, ModificationType //the type of modification (add, update, delete)
, SectionNode.Node)); //are we working with an attribute, node or section?


The trick was learning how to add in a new section. After lots (we're talking 24 man hours, not business hours) and lots of trial and error, this is what I discovered:
Modifications.Add(
new ModificationEntry(
"MyWebPart"
, "configuration"
, "CssFiles[@name='jQueryStyles']"
, ""
, 0
, ModificationType
, SectionNode.Node));

and an entry under those sections by the same trial and error method:
Modifications.Add(
new ModificationEntry(
"MyWebPart"
, "configuration/CssFiles[@name='jQueryStyles']"
, "CssFile[@Path='/_layouts/MyWebPart/styles/' and @FileName='jquery.treeview.css' and @Type='text/css']"
, ""
, 0
, ModificationType
, SectionNode.Node));


The short summary is that it all comes down to XPath for the name. In adding a new section, we need to tell the SPWebConfig that we are adding a node, that our new node will have an attribute of name and we are passing it the value of the name.

For the details, let's break this down to the important stuff:

"configuration" is the node we want to work with. So if we wanted to add a new element to the appSettings section of the config, we would pass it "configuration/appSettings" meaning that we want to work with the appSettings child node of the configuration node tree.

"CssFiles[@name='jQueryStyles']" is the node we want to add. Take note of the [@name='jQueryStyles'] snippet. This tells the SPWebConfig that we want to add a node with an attribute of name and the value of the new attribute.

""
is the literal value of the node we want to add. We are describing to the SPWebConfig what the node actually looks like.

The other elements are specific to what I am trying to do...I have a struct that looks like the following:
internal struct ModificationEntry
{
public string Owner;
public string XPath;
public string ModificationName;
public string ModificationValue;
public int ModificationSequence;
public EntryType ModificationType;
public SectionNode SectionOrNode;

//parameterized constructor
public ModificationEntry(
string Owner
, string XPath
, string ModificationName
, string ModificationValue
, int ModificationSequence
, EntryType ModificationType
, SectionNode SectionOrNode)
{
this.Owner = Owner;
this.XPath = XPath;
this.ModificationName = ModificationName;
this.ModificationValue = ModificationValue;
this.ModificationSequence = ModificationSequence;
this.ModificationType = ModificationType;
this.SectionOrNode = SectionOrNode;
}

}


This enables me to create a generic list of Entry Objects...
List Modifications = new List();
which I can iterate through to get all the modifications I added.

This is just a first, rough outline of an article, but will be updated and posted when I get a free moment. The Secret Ninja Code Monkeys are on fire for me to get other stuff done.

J.

2 comments:

Mike D said...

Just wondering if you had any issues with seeing duplicate values in your web.config once the modifications are applied?

The problems I'm having is that I enter in AJAX modifications to the web.config using a feature receiver, but duplicate values get re-entered if SharePoint modifies the web.config again (or if the another feature that modifies the web.config activates).

It doesn't make the application crash since the duplicate values are allowed in those places, but it's just annoying.

MecurioJ said...

I haven't found a solution yet, but it's on the list of things to figure out.