This chapter will focus on best practices for deploying your SharePoint 2010 customizations developed with Visual Studio 2010 SharePoint 2010 tools. This chapter does not provide an introduction to the Visual Studio 2010 SharePoint 2010 tools that automate much of the work to create features and solutions (WSP files). It is assumed you already know what SharePoint features and solutions are, and that you have a good hands-on working knowledge of how to create these in Visual Studio 2010. Rather, this chapter will demonstrate some best practices that will encourage you to carefully plan out the structure of your Visual Studio solutions, SharePoint features, and SharePoint solutions. Here are some of the best practices that will be covered in this chapter:
In my experience of reviewing probably hundreds of developed customizations for SharePoint (both the 2007 and 2010 versions), the packaging and then deployment of SharePoint solutions consistently seems to be an afterthought. That is, something that had to be done at the end of the project in order to move the customizations out of development and on to Testing and/or Production environments. Not Surprisingly, planning out the strategy and structure for features and solutions is almost never done.
Please see if some of the following deployment experiences and observations apply to you:
In order to demonstrate typical considerations for designing SharePoint features and solutions, a simple but useful example has been created. The example, when fully deployed, will provide a “footer links” Web Part that can be placed at the bottom of your master page. Footer links are the links you might typically see at the bottom of your web site page such as Contact Us, Privacy Statement, and Site Map. The Web Part will read entries from a footer links list so that it will be easy for the web master to maintain the footer links on the site. The “schema” for the footer links is defined as a content type with corresponding site columns. The content type is then attached to the list where the footer links are created. There is a feature stapler to ensure the Footer Links feature and Web Part are available automatically when a team site is provisioned.
This example contains a typical core pattern of customization to formulate the best practice recommendations, all managed in Visual Studio 2010 SharePoint 2010 tools.
I am presuming you have available a local development environment or access to a SharePoint environment. Go to Central Administration and create a site collection. In my case, I have created a site collection at http://intranet.theopenhighway.net/sites/Apress.
Open the Visual Studio solution provided for this chapter, FooterLinks.sln
. Figure 12-1 shows what the solution looks like when open.
Click on each of the projects in the solution—FooterLinksList and FooterLinksSchema—and change the site URL property (in the Properties window) so it matches the site collection you just created. Save the changes. Right click on the FooterLinksSchema project and choose Deploy. Once the deployment succeeds (view the Output window to verify), right click on the FooterLinksList project and select Deploy. Once the deployment succeeds, view the Output window to verify.
Tip Generate a key file unique for your application and use the key file in all of your Visual Studio projects. Note the APressKey.snk
file in the above projects. This will ensure the public key token for all of your DLLs will be the same.
Figure 12-2 shows a view of the Footer Link site collection features activated.
Figure 12-3 shows a view of the Footer Link site feature activated.
Tip (Well, this is more of a pet peeve than a tip.) Notice that I have set the ImageURL property for my feature and included an image as the icon for the feature. This is a professional touch that makes your features stand out, and I suggest you take the time to mark your features with your company logo or whatever else might be appropriate for the project.
Figure 12-4 shows a view of the defined site columns in the Site Column Gallery.
Figure 12-5 shows a view of the defined content type in the Content Type Gallery.
Figure 12-6 shows a view of the Footer links list settings; note the content type.
Figure 12-7 shows an example of some footer link list entries.
Figure 12-8 shows an example of the footer links Web Part in use on a master page. Note that the red box was a deliberate image highlight to point out the footer links near the bottom of the page.
It should be an assumption at this point in time that one, would, of course deploy their SharePoint items (content types, Web Parts, list schemas, or whatever) through the use of features. These features would be appropriately scoped at the farm, web application, site collection (site) or site (web) level according to the type of SharePoint item. The SharePoint 2010 tools for managing features and associated properties are absolutely fantastic. Figure 12-9 offers a quick look at the Feature Designer for the Footer Links Web Part.
Figure 12-10 shows the Properties window for the feature. I have set the image URL (as mentioned in my pet peeve/tip earlier) and set the feature version to 1.0.0.0. I will also discuss other important properties, such as the Receiver Assembly/Class and the Upgrade Actions Receiver Assembly/Class.
Tip Most importantly, set the initial version of your feature to 1.0.0.0. The usefulness of feature versions will be discussed later in this chapter.
The property that is Deployment Path is exactly as follows:
$SharePoint.Project.FileNameWithoutExtension$_$SharePoint.Feature.FileNameWithoutExtension$
I tend not to like the project_feature naming format, but this is just a preference. I have left it as the default in this chapter example but normally would change it to the last half, namely:
$SharePoint.Feature.FileNameWithoutExtension$
Feature receivers are code that (typically) runs as you press the Activate and Deactivate buttons on a feature. Well, the code will run regardless of how the feature is activated or deactivated (such as PowerShell), but it is easier if you can visualize it that way. Feature receivers can handle any initialization or clean up task. In this example, for the Footer Links list feature, you must (in code) set the Allow Management of Content Types setting on the Footer Links list. Now the footer content type will display properly in the Footer Links list settings, and when you create a new item, you get new Footer item. Upon deactivate, you have made the choice to completely remove the footer links list form the site (i.e. delete it). Listing 12-1 shows the feature receiver code you have in place.
public class FooterItemListEventReceiver : SPFeatureReceiver
{
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
SPWeb site = properties.Feature.Parent as SPWeb;
// Enable Management of Content Types for Footer Links list
SPList listFooterLinks = site.Lists["Footer Links"];
listFooterLinks.ContentTypesEnabled = true;
listFooterLinks.Update();
}
public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
SPWeb site = properties.Feature.Parent as SPWeb;
if (site != null)
{
SPList list = site.Lists.TryGetList("Footer Links");
if (list != null)
{
list.Delete();
}
}
}
}
Tip If you provision lists with attached content types, always include a feature receiver that sets “Allow Management of Content Types.” If you examine the feature properties after adding a feature receiver, you will note the Receiver Assembly and Receiver Class properties have been automatically set.
Feature activation dependencies prevent, as the name implies, activation of a given feature if the dependent feature has not been activated on the site/site collection. In your example, bad things would happen if the Footer Links list were provisioned while the underlying content types and site columns were not there. Since the schema is in one feature and the list provisioning in another feature, this requires that the schema feature be present and activated before you can activate the list provisioning feature. Without activation dependencies, nothing at all would prevent you from doing these bad things. Open up the Feature Designer for the Footer Item List feature. Scroll to the bottom if necessary. Expand the Feature Activation Dependencies section. Click the Add button, and select the Footer Links Schema feature. The result will look as shown in Figure 12-11.
To see feature activation in action, redeploy all of the SharePoint solutions, but don’t activate any of the features (or, simply deactivate all of the features if they already are deployed). Now, go the example site and go to Site Actions Site Settings Site features. You should see the text shown in Figure 12-12, where the Footer Item List feature is not currently activated.
The following feature activation dependency is in place: Footer Item List site features depends on Footer Links Schema site collection feature. Attempting to activate the Footer Item List feature results in the message shown in Figure 12-13.
Unfortunately, you can’t define all the dependencies that you would like. For example, say you would like to have the following activation dependency: “Footer Web Part site collection feature depends on Footer Item List site feature.” However, you can’t define an activation dependency on a feature of a lower scope (i.e., the site collection feature depends on the site feature). It makes sense, because you don’t want your Web Part to be available if the Footer Item List is not available. You can actually go into Visual Studio and declare the activation dependency in the Footer Web Part feature, as shown in Figure 12-14.
You can package and deploy the solution and then attempt to activate Footer Web Part, as shown in Figure 12-15.
But you will receive the error message shown in Figure 12-16.
Also, nothing will prevent the deactivation of dependent features. If all of the Footer features are currently activated, you can deactivate the Footer Links Schema feature without complaint from SharePoint. Finally, if you decide to have some of your features be hidden, then you can’t define activation dependencies on them.
Ok, it is not perfect. But as a best practice, you should declare as many valid activation dependencies as possible!
Feature stapling allows you to attach (or, I guess, “staple”) a feature to a site definition. Put another way, it lets you add your own feature to an existing site definition without having to alter the site definition in any way. That is especially good news when it is an out-of-the-box site definition such as team site. In your case, any time a team site is created, the footer links Web Part (and associated footer links list and content type) are automatically available for use.
For this example, a separate Visual Studio solution was created with a separate feature, so as not to interfere with the coming upgrade example. You can open the sample solution, build it, and deploy it. The structure of the solution is quite simple—just a web application scoped feature and one Elements.xml
file, as shown in Figure 12-17.
The Elements XML file is also quite simple. It contains the ID of the feature you want to staple, and you must give the ID of the site template you want to attach the feature to. As an example, STS#0 is the team site definition and STS#1 is the blank site definition. You have chosen to staple the footer links features to the team site definition consisting of three features: Schema, List, and Web Part, as shown in Figure 12-18.
To see this feature deployed, go to Central Administration Application Management Manage Web Applications. Click on the web application you are using for this chapter (in my case, The Open Highway), and click on the Manage Features button in the ribbon. You will see the Footer Links Feature Staple activated in the list, as shown in Figure 12-19.
So when does the magic happen?!? Use Central Administration to create a new site collection of whatever name you wish and choose the Team Site template. When the site is created, follow the link note that the footer links list has been defined. Note that in Figure 12-20 I took the additional step to add a sample value and the Footer Web Part, quite inappropriately, near the top of the page.
Tip A feature staple is a fast and easy way of customizing out-of-the-box site definitions within a given web application so that it is provisioned and even branded exactly as you want it to be.
In order to fully understand the provisioning of SharePoint solutions, you must understand the solution lifecycle from the perspective of the PowerShell commands that operate on it. Let’s first assume that the SharePoint solution has never been deployed to the farm. Starting with the FooterLinksSchema solution, the first PowerShell command to execute is Add-SPSolution. This simply adds the WSP file to the solution store of the Central Administration configuration database, and nothing more. The next command to execute is Install-SPSolution. This physically pushes the files within the WSP to the SharePoint root folder of all the servers in the farm and takes other specified actions (add entries to web.config
, deploy DLLs to global assembly cache, etc.). The features you have deployed will now be available according to the specified feature scope.
Now let’s assume you have made some significant changes to the SharePoint solution or otherwise need to fully re-deploy the contents. You would have created an updated WSP file. With the PowerShell command Uninstall-SPSolution, you are physically retracting (deleting) all of the files from all the SharePoint servers in the Farm as well as reversing other specified actions (such as removing deployed DLLs). The features previously deployed are now no longer available. Next, with the PowerShell command Remove-SPSolution, delete the WSP file from the solution store in the Central Administration database. Now you repeat the Add-SPSolution and Install-SPSolution but with the updated WSP file.
So now any full solution deployment can be done via the script in Listing 12-2 (included along with sample code for this chapter).
Add-PSSnapin Microsoft.SharePoint.Powershell -ErrorAction SilentlyContinue
$WebApp = "http://intranet.theopenhighway.net"
$Path = "C:ProjectsApressDeploymentFooterLinksList.wsp"
$SolutionPackage = "FooterLinksList.wsp"
$solution = Get-SPSolution | where-object {$_.Name -eq $SolutionPackage}
if ($Solution -ne $null) {
if($Solution.Deployed -eq $true) {
Write-Host "Retracting Solution from the Farm..."
Uninstall-SPSolution -Identity $SolutionPackage -Local -Confirm:$false
-WebApplication $WebApp
Write-Host "Solution retracted."
Write-Host
}
Write-Host "Deleting Solution from solution store..."
Remove-SPSolution -Identity $SolutionPackage -Confirm:$false
Write-Host "Solution deleted."
Write-Host
}
Write-Host "Adding Solution to solution store..."
Add-SPSolution -LiteralPath $Path
Write-Host "Solution added."
Write-Host
Write-Host "Deploying Solution to the Farm..."
Install-SPSolution -Identity $SolutionPackage -Local -GACDeployment
-WebApplication $WebApp
Write-Host "Deployment complete."
Write-Host
Write-Host "Script has completed. Press Enter to continue."
Read-Host
Note If the solution file contains any web application dependent items, such as Web Parts, you must add a “-WebApplication” parameter to both Install-SPSolution and Uninstall-SPSolution along with the URL of the web application. This will deploy the solution to a specified web application. You can optionally deploy to all defined web applications with the parameter “-AllWebApplications”.
Tip If you run your SharePoint PowerShell scripts via the SharePoint 2010 Management Shell (available via Program Files Microsoft SharePoint 2010 Products), then you don’t require the Add-PSSnapIn command, as the cmdlets for SharePoint will already have been automatically loaded.
SharePoint solution activation dependencies work in a similar fashion to feature activation dependencies. However, they are just slightly misleadingly named when deployed to the farm (the terminology is geared towards sandboxed solutions in the Solutions gallery). It acts like more of a deployment dependency in this scenario. That is, say you have Solution B that has its activation dependency set on Solution A. Solution A is not deployed to the farm. The attempt to deploy Solution B will result in an error.
In your example, the FooterLinksList solution is dependent upon the FooterLinksSchema solution. This makes sense, because you won’t be able to provision a footer links list instance if the corresponding site columns and content types have not been deployed. So your first check point will be to ensure the FooterLinksSchema solution has been deployed to the Farm.
To add the activation dependency, expand the Package node in the FooterLinksList project and double-click on package.package to bring up the package designer. Click on the Manifest tab. Unlike adding feature activation dependencies, there is no convenient way of adding the solution activation dependency. You must edit the Manifest.xml
file manually. Expand the Edit Options section and click Open in XML Editor, and you will see the code shown in Figure 12-21.
Tip Always set solution activation dependencies for your SharePoint solution packages (WSP files) to avoid potential deployment errors.
To trigger the solution activation dependency, uninstall and remove both solutions (FooterLinksList and FooterLinksSchema) using PowerShell. Add the FooterLinksList solution using PowerShell. Go to Central Administration System Settings Manage Farm Solutions. Click on footerlinkslist.wsp
. You should see the information shown in Figure 12-22.
Click Deploy Solution and accept the deployment option defaults on the following screen and click OK. You will see the error screen shown in Figure 12-23 stating that the dependent solution (FooterLinksSchema) has not been activated (i.e. deployed).
As an exercise, recreate this situation, deploy the FooterLinksSchema solution, and then come back and verify you can also deploy the FooterLinksList solution.
In this context, I am referring to SharePoint Solution (WSP) files, not a Visual Studio 2010 solution (SLN) file. In fact, please go right ahead and have one Visual Studio 2010 SLN file for your project if that makes sense for you. However, the current limitation with the SharePoint 2010 Visual Studio 2010 tools is that a Visual Studio project equals exactly one “Package” definition, which in turn means one WSP file. Each Visual Studio Project/SharePoint Package can contain one or more SharePoint Features, and each feature can consist of one or more items.
So what is the right number of SharePoint solutions? I can state with certainty that for your set of planned customizations the wrong answer is “one.” It seems temptingly simple to go for one big package of features—after all, this is all brand new functionality, right? Or maybe you have otherwise not had to think about the deployment, so one big package does the job of getting the customizations “out there” at the end of the project.
I would prefer, if you are in doubt, that you define a new Visual Studio Project/SharePoint solution file rather than adding to your existing one. It is certainly more feasible to consider consolidating features into WSP files rather than to break apart a monolith. Here are some considerations for when to split out SharePoint features into new SharePoint solution files:
Figure 12-24 shows the structure and content of this chapter’s example code, with the two solutions and three features defined. The arrow between the two solution files depicts the activation dependency between them, and the arrows between the features depict the feature activation dependencies that are logically in place.
Note that the only activation dependency you can’t physically define is the one between the footer Web Part and the footer item list. See the previous section on feature activation dependencies on why this is not possible.
Note I don’t mean to imply that in this scenario you couldn’t have one Visual Studio solution file containing all three of these projects. Two of the projects could each have a package with the contents outlined above. So, yes, I have taken some liberties with this very simple example for the purposes of highlighting the possible best practices that more likely would be applied to a much larger customization project.
Tip Draw out and think carefully about your SharePoint solutions and what features they will contain. Also define as many physical solution activation dependencies and feature activation dependencies as possible.
As a developer, you will be providing updates to your SharePoint solution (WSP) files. Perhaps you are deploying enhancements or bug fixes to the Testing or Production environments. Different versions of your solution are likely currently running in each of those environments. The latest version will be in Development, a lower version in Testing, and current release (oldest) version in Production. Historically, this has been difficult to manage!
One choice would be to rip and replace the WSP using the full deployment lifecycle cmdlets for SPSolution: Remove and Uninstall the old WSP, then Add and Install the new WSP. This is often too drastic, quite unnecessary, and can lead to unpredictable results as you may not know exactly what might happen in your feature receiver code. Also, you may have a chain of dependent features. Obviously, things can get complicated quickly.
SharePoint 2010 has the cmdlet Update-SPSolution, which is the preferred and recommended way to push out an updated WSP to the farm. Caveat: I will add “when it is valid to do so.” “Update” means you have some new elements or updated code for the GAC—not completely different or additional features! You will know when you have crossed the boundary because the update solution will fail. If you have a WSP that is already deployed to several environments and not easy to rip and replace, then I recommend that you put your new features into a new and separate WSP as they will be easier to deploy and manage.
We have had this ability to update a solution even in SharePoint 2007 (via an STSADM command), so this has been around for a while. There is a common misconception that it performs the same set of commands as rip and replace. It does not; key, for example, is the fact that feature receiver activate/deactivate code will not be fired.
What does the Update Solution do? It simply pushes out new and updated files from the WSP (primarily) into the SharePoint root folder (i.e. out to the SharePoint web front ends). It’s perfectly fine on its own if you are simply updating files, such as newly compiled DLLs (to GAC), ASCX files (to control templates directory), new element files, updated feature.xml
, images, application pages (to layouts directory), etc.
Update Solution is categorically not useless, as prevailing wisdom might indicate. In fact it is, and has been, extraordinarily useful and many time painless for deploying updated WSPs. However, I will certainly agree that it is often times not sufficient to only deploy new/updated files. Let’s imagine there was no feature receiver nor Activate and Deactivate methods for us to insert custom code on our initial (and full) deployment. We could push the files out to the web server, but would have no means of custom initialization or clean up. Those were precisely the limitation we had in SharePoint 2007 with update solution, where we had to follow up the WSP update with custom script or C# (console app) code, and maybe run through a list and update some data related to the changes.
You probably have already heard many times by now about the new upgrade capability for features. This can either be in the form of a new declarative UpgradeActions section for the Feature.xml
file or the new imperative FeatureUpgrading method in the feature receiver. In the remainder of this section, you will learn that Update Solution and Upgrade Solutions are separate steps. You will explore the mechanics of each and the process for accomplishing the upgrades.
Please define a second site collection. In my case I have called it http://intranet.theopenhighway.net/sites/Apress2
. If you are following along with the changes, please do not activate any of this chapter’s sample features or even deploy the updated solutions (which will happen if you press F5 in Visual Studio, for example).
Tip Create a snapshot of your virtual machine before running the actual upgrade commands. This way, you can easily go back to the machine state before the upgrade in case you wish to explore the upgrade in more detail or try the upgrade scenario again.
You will be able to compare the first site collection against the second, where I will demonstrate that the feature version running in a particular site collection can in fact be different from the installed version!
Open up the Version 1.1 of the Visual Studio solution for this Chapter, FooterLinksV2.sln
. You can follow along as I detail the changes made to version 1 of the solution.
You have created Version 1.1 at the request of the client, who has stated that there are too many Footer Link entries in the list. They don’t want to delete any entries, but they want a means of managing which ones are displayed. You have decided to add an Is Active flag (a Boolean) to the schema to indicate which items are displayed. This requires numerous small changes through your projects and features.
Figure 12-25. Changing Feature Version to 1.1
Tip Only increment the feature version if there has been a change. Always increment the feature version number if there is a change! Remember to make the appropriate change increment. The four-part build number is Major.Minor.Build.Revision. The Major.Minor version is typically the product version. For instance, SharePoint 2010 is version 14.0 (at time of release).
Tip Only publish a major feature version if there have been very significant changes to the software. Use of this number is ultimately up to the author. Sometimes it’s used to designate the release number of the software. You might typically increment the build of software (such as 1.0.1, 1.0.2, etc) until you have a patch or point release, at which point it becomes 1.1.
Elements2.xml
. Ensure the Deployment Type property is set to ElementManifest, as shown in Figure 12-26.
Figure 12-26. Footer Columns SharePoint item
Elements2.xml
file, define a new site column that will be named Is Active. You will see shortly why you are putting this site column in a separate XML file versus adding to the Elements.xml
file containing the Sort Order column. Ensure the GUID is unique!
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Field ID="{BB8EB2D5-3A68-4607-88F4-8338DACBD8E4}"
Group="Apress Columns"
Type="Boolean"
Name="IsActive"
DisplayName="Is Active"
ShowInDisplayForm="TRUE"
ShowInNewForm="TRUE"
ShowInEditForm="TRUE" />
</Elements>
Elements.xml
file that is under the FooterItem content type (under the content types folder), as shown in Figure 12-27.
Figure 12-27. Edit the Elements.xml file
Elements.xml
file, using the GUID from the previous step, add the FieldRef to the content type, immediately below SortOrder.
<FieldRef ID="{BB8EB2D5-3A68-4607-88F4-8338DACBD8E4}" Name="IsActive" />
Schema.xml
for the FooterItem list definition (under the ListDefinitions folder). Add the FieldRef to the ContentTypes section (created in step 3). Add the Field to the Fields section (created in step 2).<Where>
<Eq>
<FieldRef Name=""IsActive"" />
<Value Type=""Integer"">1</Value>
</Eq>
</Where>
<OrderBy>
<FieldRef Name=""SortOrder"" Ascending=""True"" />
</OrderBy>
Tip Alright! Yes, this is a CAML (Collaborative Application Markup Language) query. Clearly this should be a new and shiny SP LINQ query, but for sake of this example, I didn’t want to introduce the dependency to run spmetal.exe
to generate the datacontext
class (or to download and use the Visual Studio 2010 Power Toys).
So that takes care of the coding changes required to implement the new Is Active flag. Now you need to put in some changes that will drive an upgrade process from Version 1.0 to 1.1.
Figure 12-28. Manually adding Upgrade Actions to FooterLinksSchema feature
Feature.xml
file is new to SharePoint 2010. It allows you to specify actions to take as you upgrade from one specific version to another. Note the BeginVersion and EndVersion are actually optional; if not specified, the UpgradeActions would apply to any upgrade. Best practice? Be explicit about your upgrade actions by using version number ranges.Figure 12-29. Manually adding Upgrade Actions to FooterLinksList feature
FeatureUpgrading
method would be called for each node, passing in the name and an optional subset of parameters (there are no parameters in this example). Let’s first view the FeatureUpgrading
method and then I will describe how this works.FooterItemList.FeatureEventReceiver.cs
file. Add the following code. You can see that the guts of this goes through the Footer Links list and update each item IsActive column to true.
public override void FeatureUpgrading(SPFeatureReceiverProperties
props, string upgradeActionName,
System.Collections.Generic.IDictionary<string, string> parameters)
{
SPWeb site = props.Feature.Parent as SPWeb;
if (site != null)
{
// determine which custom upgrade action is executing
switch (upgradeActionName)
{
case "SetIsActiveColumn":
// See if the Footer Links List exists
SPList list = site.Lists.TryGetList("Footer Links");
if (list != null)
{
// Set the new IsActive Flag for each item on
// the current list
SPListItemCollection items = list.Items;
foreach (SPListItem listItem in items)
{
listItem["IsActive"] = true;
listItem.Update();
}
}
break;
default:
// exit if unknown feature action
break;
}
}
}
FeatureUpgrading
from each CustomUpgradeAction in the Feature.xml
will pass in the string “upgradeActionName”. In your case, the value will be SetIsActiveColumn. The best practice is demonstrated here where you use a switch statement to process values for the action name, and a default break in case an unknown value makes its way in so it will exit cleanly.Figure 12-30. Setting Upgrade Actions properties
I have provided a Query Features PowerShell script that does a Get-SPFeature versus QueryFeature. This script compares the installed version versus the version currently running in the various sites. For now (before the upgrade), we still have version 1.0.0.0 installed and running for our three features in the Apress site, as shown here:
Feature: FooterLinksSchema_FooterLinksSchema
=======================================================================
The following version is the INSTALLED Version: 1.0.0.0
Version 1.0.0.0 is currently RUNNING in site at
http://intranet.theopenhighway.net/sites/apress
Feature: FooterLinksList_FooterItemList
=======================================================================
The following version is the INSTALLED Version: 1.0.0.0
Version 1.0.0.0 is currently RUNNING in site at
http://intranet.theopenhighway.net/sites/apress
Feature: FooterLinksList_FooterWebPart
=======================================================================
The following version is the INSTALLED Version: 1.0.0.0
Version 1.0.0.0 is currently RUNNING in site at http://intranet.theopenhighway.net/sites/apress
There is another script provided that will take the new solution files and perform the PowerShell command Update-SPSolution; this will physically push the new files out to the SharePoint Root folder.
With these commands executed, let’s verify that the files were in fact pushed out. Go to the SharePoint Root folder in your virtual machine (located at C:Program FilesCommon FilesMicrosoft SharedWeb Server Extensions14
). Go to the Template/Features
folder and find the feature beginning with the name FooterListSchema (either by name or sort directory descending by date). In the FooterItem sub directory, you can verify the newly created Elements2.xml
is there (as shown in Figure 12-31).
Open up the Feature.xml file. Note that the version number is now 1.1.0.0, as shown in Figure 12-32.
Go to the Apress2 site created in the Getting Ready section (in my case http://intranet.theopenhighway.net/sites/Apress2
). Manually activate the Footer Links Schema feature at the site collection level. Then activate the Footer Item List feature at the site level and finally come back to activate the Footer Web Part feature at the site collection level.
If you re-run the Query Features PowerShell script again, you now see the following:
Feature: FooterLinksSchema_FooterLinksSchema
=======================================================================
The following version is the INSTALLED Version: 1.1.0.0
Version 1.0.0.0 is currently RUNNING in site at
http://intranet.theopenhighway.net/sites/apress
Version 1.1.0.0 is currently RUNNING in site at
http://intranet.theopenhighway.net/sites/apress2
Feature: FooterLinksList_FooterItemList
=======================================================================
The following version is the INSTALLED Version: 1.1.0.0
Version 1.0.0.0 is currently RUNNING in site at
http://intranet.theopenhighway.net/sites/apress
Version 1.1.0.0 is currently RUNNING in site at
http://intranet.theopenhighway.net/sites/apress2
Feature: FooterLinksList_FooterWebPart
=======================================================================
The following version is the INSTALLED Version: 1.1.0.0
Version 1.0.0.0 is currently RUNNING in site at
http://intranet.theopenhighway.net/sites/apress
Version 1.1.0.0 is currently RUNNING in site at
http://intranet.theopenhighway.net/sites/apress2
I think that is pretty amazing—that you can actually have multiple versions of a feature running simultaneously in different site collections of the same web application.
According to the Query Features PowerShell script, you are at the point where you have Version 1.1 of your features deployed, the Apress site has version 1.0 of the features running, and the Apress2 site has version 1.1 of the features running. What remains to be done is to upgrade the sites running the older version of the features. With the upgrade code, I hope that you can see you are targeting the differences in functionality between version 1.0 and version 1.1. These differences are as follows:
I have provided a full script to upgrade each of the features to Version 1.1. Here are the key lines of the script:
features = $webApp.QueryFeatures($FeatureId, $true)
foreach($feature in $features){
$feature.Upgrade($true)
}
QueryFeatures with the true parameter will retrieve all features in the current web application that are scoped to site or web and have a specific needsUpgrade state. And then, in an anti-climactic fashion, the $feature.Uprade will perform all of the upgrade actions as listed.
If you re-run the Query Features PowerShell script again, you now see the following:
Feature: FooterLinksSchema_FooterLinksSchema
==========================================================================
The following version is the INSTALLED Version: 1.1.0.0
Version 1.1.0.0 is currently RUNNING in site at
http://intranet.theopenhighway.net/sites/apress
Version 1.1.0.0 is currently RUNNING in site at
http://intranet.theopenhighway.net/sites/apress2
Feature: FooterLinksList_FooterItemList
==========================================================================
The following version is the INSTALLED Version: 1.1.0.0
Version 1.1.0.0 is currently RUNNING in site at
http://intranet.theopenhighway.net/sites/apress
Version 1.1.0.0 is currently RUNNING in site at
http://intranet.theopenhighway.net/sites/apress2
Feature: FooterLinksList_FooterWebPart
==========================================================================
The following version is the INSTALLED Version: 1.1.0.0
Version 1.1.0.0 is currently RUNNING in site at
http://intranet.theopenhighway.net/sites/apress
Version 1.1.0.0 is currently RUNNING in site at
http://intranet.theopenhighway.net/sites/apress2
Now everything is running at version 1.1. Success! As a quick verification, in the original Apress site, look at the list settings for Footer Links, as shown in Figure 12-33. Note the IsActive field appears; it has been pushed down from the content type update.
Edit any of the items in the list and note that the IsActive flag is set, verifying that your FeatureUpgrading code ran (see Figure 12-34).
The command line upgrade for SharePoint (psconfig.exe
) offers one advantage over upgrading with PowerShell Feature.Upgrade and that is the ability to control which upgrades are performed. If, after Update-SPSolution, you run the following command line:
psconfig -cmd upgrade -inplace b2b
It will trigger the upgrade for version 1.0.0.1 to 1.0.0.2, but not 1.1.0.0. That is, it will make any change in the last two places of the x.x.x.x format version number. If you run the following command line:
psconfig -cmd upgrade -inplace v2v
It will trigger the version upgrade from 1.0.0.0 to 1.1.0.0, as in our example. That is, it will make any change in the first two places of the x.x.x.x format version number.
Again, I haven’t run across this requirement in practice, but it’s there if you need it!
Have you “been there” regarding my scenarios of observations from the field? If you haven’t, I am clearly recommending that you don’t “go there.” Perhaps you now see why this is the case in so many situations. SharePoint solutions, features, packaging, versions, and dependencies require much thought and advance planning. I hope I have shown that taking the time to do so is a great investment. I hope, too, that you have a solid understanding of the mechanics involved—invaluable for the troubleshooting days ahead. If you keep one main thought in mind—and that is the maintenance and upgrading of features in the future—then you will create a great structure with which to work. I encourage you to think beyond simply the first deployment.