Deployment Using Solution Packages


Because SharePoint solutions are deployed on WSS or MOSS installations that range in size from a single standalone Web server to large enterprise server farms, there needs to be a mechanism to deploy them as a single unit. By deploying a single unit, we can have a supported, testable, and repeatable deployment mechanism. The deployment mechanism that SharePoint uses is the solution package.

Solution packages are critical components for deployment in enterprise or commercial scenarios and use the same Visual Studio project formats that you work with on your development box.

For all deployments outside of your development environment, you want to use WSS solution packages. Solution packages also enable your system administrators to create scriptable installs, an important requirement for many enterprise-class IT organizations.

It is also important to test solution package deployments in a controlled WSS environment (that is not the same as your development environment), such as a clean Virtual PC image, to test installation of the features, site definitions, assemblies, and configuration changes using solution packages. Solution packages are generally language neutral without localized resources, supplemented by solution language packs that contain the language-specific resources. First we’ll look at solution packages and then at adding language-specific resources.

A solution package is a compressed .cab file with a .wsp extension containing the components to be deployed on a target Web server. A solution package also contains additional metadata that enables the WSS runtime to uncompress the .cab file and install its components. In the case of server farm installations, WSS is able to automate pushing the solution package file out to each Web server in the farm.

Solution packages are deployed by using two steps. The first step is installation, in which WSS copies the .wsp file to the configuration database. The second step is the actual deployment, in which WSS creates a timer job that is processed by all front-end Web servers in the server farm. This greatly simplifies the installation across farm servers and ensures a consistent deployment.

The .wsp file for a solution package can be built using the MAKECAB operating system utility by reading the definition from a .ddf file. The .ddf file defines the output structure of the .wsp file by referencing each file in its source location and its destination location in the .wsp file. This is one of the more tedious aspects of WSS development because you will likely need to create and maintain the .dff file by hand.

The metadata for a solution package is maintained in a file named manifest.xml that must be added to the root of the .wsp file. It is the manifest.xml file that tells the WSS runtime which template files to copy into the WSS system directories. The manifest.xml file can also instruct WSS to install features and assembly DLL as well as to add entries to one or more web.config files for SafeControl entries and code access security settings.

Solution Package for Deploying a Feature

To create a solution package for WSS deployment, we will simply create a .wsp file that includes the deployment files, schemas, and assemblies. The initial file that we create will be a Data Description File (DDF) that describes the files for the CAB archive. The DDF file for the LitwareTypes solution is defined in Listing 9-2. We can create the solution files, including the DDF and manifest, in the Solution subfolder of the Visual Studio project. Because the Litware Types feature is explicitly dependent on the LitwareFields project (both the assembly and the .ascx user controls), we can deploy the LitwareFields project as well as the LitwareTypes project in the same solution package.

Listing 9-2: A .ddf file defining the solution structure

image from book
  DDF File for a Solution Package ; ** LitwareTypes.wsp (Pattison/Larson) ** .OPTION EXPLICIT    ; Generate errors .Set CabinetNameTemplate=LitwareTypes.wsp .set DiskDirectoryTemplate=CDROM ; All cabinets go in a single directory .Set CompressionType=MSZIP;** All files are compressed in cabinet files .Set UniqueFiles="ON" .Set Cabinet=on .Set DiskDirectory1=Package Solution\manifest.xml manifest.xml TEMPLATE\FEATURES\LitwareTypes\CustomerList.xml LitwareTypes\CustomerList.xml TEMPLATE\FEATURES\LitwareTypes\feature.xml LitwareTypes\feature.xml TEMPLATE\FEATURES\LitwareTypes\LitwareContentTypes.xml LitwareTypes\   LitwareContentTypes.xml TEMPLATE\FEATURES\LitwareTypes\LitwareCustomFieldSiteColumns.xml LitwareTypes\   LitwareCustomFieldSiteColumns.xml TEMPLATE\FEATURES\LitwareTypes\LitwareSiteColumns.xml LitwareTypes\   LitwareSiteColumns.xml TEMPLATE\FEATURES\LitwareTypes\VendorList.xml LitwareTypes\VendorList.xml TEMPLATE\FEATURES\LitwareTypesDeploymentFeature\feature.xml   LitwareTypesDeploymentFeature\feature.xml TEMPLATE\FEATURES\LitwareTypesDeploymentFeature\Elements.xml   LitwareTypesDeploymentFeature\Elements.xml TEMPLATE\FEATURES\VendorListInstance\feature.xml VendorListInstance\feature.xml TEMPLATE\FEATURES\VendorListInstance\VendorListInstance.xml VendorListInstance\   VendorListInstance.xml TEMPLATE\FEATURES\LitwareTypes\VendorListEventHandlers.xml FEATURES\LitwareTypes\   VendorListEventHandlers.xml TEMPLATE\FEATURES\LitwareTypes\CustomerList\schema.xml FEATURES\LitwareTypes\   CustomerList\schema.xml TEMPLATE\FEATURES\LitwareTypes\VendorList\schema.xml FEATURES\LitwareTypes\   VendorList\schema.xml TEMPLATE\XML\fldtypes_Litware.xml XML\fldtypes_Litware.xml TEMPLATE\CONTROLTEMPLATES\CompanySizeFieldControl.ascx CONTROLTEMPLATES\   CompanySizeFieldControl.ascx bin\Debug\LitwareTypes.dll LitwareTypes.dll bin\Debug\LitwareFieldTypes.dll LitwareFieldTypes.dll ;*** <the end> 
image from book

Unfortunately, the manual process of adding the deployment files to the solution package is somewhat primitive. You must list each file explicitly in the .ddf file, including both the source file and its location in the .wsp package. Also confusing is the fact that the destination directory is not necessarily straightforward and may take some trial and error to get right.

Along with the .ddf file, you must also list each file in the solution manifest inside the Manifest.xml file. The solution manifest is created by using a Solution element and is shown in Listing 9-3. Every file that is to be processed during installation must be listed in the solution manifest. If a file is in the .wsp package but not in the manifest, the file is ignored.

Listing 9-3: Solution package manifest for the Litware Types solution

image from book
  Litware Types Solution Manifest <Solution SolutionId=""     xmlns="http://schemas.microsoft.com/sharepoint/">   <!-- A solution for Litware field types, content types and lists -->   <FeatureManifests>     <FeatureManifest Location="LitwareTypes\feature.xml" />     <FeatureManifest Location="LitwareTypesDeploymentFeature\feature.xml" />     <FeatureManifest Location="VendorListInstance\feature.xml" />   </FeatureManifests>   <TemplateFiles>     <TemplateFile Location="XML\fldtypes_Litware.xml"/>     <TemplateFile Location="CONTROLTEMPLATES\CompanySizeFieldControl.ascx"/>     <TemplateFile Location="FEATURES\LitwareTypes\VendorListEventHandlers.xml"/>     <TemplateFile Location="FEATURES\LitwareTypes\CustomerList\schema.xml"/>     <TemplateFile Location="FEATURES\LitwareTypes\VendorList\schema.xml"/>   </TemplateFiles>   <Assemblies>     <Assembly DeploymentTarget="GlobalAssemblyCache"           Location="LitwareFieldTypes.dll" />     <Assembly DeploymentTarget="GlobalAssemblyCache" Location="LitwareTypes.dll" />   </Assemblies> </Solution> 
image from book

Like WSS features, solution packages also have a GUID that can be generated by using Visual Studio’s Create GUID tool. The main elements to examine are FeatureManifests, TemplateFiles, and Assemblies. These define which features are installed, which template files to copy to the TEMPLATE directory, and which assemblies to install. Assemblies can be installed to either the GAC or to the local bin directory for one or more Web applications and are determined by the DeploymentTarget attribute of the Assembly node.

Feature manifests must be referenced from the feature folder in the FEATURENAME\ Feature.xml format. Note that the FEATURES\FEATURENAME\Feature.xml format is invalid. Directly referenced feature manifests (for example, CustomerList.xml in our source code example, but not schema.xml) are inferred from this location and copied automatically. Files that are not directly referenced from feature manifests (including items such as list schemas) must be explicitly installed by using the TemplateFile elements inside the TemplateFiles node. These files must include the full folder path from TEMPLATE, such as FEATURES\ LitwareTypes\CustomerList\schema.xml. The full manifest for the Litware Types, Litware Types Deployment Feature, and Vendor List Instance features is defined in Listing 9-3.

After creating the solution package .ddf and manifest files, you are ready to create the package. The DOS makecab command creates the .wsp file using the .ddf description:

 makecab /f Solution\cab.ddf

After creating the .wsp file, you can install it by using the addsolution operation of the STSADM.EXE utility. This command causes WSS to copy the .wsp file into the configuration database, but it does not actually deploy it. To deploy the solution package, you can run the deploysolution operation.

 stsadm -o addsolution -filename PACKAGE\LitwareTypes.wsp stsadm -o execadmsvcjobs stsadm -o deploysolution -name LitwareTypes.wsp -immediate -allowGacDeployment -force

When you issue commands to the STSADM.EXE utility to deploy a WSP file, WSS runs these tasks asynchronously by using timer jobs. This makes solution packages a great way to deploy functionality across multiple servers in a server farm. The deploysolution operation of the STSADM.EXE utility can also be parameterized to start a deployment timer job at midnight when nobody’s using the farm. This can be important because WSS issues an IISRESET command on each front-end Web server after it has deployed a solution package.

However, when creating deployment scripts, you might need to call the tasks in a synchronous fashion to deploy the package after adding it. Fortunately, you can use the execadmsvcjobs operation supplied by STSADM.EXE to kick off any scheduled jobs and wait for their completion. Use this command when writing aggregate commands in scripts to manage the installation and removal of solution packages. When you need to remove solution packages from the server farm during development, the following commands can be used:

 stsadm -o retractsolution -name LitwareTypes.wsp -immediate stsadm -o execadmsvcjobs stsadm -o deletesolution -name LitwareTypes.wsp -override stsadm -o execadmsvcjobs

Deploying the solution package installs the features inside, providing you with the equivalent of running the installfeature operation of the STSADM.EXE utility. However, installing a solution package does not activate a feature. Therefore, you must run the activatefeature operation of the STSADM.EXE utility or activate the feature through the standard WSS application pages to perform your testing.

Note that you can also load a solution package to the solution store without deploying it, in which case the solution would be available for deployment through the Central Administration Web site. The Central Administration site includes Solution Management pages that can be accessed from the Solution Management link on the Operations menu. The Solution Management page lists each solution that is installed, as shown in Figure 9-4. By selecting an installed solution, you can deploy a solution, retract a deployed solution, or remove a solution from the solution store. Removing the solution uninstalls it, thereby removing things such as SafeControl entries, GAC assemblies, and TEMPLATE-deployed files.

image from book
Figure 9-4: Once a solution package is installed, you can manage its deployment through the Solution Management pages of the WSS Central Administration site.

Solution Package for Deploying Web Parts

For our first Web Parts solution package, open the LitwareWebParts project. This is the same project that we created in Chapter 4, which includes the Web Part assembly as well as a feature for installing the .webpart files into the Web Part gallery. At the root level of the project, create a Solution folder with a cab.ddf file and a manifest.xml file. The cab.ddf file defines the layout and content of the .wsp file, which is a compressed .cab file containing the deployment files. The WSS runtime uses the timer service and the content database internally to deploy the solution package to all front-end Web servers using the .wsp file. The following code displays the ddf file for the LitwareWebParts.wsp solution package.

  ; ** LitwareWebParts.wsp (Pattison/Larson) ** .OPTION EXPLICIT     ; Generate errors .Set CabinetNameTemplate=LitwareWebParts.wsp .set DiskDirectoryTemplate=CDROM ; All cabinets go in a single directory .Set CompressionType=MSZIP;** All files are compressed in cabinet files .Set UniqueFiles="ON" .Set Cabinet=on .Set DiskDirectory1=Package Solution\manifest.xml manifest.xml TEMPLATE\FEATURES\LitwareWebParts\feature.xml LitwareWebParts\feature.xml TEMPLATE\FEATURES\LitwareWebParts\elements.xml LitwareWebParts\elements.xml TEMPLATE\FEATURES\LitwareWebParts\DWP\HelloWebPart.webpart FEATURES\LitwareWebParts\   DWP\HelloWebPart.webpart TEMPLATE\FEATURES\LitwareWebParts\DWP\RssViewWebPart.webpart FEATURES\LitwareWebParts\   DWP\RssViewWebPart.webpart TEMPLATE\FEATURES\LitwareWebParts\DWP\ContactViewer.webpart FEATURES\LitwareWebParts\   DWP\ContactViewer.webpart TEMPLATE\FEATURES\LitwareWebParts\DWP\UserControlHost.webpart FEATURES\LitwareWebParts\   DWP\UserControlHost.webpart TEMPLATE\CONTROLTEMPLATES\Litware\LitwareUserControl.ascx CONTROLTEMPLATES\Litware\   LitwareUserControl.ascx bin\LitwareWebParts.dll LitwareWebParts.dll ;*** <the end>  

The manifest file in turn specifies the items in the solution for the WSS runtime. It specifies which files to copy to the TEMPLATES directory with the TemplateFiles node, which assemblies to deploy to the GAC, and which SafeControl entries to make.

  <Solution SolutionId=""       xmlns="http://schemas.microsoft.com/sharepoint/">   <FeatureManifests>     <FeatureManifest Location="LitwareWebParts\feature.xml" />   </FeatureManifests>   <TemplateFiles>     <TemplateFile Location="FEATURES\LitwareWebParts\DWP\HelloWebPart.webpart"/>     <TemplateFile Location="FEATURES\LitwareWebParts\DWP\RssViewWebPart.webpart"/>     <TemplateFile Location="FEATURES\LitwareWebParts\DWP\ContactViewer.webpart"/>     <TemplateFile Location="FEATURES\LitwareWebParts\DWP\UserControlHost.webpart"/>     <TemplateFile Location="CONTROLTEMPLATES\Litware\LitwareUserControl.ascx"/>   </TemplateFiles>   <Assemblies>     <Assembly DeploymentTarget="WebApplication" Location="LitwareWebParts.dll">       <SafeControls>         <SafeControl Assembly="LitwareWebParts, [full 4-part assembly name]"                      Namespace="LitwareWebParts" TypeName="*" Safe="True" />       </SafeControls>     </Assembly>  </Assemblies> </Solution> 

To create the solution package by using the .ddf file, call the following from the command prompt or build event:

 makecab /f Solution\cab.ddf

Note that the .ddf file in our example is coded to use the bin assembly, which must be configured as the Visual Studio build directory and built prior to this command.

STSADM.EXE Commands for Deploying Solution Packages

Similar to features, solution packages are deployed by using operations supplied by the STSADM.EXE utility. Before you can deploy the solution, you must install it. Installing the solution makes it available to the WSS server farm by placing it in the content database’s solution store.

While this chapter has already shown you the basic STSADM.EXE operations involved in solution package deployment, we want to discuss a few additional parameterization options that are available to you. The following command installs the solution:

 stsadm -o addsolution -filename package\LitwareWebParts.wsp

After installing the solution, it is available for deployment to any Web application on the server farm. To activate the solution, you must deploy it. The following command deploys the solution package after it is made available through the addsolution command:

 stsadm -o deploysolution -name LitwareWebParts.wsp

There are a number of switches for the deploysolution operation. The important switches to know are allContentUrls, allowGacDeployment, and allowCasPolicies. The allowGacDeployment switch is required where the solution package installs to the GAC, whereas allowCasPolicies is required where the solution package defines and installs custom security policies. The solution will not install at all without the required switches when CAS policies or GAC deployments are specified.

Solution Packages and Code Access Security

For Web Part assemblies (and any assembly running in the WSS Web application), we also want to specify the code access security trust levels that our Web Parts require. Many companies prefer to deploy their Web Part assembly DLLs inside the local bin directory for each Web application instead of using the GAC. This deployment style enables a company to run Web Part code within a sandboxed execution context that restricts what the Web Part code can do. By default, WSS configures the sandbox for Web Part assembly DLLs in the bin directory with a very restrictive trust level in which Web Part code is not allowed to access the hard drive of the local Web server or call into the WSS object model.

When you are creating a solution package for deploying Web Parts, it is a best practice to define the appropriate level of trust. This involves adding code access security configuration data into the solution manifest. If you don’t perform this step, you’ll find that your Web Parts work great on your development box, but fail miserably when deployed to production environments!

In the next chapter, we will discuss code access security in depth. You’ll want to read that section to get a grasp on the importance of code access security in WSS as well as how to configure and secure your code with it. For now, we will focus on the basics of the solution package code access security configuration.

Before you test your final solution package, you want to prepare a clean test deployment environment, preferably with a virtual machine running in Microsoft Virtual PC or Microsoft Virtual Server. The test deployment environment should have either a clean installation of WSS or MOSS, or should have the configuration that most closely matches your target customer’s environment. In most cases, you want to test your deployment both in WSS and in a MOSS installation.

Tip 

Virtual machine environments using Microsoft Virtual PC or Microsoft Virtual Server are our favorite tools for deployment testing. Undo disks in a virtual environment are too costly in performance penalties; therefore, we recommend creating a baseline test environment and backing up the virtual hard drive so that you can quickly restore the clean environment.

In the test deployment environment, make sure that the trust level of the web.config file is set as shipped to WSS_Minimal. Note that this is only for testing the solution deployment package and that it might break other custom Web Parts’ functionality. Also ensure that the Web Part assembly (LitwareWebParts in this example) is not registered as Safe in the SafeControls section of the web.config because we will be setting that through the solution package.

Tip 

To ensure successful deployments and customer installations, make sure to test your solution package against a fresh WSS and MOSS environment (not just your development box)!

To define code access security in the solution package, add the CodeAccessSecurity element to the Solution element in the solution manifest.

 <CodeAccessSecurity>  <PolicyItem>   <PermissionSet  version="1"         Description="Permission set for LitwareWebParts">   </PermissionSet>   <Assemblies>   </Assemblies>  </PolicyItem> </CodeAccessSecurity>

Within the CodeAccessSecurity element, we can define the basic permissions required for our Web Part to run. We’ll discuss advanced permissions in Chapter 10. For now, add the SharePointPermission class that allows our code to access the SharePoint object model. The following element adds the SharePointPermission permission to our assembly:

 <IPermission         version="1" ObjectModel="True" Impersonate="True"        UnsafeSaveOnGet="True" />

To specify the assemblies to which the code access security is applied, you can add nodes to the Assemblies element. You can add assemblies by either their simple name if they are deployed to the Web application or based on their strong name key. Using the simple name deployed by the Web application is preferable because it enables finer control over which assemblies are trusted and because all assemblies based on a common (corporate) public key are not treated the same. To add an assembly based on its simple name in the bin directory, use the following element syntax:

 <Assembly Name="LitwareWebParts" />

Alternatively, you could use an assembly’s public key. This is a bit trickier to obtain because you must use the .NET Framework SDK tool ILDASM to get the BLOB public key out of the assembly manifest. By using the CodeAccessSecurity element, we are defining a policy in which we allow our assembly to execute trusted code elements. At the WSS_Minimal and WSS_Medium trust levels, our assembly is not able to access the SharePoint object model unless we specify the permission defined by Microsoft.SharePoint.Security.SharePointPermission. Also, because the RSS Web Part makes Web requests (see Chapter 4), it would not be able to execute without the System.Net.WebPermission permission (defined in this chapter’s sample code).

To ensure that our RSS Web Part allows access only to trusted locations, we could define more restrictive URL paths in the ConnectAccess node. We could also specify that this trust should apply to all assemblies signed with the Litware private key by choosing to trust the BLOB public key, obtained by loading the assembly’s manifest by using the ILDASM tool. However, specifying fine-grained permissions per assembly is the most secure approach.

Solution Package for Deploying a Site Definition

In addition to Web Parts, the solution package also supports the deployment of site definitions. Site definitions can be much simpler to deploy through the solution package than through features because the required files and assemblies typically are previously deployed in features. To create a solution package for the Litware Marketplace site definition created earlier in the chapter, we will create a .ddf file referencing the ONET file, the WEBTEMP file, and the core resources.

  ;**LitwareMarketplace.wsp ** .OPTIONEXPLICIT    ; Generate errors .SetCabinetNameTemplate=LitwareMarketplace.wsp .setDiskDirectoryTemplate=CDROM ; All cabinets go in a single directory .SetCompressionType=MSZIP;** All files are compressed in cabinet files .SetUniqueFiles="ON" .SetCabinet=on .SetDiskDirectory1=Package Solution\manifest.xmlmanifest.xml TEMPLATE\SiteTemplates\LitwareMarketplace\XML\ONET.XML LitwareMarketplace\XML\ONET.XML TEMPLATE\1033\XML\webtemp.LitwareMarketplace.xml 1033\XML\webtemp.LitwareMarketplace.xml RESOURCES\LitwareMarketplace.resx Resources\LitwareMarketplace.resx ;*** <the end> 

A few additional solution manifest element types that are useful when deploying a site definition have not yet been discussed. First, the SiteDefinitionManifest node defines the location of the site definition. The child WebTempFile node defines the localized WEBTEMP file. You can add several of these elements to deploy to several different localized cultures from within the same solution package. The Location attribute of the site definition Manifest is a folder reference, in which case the XML\ONET.XML file is automatically deployed. Resources for the site definition can be deployed by using the RootFiles element, which defines files that are copied to the 12 folder. In our case, we are copying Resources to the 12\RESOURCES folder.

 <Solution SolutionId=""       xmlns="http://schemas.microsoft.com/sharepoint/">   <!-- A solution for the site definition "Litware Marketplace".     Note: Litware Types is a prerequisite. -->   <SiteDefinitionManifests>     <SiteDefinitionManifest Location="LitwareMarketplace" >       <WebTempFile Location="1033\XML\webtemp.LitwareMarketplace.xml"/>     </SiteDefinitionManifest>   </SiteDefinitionManifests>   <RootFiles>     <RootFile Location="Resources\LitwareMarketplace.resx"/>   </RootFiles> </Solution>

Web Configuration Changes

Certain scenarios exist in which deployment of your solution requires changes to one or more web.config files on the target front-end Web servers. As you have seen, a solution package provides you with an easy way to add SafeControl entries and CodeAccessSecurity entries to properly deploy Web Parts. However, this technique does not extend to other types of entries within the web.config file. This situation makes it necessary to find another approach when you need to modify the contents of web.config to deploy Application Programming Interface (API) components, such as custom HTTP handlers and HTTP module classes.

For example, to deploy the ASP.NET 2.0 AJAX framework to WSS 3.0, you need to add the scriptresource.axd handler to web.config. You might also need to add handler entries for other custom API endpoints, such as the opml.ashx handler from Chapter 5. (Note that you can use file extensions, such as .xml, for handlers in WSS 3.0 because all Web requests are processed through the .NET Framework.) In the AJAX Web Parts chapter (Chapter 5), we created an HTTP handler class to deploy the feed list as an OPML XML feed. To install this manually, we need to create the httpHandler node for opml.ashx on every IIS Web application in the farm. This process can become unmanageable over the life cycle of the server as new IIS Web sites are created and extended, especially in a farm configuration. The “no-touch” benefits of the solution package would be lost if your application depended on web.config modifications!

Fortunately, the WSS framework provides a way to manage both Web applications and web.config through the SPWebApplication class, which represents the IIS load-balanced Web application installed to the WSS server farm. This is an IIS Web application that is extended by WSS, which is also mapped to a WSS content database. It is virtualized across the server farm because you can extend arbitrary IIS sites to WSS Web applications, even on the same physical box. It can contain multiple site collections and can be accessed through the WebApplication property of the SPSite class.

Tip 

SPWebApplication is a class with all types of fun and useful ways to administer the WSS Web application!

SPWebApplication is found in the Microsoft.SharePoint.Administration namespace, along with other classes used for administering the WSS environment, including the IIS servers that it runs on. By using classes in the administration namespace, you can manage the WSS environment as a single unit, regardless of the server farm configuration. For example, when you modify the web.config file through the WSS object model, it is modified across all instances of the WSS Web application, including multiple IIS sites that are extended with the WSS application across the server farm.

WSS also manages the state of the Web application so that changes made through the object model are applied to new servers added to the WSS farm as it is scaled out. For example, you might add an additional Web server six months after the initial WSS deployment. For each site on the new server, web.config contains multiple entries for SafeControls, HTTP handlers, and CAS policies, as well as assembly DLLs and other resources for your applications. With an approach that uses only the solution package deployment mechanism, these changes are all maintained by the WSS runtime and applied to the new server automatically.

To access the SPWebApplication, you can use any reference to the SPSite class, such as SPContext.Current.Site.WebApplication. Within a feature receiver, you can obtain a reference to the site collection through the SPFeatureReceiverProperties class and use that to access the SPWebApplication as in the following example.

 public override void FeatureActivated(          SPFeatureReceiverProperties properties) {   if (properties == null)      throw new ArgumentNullException("properties");   SPWebApplication app = null;   SPSiteCollection site = properties.Feature.Parent as SPSiteCollection;   if (site == null) {     SPWeb web = properties.Feature.Parent as SPWeb;     if (web != null)       app = web.Site.WebApplication;   } else     app = site.WebApplication;   // Do something with the web application }

The Web application has a collection called WebConfigModifications that it maintains in the content database and in each web.config for the application. The Web application’s WebConfigModifications collection contains modifications to be applied across all instances of the IIS Web application across all servers in the farm. These modifications are encapsulated in the SPWebConfigModification class. SPWebConfigModification provides a way to make changes to web.config and can be used in a console application or feature receiver. Internally, the WSS runtime stores this information in the farm configuration database in the Objects table and uses XML-serialized objects to persist the class. This lets WSS reapply the objects to new web.config files as new sites come online. The properties for the SPWebConfigModification class are listed in Table 9-1.

Table 9-1: SPWebConfigModification Properties
Open table as spreadsheet

Name

Description

Name

The relative xpath to the modification; used to locate the modification given to the root xpath from the Path property when removing the modification (also the constructor’s name parameter)

Owner

The owner reference of the modification; used to track the modification in the content database; assembly’s full name is recommended

Path

The xpath (also the constructor’s path parameter)

Sequence

Specifies the ordinal sequence of the modification

Type

The SPWebConfigModificationType type of modification-either EnsureChildNode, EnsureAttribute, or EnsureSection

Value

The actual web.config element to insert

Tip 

Use objects in the Microsoft.SharePoint.Administration namespace to manage your environments and avoid making manual changes to configurations in production environments.

To test the SPWebConfigModification class, you can use a console application to administer the local server. To take this further, you could build an extension to STSADM by using the ISPStsadmCommand interface. ISPStsadmCommand is an interface that allows you to write custom STSADM commands. You can read more about extending STSADM through ISPStsadmCommand at http://msdn2.microsoft.com/library/microsoft.sharepoint.stsadmin.ispstsadmcommand.aspx.

A simple console application is included in Listing 9-4. This application adds an element to the WSS Web configuration through SPWebModification. Remember that this is a configuration change tracked and managed by WSS and the WSS configuration database over the lifetime of the WSS Web application, not just a modification to the web.config file. For simplicity, the values are hard-coded into the application in this example. To enable the WSS runtime to track this change, the Path property must be the xpath expression to the root node containing the child node, and the Name property is the xpath expression from the parent node to the new child node. The Name and Path properties are used primarily by WSS to manage the entry over the lifetime of the WSS Web application. On subsequent calls to ApplyWebConfigModification, WSS ensures that all of its modifications are applied or removed. If Name is incorrect on the initial add operation, the element can still be added, but WSS is unable to manage its removal.

Listing 9-4: Web Config Modification Console demonstrates simple use of SPWebApplication and SPWebConfigModification.

image from book
  Web Config Modification Console using System; using Microsoft.SharePoint; using Microsoft.SharePoint.Administration; class Program {   private const string ScriptHandler =     @"<add verb=""GET,HEAD"" path=""ScriptResource.axd"" type=""System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions""     validate=""false""/>";   static void Main(string[] args) {     SPSite siteCollection = new SPSite("http://localhost");     SPWebApplication webApp = siteCollection.WebApplication;     SPWebConfigModification modification = new SPWebConfigModification();     modification.Path = "configuration/system.web/httpHandlers";     modification.Name = "add[@path='ScriptResource.axd']";     modification.Value = ScriptHandler;     modification.Owner = "ExampleOwner";     modification.Sequence = 0;     modification.Type =       SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;     webApp.WebConfigModifications.Add(modification);     // To remove the modification:     // webApp.WebConfigModifications.Remove(modification);     webApp.Farm.Services.GetValue<SPWebService>()     ApplyWebConfigModifications();   } } 
image from book

The example code could be changed easily to remove the configuration change, as in the following example:

 webApp.WebConfigModifications.Remove(modification);

The SPWebConfigModification class is perhaps most useful in the context of a feature receiver, in which case the SPFeatureReceiver passes an instance of the site context in the SPFeatureReceiverProperties object. Depending on whether the feature was installed at the site collection or site level, the feature receiver passes either an SPWeb or an SPSite reference. Using this technique, you can modify the configuration based on the activated feature, letting you package the SPWebConfigModification within the solution package. Following is the example FeatureActivated method of an example feature receiver, which adds the ScriptResourceHandler to the ScriptResource.axd path.

 public override void FeatureActivated(     SPFeatureReceiverProperties properties) {   SPWebApplication app = null;   SPSiteCollection site = properties.Feature.Parent as SPSiteCollection;   if (site == null) {     SPWeb web = properties.Feature.Parent as SPWeb;     if (web != null)       app = web.Site.WebApplication;   } else     app = site.WebApplication;   SPWebConfigModification modification = new SPWebConfigModification();   modification.Name = "add[@path='ScriptResource.axd']";   modification.Path = "configuration/system.web/httpHandlers");   modification.Value = @"<add verb=""GET,HEAD"" path=""ScriptResource.axd"" type=   ""System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions"" validate=""false""/>";   modification.Owner = Assembly.GetExecutingAssembly().FullName;   modification.Sequence = 0;   modification.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;   app.WebConfigModifications.Add(modification);   SPFarm.Local.Services.GetValue<SPWebService>().ApplyWebConfigModifications(); }

Within the FeatureDeactivating method, you can remove the handler by using the following code, being careful to pass the same Name, Path, and Owner previously used.

 public override void FeatureDeactivating(SPFeatureReceiverProperties properties) {   SPWebApplication app = null;   SPSiteCollection site = properties.Feature.Parent as SPSiteCollection;   if (site == null) {     SPWeb web = properties.Feature.Parent as SPWeb;     if (web != null)       app = web.Site.WebApplication;    .} else     app = site.WebApplication;   SPWebConfigModification modification = new SPWebConfigModification();   modification.Name = "add[@path='ScriptResource.axd']";   modification.Path = "configuration/system.web/httpHandlers");   modification.Value = @"<add verb=""GET,HEAD"" path=""ScriptResource.axd""   type=""System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions"" validate=""false""/>";   modification.Owner = Assembly.GetExecutingAssembly().FullName;   modification.Sequence = 0;   modification.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;   app.WebConfigModifications.Remove(modification);   SPFarm.Local.Services.GetValue<SPWebService>().ApplyWebConfigModifications(); }

Using this strategy, you can create modifications to web.config and manage web.config files across the server farm through the use of feature receivers, and you can maintain a no-touch deployment strategy for your WSS solutions.




Inside Microsoft Windows Sharepoint Services Version 3
Inside Microsoft Windows Sharepoint Services Version 3
ISBN: 735623201
EAN: N/A
Year: 2007
Pages: 92

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net