Wednesday, January 7, 2009

Making SharePoint's web.config changes manageable

Scenario:
Making Web.config is pain in the back ( always ). But every deployment need some sort of AppSettings to be stored in Web.Config.

Solution:
I wrote a small feature to handle this, while discussion the same with Sahil over appSetting manageability.

Code ( Feature Receiver ) :

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

namespace MyClient
{
class WebConfigModifierFeature : SPFeatureReceiver
{
public override void FeatureInstalled(SPFeatureReceiverProperties properties) { }
public override void FeatureUninstalling(SPFeatureReceiverProperties properties) { }

public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
SPWebApplication application = (SPWebApplication)properties.Feature.Parent;

foreach (ModificationEntry entry in this.SectionEntries)
{
application.WebConfigModifications.Add(this.CreateModification(entry.Name, entry.XPath, entry.Value, SPWebConfigModification.SPWebConfigModificationType.EnsureSection ));
}
foreach (ModificationEntry entry2 in this.ChildNodeEntries)
{
application.WebConfigModifications.Add(this.CreateModification(entry2.Name, entry2.XPath, entry2.Value, SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode));
}
foreach (ModificationEntry entry3 in this.AttributeEntries)
{
application.WebConfigModifications.Add(this.CreateModification(entry3.Name, entry3.XPath, entry3.Value, SPWebConfigModification.SPWebConfigModificationType.EnsureAttribute));
}
application.WebService.ApplyWebConfigModifications();
}

public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
SPWebApplication application = (SPWebApplication)properties.Feature.Parent;

foreach (ModificationEntry entry in this.AttributeEntries)
{
application.WebConfigModifications.Remove(this.CreateModification(entry.Name, entry.XPath, entry.Value, SPWebConfigModification.SPWebConfigModificationType.EnsureAttribute ));
}
foreach (ModificationEntry entry2 in this.ChildNodeEntries)
{
application.WebConfigModifications.Remove(this.CreateModification(entry2.Name, entry2.XPath, entry2.Value, SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode));
}
application.WebService.ApplyWebConfigModifications();

}

private struct ModificationEntry
{
public string Name;
public string XPath;
public string Value;

// parameterized contructor
public ModificationEntry( string Name, string XPath, string Value )
{
// intialize structure instances
this.Name = Name;
this.XPath = XPath;
this.Value = Value;
}
}

private ModificationEntry[] AttributeEntries = new ModificationEntry[] {
new ModificationEntry("file", @"configuration/appSettings", "appSettings.config")};
private ModificationEntry[] SectionEntries = new ModificationEntry[] {
new ModificationEntry("appSettings", "configuration", "appSettings")};

public SPWebConfigModification CreateModification(string Name, string XPath, string Value, SPWebConfigModification.SPWebConfigModificationType Type)
{
SPWebConfigModification modification = new SPWebConfigModification(Name, XPath);
modification.Owner ="MyClient";
modification.Sequence= 0;
modification.Type=Type;
modification.Value= Value;
return modification;
}
}
}


Code ( AppSettings.config ) :
<?xml version="1.0"?>
<appsettings>
<add key="GenericError" value="Error occured : Please contact administrator.">
</appsettings>


Question:
Q : Where will I keep the AppSettings.config ?
A : It shud be next to WebApplication web.config.

Q : Where to put while packaging ?
A : Create a folder with name 80 ( if you are using WSPBuilder ).

Q : I have load balanced farm , will this solutuion gonna work ?
A : 100% , AppSettings is part of the solution and will be automatically replicated on all the front end servers.

Q : Any downside to it ?
A : Big problem , if the same feature is activated more than once on the same web application then one will over-ride the changes of other.



Enjoy :-)

6 comments:

Anonymous,  November 3, 2010 at 10:18 AM  

Nice work.. Is this site collection level or web applicaiton level feature?

Nik Patel November 3, 2010 at 11:00 AM  

Nice work but you are missing the references of the ChildNodeEntries in your code base.

Sandeep November 3, 2010 at 11:06 AM  

Nik , please check line no 23

Sandeep November 3, 2010 at 11:06 AM  

This is going to be a Web Application level feature

Nik Patel November 3, 2010 at 11:26 AM  

Sandeep, you are missing the definition of the ChildNodeEntries. On line 66 and 68, you are defining the AttributeEntries and SectioEntries but not ChildNotEntries..

This code doesn't compile.. On the side note, how easy this to do in VS 2010? How can you map the folder 80?

Sandeep November 3, 2010 at 12:49 PM  

Yup now I see.. will update when i get a chance. My suggestion for this with VS 2010 is to use old pal ... WSP Builder with your own project structure.