.NET, SharePoint, Technical

Web.Config FeatureReceiver Update

After my previous post outlining my custom Feature Receiver used to update any section of a web.config file, I had some follow up email conversations with Mike about his post and us possibly collaborating on a combined CodePlex solution.  Well, that hasn’t happened yet.  However, during that discussion, we talked a bit about security.  Mike referred me to a post by a colleague of his inspired by this very topic.  The gist of the discussion and post is that modifying the web.config with a Feature Receiver really only makes sense, from a security perspective, when the Feature is scoped at the web level.  I agree, so I needed to make a small change to my custom FeatureReceiver.

The change I needed to make was simply to make sure that it did not update the web.config if the Feature was not deployed at the web scope.  This was a pretty simple change, but I took the opportunity to do a bit more research on the topic to see what others had done.  The best nugget I pulled out of this research time was a change in the way I was applying the updates.  Turns out there is an issue applying an update using

SPFarm.Local.Services.GetValue< SPWebService>().ApplyWebConfigModifications();

Using that method, the changes don’t get applied to the entire farm.  Since we’re in a farm environment, I would’ve run into that at some point.  The solution is to use this instead:

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

Continue to the end of this post for some more reading on the topic.  For now, here is the code update I made:

   1: private void UpdateWebConfig(string XPathLocation, string ElementName,  
   2:     Dictionary<string, string> Attributes, bool removeModification)
   3: {
   4:     try
   5:     {
   6:         SPWebApplication webApp = null;
   7:  
   8:         //Get the web app
   9:         webApp = _properties.Feature.Parent as SPWebApplication;
  10:  
  11:         if (webApp == null)
  12:             throw new SPException("Error obtaining reference to Web application. A feature must " +
  13:                 "be deployed at the WebApplication level to use the WebConfigChanges feature.");
  14:  
  15:         SPWebConfigModification modification =
  16:             new SPWebConfigModification(ElementName + CreateAttributeString(Attributes), XPathLocation);
  17:             //new SPWebConfigModification("authorizedType[@Assembly="Company.Moss.Activities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9eed2245513232a4"][@Namespace="Company.Moss.Activities"][@TypeName="*"][@Authorized="True"]", "configuration/System.Workflow.ComponentModel.WorkflowCompiler/authorizedTypes");
  18:  
  19:         modification.Owner = "Company.Moss.FeatureReceiver.FDFeatureReceiver";
  20:         modification.Sequence = 0;
  21:         modification.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
  22:         modification.Value =
  23:              string.Format(CultureInfo.InvariantCulture,
  24:              CreateModificationValueString(ElementName, Attributes),
  25:              CreateModificationValueArgs(Attributes));
  26:  
  27:         if (removeModification)
  28:             webApp.WebConfigModifications.Remove(modification);
  29:         else
  30:             webApp.WebConfigModifications.Add(modification);
  31:  
  32:         //Changing from SPFarm to webApp as advised by http://www.crsw.com/mark/Lists/Posts/Post.aspx?ID=32
  33:         //SPFarm.Local.Services.GetValue<SPWebService>().ApplyWebConfigModifications();
  34:         webApp.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications();
  35:         webApp.Update();
  36:  
  37:     }
  38:     catch (Exception ex)
  39:     {
  40:         System.Diagnostics.EventLog el = new System.Diagnostics.EventLog();
  41:         el.Source = "WebConfigFeature";
  42:         el.WriteEntry(ex.Message, System.Diagnostics.EventLogEntryType.Error);
  43:     }
  44: }

Like I said, this is going to look a lot like the code in my previous post.  The first change is in the first few lines of the try block.  I assume the parent of the Feature is a Web App.  If it gets a reference, great.  If it doesn’t, it logs an error and doesn’t do anything else.  It would be nice if there were a way to actually stop the Feature from being deployed, but that can’t be done in a Feature Receiver (it happens after the Feature is activated.)

The second change is at the end of that code snippet, and is to account for the Farm update issue I mentioned earlier.

That’s it.  Like I said, not much has changed, but I wanted to put out an update in case others are using this approach.

For further reading, here are some references:

Reza Alirezaei – SPWebModification’s Top 6 Issues

Mark Wagner – How To Modify the web.config File in SharePoint Using SPWebConfigModification

Serge van den Oever – SharePoint Features – elements, scope and other info

(That last one is useful because he lists the types of features that are allowed at each scope.  Can save you some time so you don’t implement this method to deploy something that can’t be deployed at the WebApplication level.)

Leave a Reply

Your email address will not be published. Required fields are marked *