Sunday, December 20, 2009

Web.config modifications and copying files to the web application’s physical path

Yes, I know that we have the standard SharePoint SPWebConfigModification class and also the stsadm CopyAppBinContent command. But … the problem is that unfortunately there’re cases when they just can’t do the job the right way causing quite some frustration. When I thought about these problems I came to the conclusion that spending a couple of hours and with some two or three hundred lines of code I could achieve the same thing – and this is the solution that I came up with (maybe one in a row of many already). It’s pretty simple and does both things in one piece of functionality (a feature with a custom feature receiver that is) – it can simultaneously apply changes to the web.config files on all servers in a farm and also can copy files to the physical location of the selected SharePoint web application (not just resource files).

So, let’s get right to it:

<?xml version="1.0" encoding="utf-8"?>

<Feature Id="EA0DD85A-F215-4ffb-893C-7EFFAA09FDFF"

     Version="1.0.0.0"

     Hidden="FALSE"

     Scope="WebApplication"

     Title="Web application config and path settings feature"

     Description=""

     ReceiverAssembly="Stefan.SharePoint, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6ced17f280b33956"

     ReceiverClass="Stefan.SharePoint.FeatureReceivers.WebAppPathReceiver"

     xmlns=http://schemas.microsoft.com/sharepoint/>

  <ElementManifests></ElementManifests>

   <Properties>

    <Property Key="ConfigChangePath" Value="webconfig.xml"/>

    <Property Key="WebAppSourcePath" Value="80"/>

    <Property Key="UrlZone" Value="Default"/>

  </Properties>

</Feature>

This is a sample feature.xml file of the feature that modifies the web.config and copies (actually xcopies) files to the web application’s physical folder. You can see the custom feature receiver class specified in the feature definition – the receiver checks the properties of the feature definition and starts a custom timer job passing the values of these properties to it. It is the custom timer job that runs on all servers in the SharePoint farm that implements the aforementioned functionality.

And here is a short description of the feature’s custom properties:

  • ConfigChangePath – specifies the path (relative to the feature definition path) of the xml file with the changes that should be applied to the web.config of the target web application (I’ll describe its schema in a little while) – the property is optional.
  • WebAppSourcePath - specifies the path (relative to the feature definition path) of a folder whose contents (files and sub-folders) will be copied recursively to the physical folder of the target web application – the property is optional.
  • UrlZone – specifies the URL zone of the target web application – you may need this property only if you have an extended web application. The property is optional and if you don’t specify a value the Default URL zone will be used. You can specify more than one URL zones in the property like Default|Custom|Internet (using the ‘|’ character as separator). Then the web.config modifications and the web application files will be copied to all IIS web sites’ physical folders of the extended web application.

Note that the Scope attribute of the feature is set to WebApplication. This is actually not a requirement and the scope can be set to Site or Web as well – the feature receiver can handle all scenarios.

feature

The image above shows the folder structure and the files of the sample feature. You can see that the 80 sub-folder of the feature folder contains an App_GlobalResources sub-folder with one resource file in it.

And a sample web modification XML file looks like:

<?xml version="1.0" encoding="utf-8" ?>

<ConfigChanges>

  <Namespaces>

    <NamespaceAlias alias="a" url="http://someaddress.com" />

  </Namespaces>

  <ConfigItem ParentElementXPath="/configuration/appSettings" ElementXPath="add[@key='somekey']" CreateOption="Add" >

    <![CDATA[<add key="somekey" value="somevalue1" />]]>

  </ConfigItem>

  <ConfigItem ParentElementXPath="/configuration/appSettings" ElementXPath="add[@key='somekey2']" CreateOption="AddOrReplace" >

    <![CDATA[<add key="somekey2" value="somevalue2" />]]>

  </ConfigItem>

</ConfigChanges>

The web.config modification XML comes with a custom XSD – you can use it in Visual Studio for intelli-sense and validation support and the XSD file should also be deployed to the 12\TEMPLATE\XML folder of the SharePoint installation since the timer job uses it to validate the input XML file.

The elements of the custom web.config modification XML are mostly self-explanatory. You will notice that the modifications that can be applied to the web.config work only on XML elements (not XML attributes) and the parent element of the element(s) to be inserted should exist in the web.config file.

The ParentElementXPath attribute of the ConfigItem element contains the XPath that will be used to locate the parent element of the element that should be added, updated or deleted – as I already mentioned this element should exist in the web.config. The ElementXPath attribute contains the XPath that will be used to locate/identify the element to be created/modified – note here that the XPath for it is relative to the parent element. The third attribute of the ConfigItem element is the CreateOption one – it has three possible values:

  • Add – this will create a new element, if the element already exists it won’t get overwritten
  • AddOrReplace – this will create a new element or overwrite the element if it exists
  • Remove – this will delete the element if it already exists

As you see the functionality provided is pretty basic and simple but as I said before the code is really small and straight-forward and can be quite easily modified or extended.

The custom solution can be downloaded from here.