I have been pounding my head against a wall for the last few days trying to get a couple of features to activate in my projects new High Availability Environment (HA). The environment consists of two MOSS Web Front Ends (WFE) named web1 and web2. Our env. also includes web3 which runs the Central Admin site, but does not have any of the externally accessible sites (the ones that run on port 80 and 443). This has lead to the following issues.
- Attempt to activate the feature fails when executed from the web app. This issue was easily resolved when I read The Kid’s blog, basically the permissions proposed by Microsoft for the MOSS configuration does not allow this.
- Actual values never appear in the web.config for web1 or web2
- I have a theory about this issue. In our development environment we have two WFEs, but one of them is also running Central Admin. I believe that I need to have the web applications running on the server that is also running Central Admin in order for this to work. As I work through this issue with our system admins I will update my findings.
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
List<SPWebConfigModification> modifications = CreateConfigModification();
SPWebApplication webApp = null;
if (properties.Feature.Parent is SPSite)
{
SPSite spSite = properties.Feature.Parent as SPSite;
webApp = spSite.WebApplication;
}
else if (properties.Feature.Parent is SPWebApplication)
{
webApp = properties.Feature.Parent as SPWebApplication;
}
foreach (SPWebConfigModification mod in modifications)
{
webApp.WebConfigModifications.Add(mod);
}
webApp.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications();
webApp.Update();
}
- To allow a more generic approach to the activation getting the SPWebApplication object is done so we can handle Web Application, Site, etc. feature activation scopes.
- Once we have created the list of SPWebConfigModifications we simply loop through it and apply them to the SPWebApplication object.
- Finally, call the SPWebApplication's Farm Service to Apply the web.config modifications. This causes the changes to setup across the farm. ALWAYS follow this with the SPWebApplication's update function, which essentially causes the modifications to "stick".
public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
List<SPWebConfigModification> modifications = CreateConfigModification();
SPWebApplication webApp = null;
if (properties.Feature.Parent is SPSite)
{
SPSite spSite = properties.Feature.Parent as SPSite;
webApp = spSite.WebApplication;
}
else if (properties.Feature.Parent is SPWebApplication)
{
webApp = properties.Feature.Parent as SPWebApplication;
}
foreach (SPWebConfigModification mod in modifications)
{
webApp.WebConfigModifications.Remove(mod);
}
webApp.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications();
webApp.Update();
}
- To remove the modifications simply cycle through the same list of modifications we used orignally during activation. I like this method because it is very clean and a bit more efficient. However there is a problem with this approach! If you do not name your modification correctly the modification will not be removed. Therefore you may wish to cycle through the SPWebApplication's WebConfigModification list first matching the owner name to this feature's owner name and then cycle though that list removing the modifications as shown below
public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
List<SPWebConfigModification> modifications = new List<SPWebConfigModification>();
SPWebApplication webApp = null;
if (properties.Feature.Parent is SPSite)
{
SPSite spSite = properties.Feature.Parent as SPSite;
webApp = spSite.WebApplication;
}
else if (properties.Feature.Parent is SPWebApplication)
{
webApp = properties.Feature.Parent as SPWebApplication;
}
foreach (SPWebConfigModification mod in webApp.WebConfigModifications)
{
if (mod.Owner.Equals(this.GetType().ToString()))
modifications.Add(mod);
}
foreach (SPWebConfigModification mod in modifications)
{
webApp.WebConfigModifications.Remove(mod);
}
webApp.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications();
webApp.Update();
}
- I usually use the typename as the owner, since the typename's must all be unique this ensures that all of my owners are unique. I have also seen other developers use the Feature ID for the Owner property, that is up to you but make sure your's is always going to be unique if you use this method.