Click here to Skip to main content
Email Password   helpLost your password?

Introduction

When I started to play with Telerik Rad controls under SharePoint, I realized that massive changes should be made manually to web application's web.config file. Therefore the DeploymentFeature application was created. It presents the SharePoint feature, which applies all needed changes to the web application's web.config file. Moreover it installs needed DLLs to the GAC.

In general, this application can add any modifications to the web.config, by reading them from an external XML file, which has a structure similar to web.config. Moreover, since the modifications are located externally, they can be dynamically changed, without recompiling the application.

Examples of Use

An article SharePoint MVP with Telerik ORM can be considered as a good example of the employment of the application provided here.

Prerequisites

The usage of the solution implies the SharePoint 2007 existence, which means that the target OS is Win2003 or Win2008.

The source code project was created using SPVisualDev, which uses WSPBuilder for deployment. So you should download and install them from CodePlex, or deploy and activate SharePoint feature manually. (Those tools are really helpful for development and deployment of SharePoint projects).

Also, since the Telerik Rad controls were the target, the application implies that controls are installed and look for them at c:\Program Files\Telerik\RadControls for ASPNET AJAX Q1 2009\Bin35\. However it's not a problem if the controls aren't installed or installation path is different, since this information is stored in an external XML file and can be easily changed.

Using the Code

There are two classes in the solution:

FeatureEventReceiver

Look into FeatureActivated method:

public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
	this.ReadDeploymentSettings(properties);

	SPWebApplication webApplication = properties.Feature.Parent as SPWebApplication;

	Installer installer = new Installer()
	{
		WebApplicationId = webApplication.Id,
		Nodes = this.DeploymentNodes,
		DllsToGac = this.DllsToGac
	};

	installer.Deploy(Installer.DeploymentType.Deploy);
}

This method calls ReadDeploymentSettings in order to parse the XML file, which contains all the modifications. (The XML will be discussed right after this section.) The Installer is generated and run in Deploy mode.

The FeatureDeactivating method makes the same things, only run the Installer in UnDeploy mode.

Installer

The main method of Installer is Deploy:

public void Deploy(DeploymentType deploymentType)
{
	this.ModifyWebConfig(deploymentType);

	this.ModifyGac(deploymentType);
}

Look into the ModifyWebConfig method:

private void ModifyWebConfig(DeploymentType deploymentType)
{
	Collection<SPWebConfigModification> webConfigModifications = 
             this.CreateWebConfigModifications();

	SPWebApplication webApplication = 
             SPWebService.ContentService.WebApplications[this.WebApplicationId];

	// Clears the SPWebConfigModification collection,
         // in order to prevent applying of earlier entered modifications.
	webApplication.WebConfigModifications.Clear();

	foreach (SPWebConfigModification 
			webConfigModification in webConfigModifications)
	{
		if(deploymentType == DeploymentType.Deploy)
			webApplication.WebConfigModifications.Add(
                               webConfigModification);
		else
			webApplication.WebConfigModifications.Remove(
                               webConfigModification);
	}

	// Applies all modifications to web.config.
	webApplication.WebService.ApplyWebConfigModifications();
	webApplication.Update();
}

It parses the web.config modifications using CreateWebConfigModifications method, which will be examined right after. When the collection of SPWebConfigModifications is created, all of them are applied, depending on the deployment type. The CreateWebConfigModifications method parses the collection of XML nodes and creates the collection of SPWebConfigModifications for every node.

private Collection<SPWebConfigModification> CreateWebConfigModifications()
{
	Collection<SPWebConfigModification> webConfigModifications =
             new Collection<SPWebConfigModification>();

	foreach (XmlNode node in this.Nodes)
	{
		// Throws out comments.
		if (node.NodeType == XmlNodeType.Comment)
			continue;

		SPWebConfigModification webConfigModification =
                      new SPWebConfigModification();

		webConfigModification.Name = node.Attributes["Name"].Value;
		webConfigModification.Path = node.Attributes["Path"].Value;
		webConfigModification.Sequence = 0;
		webConfigModification.Type =
                      SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
		webConfigModification.Value = node.InnerXml;

		webConfigModifications.Add(webConfigModification);
	}

	return webConfigModifications;
}

Here is the ModifyGac method:

private void ModifyGac(DeploymentType deploymentType)
{
	foreach (string key in this.DllsToGac.Keys)
	{
		string assembly = this.DllsToGac[key] + key;

		Publish p = new Publish();

		if(deploymentType == DeploymentType.Deploy)
			p.GacInstall(assembly);
		else
			p.GacRemove(assembly);
	}
}

Web.Config Modifications

All modifications, which have to be done, can be divided for two independent groups, described by different help articles on the Telerik site.

As it was mentioned earlier, web.config modifications are stored in an external file, which can be found at _layouts\WebConfigModification\DeploymentSettings\RadControlsWebConfigAdds.xml.

Let's look at the beginning of this file:

<WebConfigDeployments>
  <DllToGac Name="Telerik.Web.UI.dll"
     Folder="c:\Program Files\Telerik\RadControls for ASPNET AJAX Q1 2009\Bin35\" />
  <DllToGac Name="Telerik.Web.Design.dll"

     Folder="c:\Program Files\Telerik\RadControls for ASPNET AJAX Q1 2009\Bin35\" />
  <Deployment Name="sectionGroup[@name='system.web.extensions']"
      Path="configuration/configSections" Comment="1">

    <sectionGroup name="system.web.extensions"
          type="System.Web.Configuration.SystemWebExtensionsSectionGroup,
          System.Web.Extensions, Version=3.5.0.0, Culture=neutral,
          PublicKeyToken=31BF3856AD364E35">

      <sectionGroup name="scripting"
           type="System.Web.Configuration.ScriptingSectionGroup,
           System.Web.Extensions, Version=3.5.0.0, Culture=neutral,
           PublicKeyToken=31BF3856AD364E35">

        <section name="scriptResourceHandler"
            type="System.Web.Configuration.ScriptingScriptResourceHandlerSection,
            System.Web.Extensions, Version=3.5.0.0, Culture=neutral,
            PublicKeyToken=31BF3856AD364E35" requirePermission="false"
            allowDefinition="MachineToApplication"/>
        <sectionGroup name="webServices"

            type="System.Web.Configuration.ScriptingWebServicesSectionGroup,
            System.Web.Extensions, Version=3.5.0.0, Culture=neutral,
            PublicKeyToken=31BF3856AD364E35">
          <section name="jsonSerialization"
              type="System.Web.Configuration.ScriptingJsonSerializationSection,
              System.Web.Extensions, Version=3.5.0.0, Culture=neutral,
              PublicKeyToken=31BF3856AD364E35" requirePermission="false"
              allowDefinition="Everywhere" />

          <section name="profileService"
              type="System.Web.Configuration.ScriptingProfileServiceSection,
              System.Web.Extensions, Version=3.5.0.0, Culture=neutral,
              PublicKeyToken=31BF3856AD364E35" requirePermission="false"
              allowDefinition="MachineToApplication" />

          <section name="authenticationService"
              type="System.Web.Configuration.ScriptingAuthenticationServiceSection,
              System.Web.Extensions, Version=3.5.0.0, Culture=neutral,
              PublicKeyToken=31BF3856AD364E35" requirePermission="false"
              allowDefinition="MachineToApplication" />

          <section name="roleService"
              type="System.Web.Configuration.ScriptingRoleServiceSection,
              System.Web.Extensions, Version=3.5.0.0, Culture=neutral,
              PublicKeyToken=31BF3856AD364E35" requirePermission="false"
              allowDefinition="MachineToApplication" />

        </sectionGroup>
      </sectionGroup>

    </sectionGroup>   
  </Deployment>

The WebConfigDeployments is the root node. It can contain two types of nodes:

Points of Interest

There were two points, which demanded additional effort from me.

Name Property of SPWebConfigModification

The Name property is not only the unique name of the modification, but according to MSDN also "refers to an XPath expression that uniquely identifies the node under the parent node." It took me some time to realize how to specify them, in each particular case. And one of them demanded special care.

dependentAssembly Tag of web.config

The dependentAssembly tag of web.config requires a special format to be proceeded.

  <Deployment Name="*[local-name()='dependentAssembly'][*/@name=
      'System.Web.Extensions.Design'][*/@publicKeyToken='31bf3856ad364e35']"
      Path="configuration/runtime/*[local-name()='assemblyBinding']" Comment="7.2">

      <dependentAssembly>
      <assemblyIdentity name="System.Web.Extensions.Design"
          publicKeyToken="31bf3856ad364e35"/>
      <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/>

    </dependentAssembly>
  </Deployment>

Pay attention to the format of Name attribute. In many sources, it is said that there is no way to apply it. However, thanks to this blog, the problem was finally resolved.

Usage

After deployment of the application to the SharePoint, you will see the feature under "Central Administration > Application Management > Manage Web Application Features."

DeploymentFeature.GIF

Choose the web application in the upper right corner and activate the feature. See the changes to the web application's web.config file.

History

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralNice
wildcatfan
14:01 21 Jan '10  
Great solution. This helped me tremendously to get AJAX on my site. I also wanted to add the AJAX Control Toolkit (instead of the Telerik control you used) and this worked fine. Two things:

First, in order to get the web.config changes to go out to all web servers in the farm (if you have multiple servers), you need this one extra line of code (the second line is the one you need to add):

webApplication.Update();
webApplication.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications();

In addition, while your code for registering to the GAC worked, I found it did not work for all servers in the farm. While searching for a solution, I found it was easy to do this with WSPbuilder. It's what I use to develop my features anyway. Just add a folder called "GAC" at the same level as the "12" folder. Inside the GAC folder, add another for "Reference" and put your 3rd party DLLs there. Easy! See this link for details: http://keutmann.blogspot.com/2009/08/wspbuilder-extensions-ver-106.html[^]

All in all, a great solution. Good work!
GeneralSharePoint Features it is easy
itsaranga
2:22 29 Sep '09  
Try this,

Very simple way to create sharepoint features
http://sarangasl.blogspot.com/2009/09/in-this-article-im-going-to-describe.html
General[Message Deleted]
itsaranga
4:03 28 Sep '09  

GeneralRe: Simple Solution
Michael Raizman
4:19 28 Sep '09  
Thank you!
GeneralGreat Solution
Wimmo
22:36 21 Sep '09  
Thank you for sharing this, I guess alot of people are going to be happy with this!

Wim Thumbs Up
GeneralRe: Great Solution
Michael Raizman
3:53 22 Sep '09  
Thank you.
GeneralNice Solution
MAHESHSETHI
11:14 26 Aug '09  
Can it be used to deploy any feature/event receiver also, not only RAD controls?
GeneralRe: Nice Solution
Michael Raizman
12:14 26 Aug '09  
MAHESHSETHI thank you for the good words.

I'm not completely sure, that have understood the question.

This application can be easily adopted to any modifications of the web.config. You just need to modify the RadControlsWebConfigAdds.xml file.

Also the application can be used as a sample for writing any SharePoint feature.
GeneralRe: Nice Solution
MAHESHSETHI
4:36 27 Aug '09  
So it is extensible. Great. Thanks.
GeneralRe: Nice Solution
Michael Raizman
5:39 27 Aug '09  
You are welcome!

Please, don't hesitate to ask, if you have more questions or concerns.


Last Updated 21 Sep 2009 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010