SharePoint provides a API that allows developers to modify web.config on all web front-end servers at the same time. This is really a nice concept as soon as it is used the correct way. All web.config modifications should (I could stay must) be performed through the API. Any direct change to web.config files can result in changes lost as this API will override entries in the config file.
Like for all classes and APIs, developers should have a look to documentation to be able to use the API without bringing any mistakes in their code. Unfortunately, this API is poorly documented. The best documentation is coming from blog posts. There is a lot of posts all over the Internet but you have to read a lot of them if you want a global overview of use of this API. So have a look to this simple feature.
SPWebConfigModification usual members
First of all, a web config modification is described with a name, an owner name, an xpath value to define location of the change and a value.
So if you want to add an entry in the web.config file, you have to know how we can define a unique identifier for the entry. As an example, you want to add <action param1=’value1’ param2=’value2’ param3=’value3’ /> and you know that only param3 should be changed, you have to define Name parameter to action [@param1=’value1’] [@param2=’value2’]. This part is the most obscure part of the SPWebConfigModification class and it is really important to understand why you have to use a correct name so let’s have the explanation: When applying modifications, API will read the web.config file and look for a entry with identifier. If it find such an entry, SPWebConfigModification will replace the current value. If not, it will add an new entry. So, if Name doesn’t fit with config entry, you will have duplicate value in the API.
Owner property is also really useful. We will use it to know which entries we have to delete when deactivating the feature.
Feature sample
In this feature, we will add two entries in the web.config file and remove them when deactivating the feature.If you don’t know how to create a feature, please refer to MSDN Documentation.
Feature.xml
<?xml version="1.0" encoding="utf-8"?>
<Feature Id="1625EAF0-F3EB-4c4a-AB8A-36FDBD878AE8"
Title="Company_FeatureName"
Description="Used to add some entries in the web.config"
Version="12.0.0.0"
Hidden="FALSE"
Scope="WebApplication"
DefaultResourceFile="core"
ReceiverAssembly="Company.FeatureName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0a1bc23456d78ef9"
ReceiverClass="Company.FeatureName.WebConfigModificatorFeatureReceiver"
xmlns="http://schemas.microsoft.com/sharepoint/">
<ElementManifests />
</Feature>
Feature receiver
class WebConfigModificatorFeatureReceiver : SPFeatureReceiver
{
private const string SPWebConfigModificationOwner = "OwnerName";
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
string name, xpath, value;
SPWebApplication webApp = (SPWebApplication)properties.Feature.Parent;
#region ..: appSettings :..
name = "add[@key='TrustedGroup']";
xpath = "configuration/appSettings";
value = "<add key='TrustedGroup' value='Trusted' />";
ModifyWebConfig(webApp, name, xpath, value, SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode);
name = "add[@key='KeyName']";
xpath = "configuration/appSettings";
value = "<add key='KeyName' value='Value' />";
ModifyWebConfig(webApp, name, xpath, value, SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode);
#endregion
try
{
webApp.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications();
}
catch (Exception ex)
{
RemoveAllModifications(properties);
throw ex;
}
}
public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
RemoveAllModifications(properties);
try
{
SPWebApplication webApp = (SPWebApplication)properties.Feature.Parent;
webApp.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications();
}
catch (Exception ex)
{
System.Diagnostics.EventLog eventLog = new System.Diagnostics.EventLog();
eventLog.Source = SPWebConfigModificationOwner;
eventLog.WriteEntry(ex.Message);
throw ex;
}
}
private void RemoveAllModifications(SPFeatureReceiverProperties properties)
{
SPWebApplication webApp = (SPWebApplication)properties.Feature.Parent;
List<SPWebConfigModification> modificationsToRemove = new List<SPWebConfigModification>();
foreach (SPWebConfigModification modification in webApp.WebConfigModifications)
if (modification.Owner == SPWebConfigModificationOwner)
modificationsToRemove.Add(modification);
foreach (SPWebConfigModification modification in modificationsToRemove)
webApp.WebConfigModifications.Remove(modification);
webApp.Update();
}
private void ModifyWebConfig(SPWebApplication webApp, String nameModif, String pathModif, String valueModif, SPWebConfigModification.SPWebConfigModificationType typeModif)
{
SPWebConfigModification modification = new SPWebConfigModification(nameModif, pathModif);
modification.Value = valueModif;
modification.Sequence = 0;
modification.Type = typeModif;
modification.Owner = SPWebConfigModificationOwner;
try
{
webApp.WebConfigModifications.Add(modification);
webApp.Update();
}
catch (Exception ex)
{
System.Diagnostics.EventLog eventLog = new System.Diagnostics.EventLog();
eventLog.Source = SPWebConfigModificationOwner;
eventLog.WriteEntry(ex.Message);
throw ex;
}
}
public override void FeatureInstalled(SPFeatureReceiverProperties properties) { }
public override void FeatureUninstalling(SPFeatureReceiverProperties properties) { }
}
Catching exception during ApplyWebConfigModifications
If you run two ApplyWebConfigModifications simultaneously, an exception will be thrown during the second operation and modifications are not sent (I know, I said simultaneously, I should say if you execute a ApplyWeConfigModifications before the end of another ApplyWebConfigModifications). Unfortunately, modifications are already in the modifications list but not applied in the web.config files and we will add them again during the next feature activation. Because of this, we will remove all the modifications ourselves before throwing the exception to caller.
Scope of modifications
What about the scope? Web config modifications can be applied by web application. To be more precise, this is a web application and all its extensions. It is not possible to apply modifications to a extended web application without applying these modifications to all the extensions.
Entries conflicts
Unfortunately, SharePoint doesn’t provide a solution for web.config conflict values (when two applications added the same entry) so when deactivating one of the feature, entry is removed and the second application may not work correctly.
Entries modifications through UI
Last but not least, if you want to modify a value without executing any code, you will have to use a page that is able to manage all the entries. You can find such a page here: http://blog.thekid.me.uk/archive/2007/03/24/web-config-modification-manager-for-sharepoint.aspx
Hope this post will help!