Monday, November 9, 2009

In-place Upgrade of Solutions in SharePoint 2010

The In-Place upgrade mechanism for SharePoint solutions now uses the feature upgrade mechanism to upgrade features already installed and activated in the farm. In this scenario an existing version of a solution exists within a farm with a set of active features. The goal is to upgrade it to a new version without retracting and redeploying. This will allow any active features to upgrade if needed.

Only one version of any solution will exist in the farm solution store. In the first step, a WSP that exists in the solution store is updated with a WSP file on disk. Then a job is run in the timer service and files in the WSP are deployed into the 14 hive on top of the existing files. (This is an update of the SPPersistedFile objects in the config database.) Finally psconfig must be called to upgrade features using the new 2010 feature upgrade system and to upgrade administrative SPPersistedObjects using the IUpgradable and IUpgradable2 interfaces.

The upgrade mechanism extends what was delivered in 2007. Either STSADM or PowerShell can be used to upgrade solutions stored in the farm solution store.

The STSADM approach:

CMD> stsadm –o upgradesolution –name <Solution name> -filename <path to new version of solution> -immediate -allowgacdeployment

CMD> stsadm -o execadmsvcjobs

CMD> psconfig -cmd upgrade -inplace b2b

The PowerShell approach:

PS> Update-SPSolution –Identity <Solution GUID ID or solution name> -LiteralPath <path to new version of solution> –GACDeployment true

PS> psconfig -cmd upgrade -inplace b2b

It is important to note that the “b2b” argument for psconfig. It indicates that the upgrade will action will be executed on a build to build comparison. With “b2b” any feature that has any positive version change will be upgraded. Alternatively the “v2v” argument can be used. The “v2v” argument will cause features to only be upgraded if the major and minor versions increase; it ignores the build and revision portion of the version string.

If the solution to be deployed contains assemblies for the GAC the –allowgacdeployment must be used with stsadm or –GACDeployment true with Update-SPSolution. Watch the time between the completion of stsadm or Update-SPSolution and the completion of psconfig. During this time the GAC will be running the new DLL assemblies while the features will still be configured with the previous version.

The upgrade is global to the farm and all installed components. The psconfig will search the farm for all items that need upgrade and upgrade them in place. This will include all pending SharePoint patches that have been installed as well as any third party solution upgrades that have been place in the system but to which the psconfig –cmd upgrade has not been run.

It is possible to end up with a partial upgrade. All activated features that can be upgraded will. Any that can’t be upgraded will be noted in an upgrade log. The psconfig tool will point you to the log in the event of failure.

I have performed many upgrades on solutions stored in the farm solution store during my testing.

The in-place upgrade for the new SPUserSolution sandbox solutions is very different. It happens automatically if you have set up the WSP file correctly with the same solution ID but a different hash code. Here is what Microsoft says:

An upgrade for a sandboxed solution is any solution that is uploaded to the solution gallery with the same solution ID of the version deployed to the site collection but with a different hash code. Incoming requests fail during the upgrade process. Any feature upgrade actions will be processed as well. During upgrade, the feature definitions for the existing solution are compared with the feature definitions for the new solution. Existing feature definitions are upgraded on the site and all subwebs are removed if they no longer exist in the new solution. All new feature definitions are activated on the site. However, upgrade will fail if an existing feature definition is a newer version than the feature definition that is included in the new solution.

I have yet to try it and see if it all works as they claim.

Thursday, November 5, 2009

Features are Versioned and Upgradable on SharePoint 2010

One of the big sticking points with SharePoint 2007 was that Microsoft failed to adequately address was how to update between versions of third party SharePoint applications. Microsoft has addressed much of this introduction of feature versioning in 2010.

Starting with SharePoint 2010, the versions of all features activated are stored. Farm and web application features versions are stored in the config database. Site collection (SPSite) and site (SPWeb) features versions are stored in the content database. Features shipped without version numbers default to version 0.0.0.0.

With the in-place upgrade process provided in psconfig.exe, the farm is scanned and the versions of all features activated are compared with the versions of the feature definitions installed. Any active feature that is not up to the current feature definition (SPFeatureDefinition) version has the opportunity to upgrade. How that upgrade occurs depends on a new block of CAML XML in the feature definition under the new UpgradeActions element.

There are several types of UpgradeActions. They include CustomUpgradeAction, ApplyElementManifests, AddContentTypeField, and MapFile. The most flexible of these is CustomUpgradeAction for which you can assign a SPFeatureReceiver. When you do that it will invoke a new method FeatureUpgrading on the SPFeatureReceiver.

Some upgrade code paths must always run. An example of this would be having a base schema for a content type which never changes (because it was released in the past), but always AddContentTypeField regardless of whether deploymenting a new current version or an upgrading to the current version.

At other times, you must use the VersionRange element. This element specifies the affectivity of the upgrade code. An example would be a new module added to older versions.

Over the next few days I will post some examples of using feature upgrade.

Wednesday, November 4, 2009

PowerShell Setup for SharePoint 2010 Diagnostics

STSADM still ships with SharePoint 2010 but has been replaced with PowerShell as the preferred scripting engine for SharePoint. I rarely write SharePoint scripts, but I do often use these tools for testing. Lately I have been testing a lot of upgrade scenarios. To make the best use of PowerShell as a SharePoint diagnostic environment I have a few tips.

PowerShell Community Extensions – Get and install these extensions as they will make your PowerShell environment much nicer. Once installed, edit the (My)Documents\WindowsPowerShell\Profile.ps1 file to uncomment the Visual Studio environment variables. It is necessary to add ’10.0’ at the front of the comma separated list for “VisualStudioVersion”.

Auto Load the SharePoint Extension – Add the following line to your PowerShell profile.ps1 file to automatically load the SharePoint extension for PowerShell in every shell you launch.

& "C:\Program Files\Common Files\Microsoft Shared\Web Server xtensions\14\CONFIG\POWERSHELL\Registration\sharepoint.ps1"

PowerShell Threading Model and Extension Object Disposal – Each line entered in PowerShell is run by a single thread. This creates some problems because many SharePoint objects are attached to IIS COM objects and need disposal. The SharePoint extension methods for PowerShell deal with this to some extent. You get objects that appear to be the SharePoint .Net objects but are in some way disconnected from the IIS backend. The result is that some of the methods and properties of the object may not function. When you call these methods you may get a response that the object has been disposed.

Workaround for the Extension Object Disposal Problem - To get around this problem, use PowerShell to instantiate the .Net objects directly. This was possible with SharePoint 2007. When doing this, the object and the disposal should be contained in a single line of PowerShell (one thread). Here is an example of the threading model in practice:

PS> [Guid]$featureId="6d44695f-ca99-4c27-9b6b-2a39c62357a1"
PS>
$site=new-object Microsoft.SharePoint.SPSite("http://server/sitecollection"); site.RootWeb.Features[$featureId];$site.Dispose()

This example can be used to show the version of a particular feature. I have used this a lot while studying the new feature upgrade capabilities in SharePoint 2010. Upgrade is a subject for another time.

Finding the Right Cmdlet – Microsoft has yet to publish the PowerShell documentation for the SharePoint extension. It is possible to dig the list of Cmdlets from looking at the SharePoint API documentation. I find it easier to just play with them in PowerShell. I use the following help function to make it easier to find the Cmdlets I need. You can put this in your PowerShell profile.ps1 file to make it available.

function findhelp([string]$part)
{
help > c:\temp\helpjunk.txt
$lookingFor = ".*" + $part + ".*"
cat c:\temp\helpjunk.txt where {$_ -match $lookingFor}
}

Tuesday, November 3, 2009

New VS Import WSP Project Speeds SharePoint 2010 Development

In SharePoint 2010, site templates are now saved as a WSP files. In addition, the new SharePoint tools for Visual Studio 2010 allow the contents of a WSP to be selectively imported. This allows the developer to quickly setup new SharePoint content using the SharePoint web UI or SharePoint Designer 2010. When the developer has gotten as far as possible with the SharePoint web UI or SharePoint Designer 2010, the structure can be imported into Visual Studio to add customization. The approach has saved me a great deal of time.

Here is how to do it:

1) Do as much design right in the SharePoint web UI and SharePoint Designer as possible until ready to transfer the work to Visual Studio.

2) Click on the Site Actions in the upper left hand of the sites root page. Select Site Settings from the drop down.


3) Under the heading Site Actions click on Save site as template

4) The Save Site as Template page should appear

a. Enter the File name for the template. Do not add the “.wsp” to the name as it will be added automatically later at download.

b. Add the Template name and Template description.

c. If custom pages have been created select the Include Content option. Custom pages created in the web UI or SharePoint Designer and placed them in Document libraries can be saved with the library by selecting this option. Note that selecting this option also includes a lot of other content data that may generate more cleanup work when importing into Visual Studio.

d. Click OK to save the template

5) Once the site template has been saved it will appear in the User Solution Gallery (at the site collection level). This is the location where the new SharePoint 2010 Sandbox Solutions are loaded and deployed. Upon completion, click on the link provided to the user solution gallery.

6) At the user solution gallery, do not activate the template. It is only passing through this location on its way to Visual Studio. Download the template simply by clicking its name

7) Start Visual Studio 2010. Click on New Project…

8) In the Installed Templates pain on the left select Visual C#->SharePoint->2010. Then select Import SharePoint Solution Package. Enter the name and location and then click OK.


9) At the prompt for the template file, browse and select the WSP file.

10) VS gives the opportunity to select what components within the WSP that are desired to be import into the project. This is where the real power of the tool lies. It is possible to import as little as a single field or list definition, or as much as the entire site template. If selectively importing only a portion of the WSP, it may take several tries to get the right combination of components to satisfy component dependencies. In general, if customizing on top of a common template such as Team Site parts like the common column definitions need not be imported, only the custom columns. Also, as far as I can tell, the property bags associated with the objects would rarely be needed.

11) After import there will be a project with a number of features and modules and other SharePoint components. The import makes no attempt to manage component dependency. Turning around to build and deploy the new project may not work. Check the packaging to ensure that components are deployed in the correct order to satisfy any dependencies. This can take some time if there are a lot of lookup fields defined in the project.

This approach lends itself to what I call the minimize costs methodology for SharePoint:
  • Customize in the SharePoint Web UI to the maximum extent possible.
  • Then, customize in SharePoint Designer to the maximum extent possible.
  • Finally, turn to Visual Studio for anything that could not be handled in the previous two approaches.

Monday, November 2, 2009

SharePoint 2010 Development Is Now Public

With the coming public release of SharePoint 2010 Beta 2 and the publication of development information by Microsoft, I can now restart the SharePoint Developer Tip of the Day. I have been working with SharePoint 2010 for a number of months and will start sharing some of the leanings through this blog again.

The Microsoft documentation for developing with SharePoint 2010 can be found at:

http://msdn.microsoft.com/en-us/sharepoint/ee514561.aspx

What do I think are the most exciting features for SharePoint 2010

My goal is to keep the tips I will present here practical and to the point.

Tuesday, June 16, 2009

Solution Feature Upgrading and Versioning

Managing features between releases of a SharePoint 2007 solution is tricky business.  Here are some considerations I have gleamed from recent upgrade issues:

·         Do not remove features from one version of a solution to another.  In theory you can remove a feature if it is deactivated on all sites and systematically uninstalled.  Practically I find this problematic, many features are so wound into the many systems it just is not practical.  Microsoft states that feature removal from a solution is not supported (see table below).

·         When adding new features to a site (web scope), use feature stapling to add them to the site templates.

·         For existing features that will be upgraded, update the Version tag on with your feature.xml.  This is not used in SharePoint 2007, but it will be in a future version.

·         Never add additional functionality to a SPFeatureReceiver on subsequent versions.  An existing deployment has already activated the feature receiver.  New sites will execute the new functionality and exiting sites will not.  Any additional setup that business logic is relying upon will not exist for existing sites.

·         Provide a path for activating the new features on existing deployed sites.  If your new solution contains 10 new features that are site collection (site scoped) or site (web scoped), these features will not be active on any existing sites of content database.  After you have installed your new solution into the farm it is necessary to activate these missing features.  This can be done in a couple of ways:

o    If you have written an external installer, you can have it systematically upgrade the previous sites and site collections throughout the farm (assuming proper permissions). 

o   You can add a single Farm level upgrade feature that auto activates and activates the missing features (assuming you can get the correct permissions).

o   You can add a site or site collection level feature that will go out and activate the missing features for that site collection or site.  This allows site owners to upgrade their sites piecemeal.  On caveat of this approach is that your entire business logic for your new solution must be able to function when these new features are missing.

Here are some recommendations from Microsoft. The following table was taken from Microsoft’s Feature Upgrading document:

Feature

Supported

Adding new files and removing old files in a new version of the solution.

Yes

Adding new Features in a new version of the solution.

Yes

Removing old Features in a new version of the solution

No

Changing the ID and/or scope of old Features in a new version of the solution.

No

Updating or changing the receiver assembly of old Features in a new version of the solution.

Yes

Adding or changing Feature elements or element XML files in a new version of the solution.

Yes

Removing Feature elements or element XML files in a new version of the solution.

No

Adding or changing Feature properties in a new version of the solution.

Yes

Removing Feature properties in a new version of the solution.

No

 

Monday, April 20, 2009

Programmatically Activating Features just after Deployment

There are a variety of scenarios where features need to be programmatically activated just after a solution has been deployed.  I have found that even when the SPSolution object says it has been deployed, it really isn’t finished deploying.  Sometimes my SPFeatureDefinitions are either non existents or not installed even when the deployment is “done”.  They eventually do show up. Until they do, feature activation fails when the feature is added to the SPFeatureCollection of the SPFarm, SPWebApplication, SPSite, or SPWeb.  I ended up coding a small bit of code to work around this problem.  This example shows activation of a web application scope feature, but the algorithm can be applied to a feature of any scope.

private void ActivateWebApplicationFeature(Uri webApplicaitonUri, Guid featureId, int timeoutSeconds)
{
    const int sleepTime = 1000;
    for (int i = 0; i < timeoutSeconds; i++)
    {
        try
        {
            SPFeatureDefinition definition = SPFarm.Local.FeatureDefinitions[featureId];
            if (definition.Status == SPObjectStatus.Online)
            {
                break;
            }
            Thread.Sleep(sleepTime);
        }
        catch
        {
            Thread.Sleep(sleepTime);
        }
    }
    SPWebApplication application = SPWebApplication.Lookup(webApplicaitonUri);
    if (application.Features[featureId] == null)
    {
        AddWebApplicationFeature(webApplicaitonUri, featureId);
    }
}

private void AddWebApplicationFeature(string webApplicaitonUri, Guid featureId)
{
    int count = 0;
    while (true)
    {
        try
        {
            SPWebApplication application = SPWebApplication.Lookup(webApplicaitonUri);
            application.Features.Add(featureId);
            application.Update();
            break;
        }
        catch (SPDeletedConcurrencyException)
        {
            // Done. This object is gone so we are finished.
            // Optional logging of condition
            break;
        }
        catch (SPUpdatedConcurrencyException)
        {
            count++;
            if (count > 10)
            {
                throw;
            }
        }
    }
}

The algorithm is to first wait for the feature definition to appear.   When looking up the SPFeatureDefinition in the SPFeatureDefinitionCollection an exception will be thrown until the definition has been added.  The code waits a second between checks.  It continues waiting for the SPFeatureDefinition to install.  Finally it activates the feature if the feature needs activation (in certain upgrade scenarios the feature may already be active).  You will notice that the second method uses my technique to control SPDeletedConcurrencyException and SPUpdatedConcurrencyException

Wednesday, April 15, 2009

Best Practices for SharePoint Solutions

Here are my personal requirements that I use for applications built on SharePoint.  I think they embody many of the best practices.

Applications should be SharePoint Solutions

·         Each application should be self contained in a single SharePoint solution .wsp file.

o   Including all DLL’s to GAC

o   Including all SafeControls

o   Including all Templates

o   Including all Features

o   Including all List and Item Schema

·         Including all WebServices  and HttpHandlers for data communication

·         Solutions should be deployable (SharePoint’s concept of an internal install) to a new Web Application or one or more existing Web Applications.

·         Solutions should not be global to the farm (SharePoint has the concept of a global solution deployment) as this prevents multiple versions of the same solution from coexisting on the farm.

·         Solutions must be visible in the Farm Solution Manager so they may be retracted from the SharePoint farm.

·         Solutions should properly clean up themselves upon a Solution retraction.

·         Solutions must play friendly with third party applications

o   Unique ID’s on all objects

o   Unique namespace within file store

o   Never override or modify built in items

o   Smart about web application configuration

·         Solution version to version compatibility must be maintained

o   If the site template needs to be upgraded

§  Never change ID or site template (no delete)

§  Add a new site template into the system with the new functionality

§  Preserve all old template definitions

·         there may be existing site content built on this template

·         there may be customer customized site templates built on this template

·         PTC partners may have built their own templates on top of existing templates

§   Mark old template definitions as hidden so that customers are discouraged from using old site definitions

§  Feature staple new features to old site definitions to add new features to previously installed sites

o   If a list definition needs to be upgraded

§  Never change ID or  remove a list definition (no delete)

·         Never remove a content type

§  add a new list definition into the system with the new functionality

§  Preserve all old list definitions

·         They may have been customized and migration is impossible without loss of customization

§  Mark old list definitions as hidden so that customers are discouraged from using old list definitions

§  Repurpose the Microsoft’s SharePoint Upgrade Schema system to upgrade old lists to new lists

o   If a feature definition needs to be upgraded

§  Never change ID or remove a feature definition (no delete)

§  Do not remove any existing element definitions

o   If a administrative object needs to be upgraded

§  Should maintain deserialization between versions

§  Override the Upgrade method in the SPPersistedObject to perform self upgrade

§  Detect old status (when deserialized) and implement the NeedsUpgrade property

§  Maintain all API’s from version to version (no delete on API)

 

Monday, April 13, 2009

Deployment of ASP Resources

Resource files referenced directly in ASP pages must exist in the App_GlobalResources of your IIS instance (each IIS instance on each farm machine) to be available to your ASP code. The real question is how do you get your resources there?  I am aware of four main solutions.

1)      The SPWebApplicationBuilder copies items in from the 12 hive directory 12\CONFIG\Resources to the App_GlobalResources at the time of web application creation.  You can place resources into this directory with global solution deployment (assuming SPSolution.ContainsWebApplicationResource = false for your SPSolution).  Now these resources will be available to all new web applications created.  This limits your solution to use on only new web applications.

2)      You can place your resources into the 12 hive directory 12\CONFIG\Resources during deployment of any solution and then call “stsadm -o copyappbincontent”.  It works great.  This has the side effect of updating the App_GlobalResources of all Web Applications on the farm from the 12 hive CONFIG directory.  Some in the SharePoint community suggest that this is like using a sledge hammer to drive a pin in place.  It may have negative impacts upon other web applications.

3)      You can create a SPJobDefinition that copies the ASP resources to the App_GlobalResources and provision the job definition from a SPFeatureReceiver or SPWebProvisioningProvider .  The scope of the feature should match the scope of the ASP code that the resources support. 

4)      The final option is to not use .resx references in your ASP pages.  Instead build properties on code behind objects with properties that then reference back to imbedded resource files.  In this solution you must deploy the resource DLL’s instead of dealing with the coping of .resx files to the App_GlobalResources directory.

I have seen examples of people using all of these approaches.

Friday, April 3, 2009

SharePoint Designer 2007 is Now Free

Microsoft just announced that the SharePoint Designer 2007 is now free. This is a great little tool for customizing site templates and changing look and feel. It has some other nice features. One of the most useful for the developer is the ability to quickly copy and modify ASP Pages.

When modifying the base SharePoint ASP pages, I recommend adding any additional code into the ASPX file only. I do not recommend referencing the Microsoft.SharePoint.ApplicaitonPages.dll directly in any .cs file. This will cause a DLL load problem in any process other than the w3wp. So if you include such a reference in your DLL and wish to push work to the SPTimerService or custom SPWindowsService, the DLL will not load. That is because the Microsoft.SharePoint.ApplicationPages.dll is found only in _app_bin of a web application.

As Microsoft is pushing the use of SharePoint Designer 2007 (by making it free), any application you create may become the victim of this tool. Your templates should be robust enough to handle this type of modification and redeployment and your ASP pages should be well documented with comments if you want Designer users not to render your application useless.

Thursday, April 2, 2009

Uniquely Name Features

For SharePoint Features deployed into the 12 hive at the root of the feature directory it is necessary to remember that the name of your feature must be unique. The 12 hive feature (12\Templates\Features) directory is a global namespace and your feature directory should not trample another third party feature. I recently had to explain this to a developer who was provisioning “SearchWebPart” a feature with a very generic name.

My recommendation is to use the following naming convention for your feature directory: CompanyApplicaitonFeaturename. By doing this you will avoid colliding with other features deployed by other solutions running in the SharePoint farm.

Wednesday, April 1, 2009

Who is "The Farm Administrator"

New SharePoint developers can often be confused about farm administration.  In the Central Administration -> Operations -> Update Farm Administrators there are a list of users who are farm administrators.  These users are farm administrators but they are not “The Farm Administrator.”  This is actually a wrapper on the local operating system group WSS_ADMIN_WPG which has the description: “Members of this group have write access to system resources used by Windows SharePoint Services.” The group exists locally on each server in the farm and the Central Administration application propagates changes to all servers in the farm.

If you wish to know who is “The Farm Administrator” you need to look at the local group WSS_RESTRICTED_WPG.  This group has the description: “Group for the Windows SharePoint Services farm administrator.” Normally this group contains one and only one user.  This should be the same user that was entered in “Specify Database Access Account” in the “Advanced” SharePoint configuration path.  It is also the same user used for the Central Administration Application Pool  as well as the Timer Service process. Any time a SharePoint object is updated by this user will be marked as changed by “SHAREPOINT\system”. This is “The Farm Administrator.” For the “Basic” SharePoint configuration path this user is always NT AUTHORITY\NETWORK SERVICE. This user is called the “Server farm account” in Microsoft’s Office SharePoint Server security account requirements document.

There is an erroneous perception amongst new SharePoint programmers that this user is all powerful.  This is not quite true.  Here are the facts.

Does “The Farm Administrator” have operating system administration rights on each of the SharePoint servers? NO. If configured correctly (for best security) this user has no power outside of the SharePoint domain.

Does “The Farm Administrator” have read and write rights on all site collections in SharePoint? NO. If configured correctly (for best security) this user does not have direct access to business data. That access has been delegated to the site collection administrators.  There are several methods of indirect access (1) (2), but there is no assumption that any farm administrator can simply ask for any Site or Web in the system.

There is one last group worth mention in this article.  The local WSS_WPG group which has the description: “Members of this group have read access to system resources used by Windows SharePoint Services.” The process users who run SharePoint services are added to this group.  This includes the web application pool users as well as any windows service that SharePoint oversees.

 

Tuesday, March 31, 2009

How to Run WSS 3.0 or MOSS on Vista or XP64

Microsoft designed WSS and MOSS to run on Windows Server 2003 or Windows Sever 2008.  This restriction is enforced by the installer.  The creative people at Bamboo Solutions have created a installer wrapper for WSS and MOSS which runs on Windows Vista x32 and x64 or Windows XP x64. The full instructions for this install are found here.

The limitations appear to be:

1)      It is not supported by Microsoft.  This means some things may not actually work correctly.  As I pointed out in my article about WindowsIdentity impersonation, some operating system API calls are only supported in Windows Server 2003 and Windows Server 2008. So spurious errors may occur.

2)      IIS on Windows Vista Home Premium only supports Basic Authentication. 

3)      The installer supports only install in farm (not single server) mode as web front end.

4)      Because it is in farm mode, an external SQLServer must be provided.

I tried this out at home and it works.  There are some curious features to my home installation.  First I do not have a domain controller so the entire system runs on local users and basic authentication.  I am an administrator in both SQLServer and on my machine so I just used myself as the Farm Administrator process users.  The result is that everything I do in SharePoint is shown as being done by System Account (SHAREPOINT/system).  I was able to add other local users to my Document Sharing site though. I would suggest that anyone considering doing this for either development or a home office, create separate local users as suggested in the Office SharePoint Server security account requirements.

The other obvious problem is using SQLExpress for the database.  Since SharePoint stores document blobs, after a while the Document Sharing site is likely to be full.

Overall though, I think I prefer my Windows Server 2008 x32 box for development.  With MSDN membership there is no reason not to go with Windows Server 2008, SQLServer 2008, MOSS 2007 SP1, VS 2008, and VSeWSS 1.3.  But if you have a zero budget operation, this looks like it might be a good way to enter SharePoint development.

 

Monday, March 30, 2009

Activate-Once Hidden Farm Features

To create a dependent farm feature that is hidden and will activate only once, use a resource-hidden feature.  I explained Friday that hidden features automatically deactivate when the last feature dependent upon the hidden feature deactivates and that resource-hidden features do not.  So using a resource-hidden feature the feature does not deactivate.

The problem is that resource-hidden features do not automatically activate in the activation tree.  The solution for farm level features is to set the attribute ActivateOnDefault=”true” in the feature element API.  This will activate your farm level feature on deployment. Here is the feature.xml for the SPFeatureDefinition:

<?xml version="1.0" encoding="utf-8"?>
<Feature xmlns="http://schemas.microsoft.com/sharepoint/"
         Id="C595997F-F3DD-4677-82CF-02AF9FB73451"
         Title="$Resources:Resource_hidden_feature_DO_NOT_LOCALIZE"
         Description="$Resources:Resource_hidden_feature_DO_NOT_LOCALIZE"
         RequireResources="true"
         Hidden="false"
         Scope="Farm"
         ActivateOnDefault="true"
         ReceiverAssembly="My.Receiver.Assembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8d63fadacc3f6a0e"
         ReceiverClass="My.Receiver.RunOnceFarmFeatureReceiver">
</Feature>

In this example the code in the SPFeatureReceiver is run only once at initial SPSolution.Deploy.  The feature is resource-hidden so users cannot see it and will not deactivate it from the Central Administration UI.  The feature also will not be deactivated by any features which depend on this feature.   The feature will only be deactivated prior to uninstall.

Thursday, March 26, 2009

Resource-Hidden Features can have ActivationDependencies

What is a resource-hidden feature?  It is a feature that is hidden from the user using a loophole in the SPFeatureDefinition API that is intended to show locale specific features.

Basically the feature element API says that the attribute RequireResources=”true” will prevent a feature from appearing in the GUI feature list if a resource file for the locale cannot be found.  A resource-hidden feature exploits this by providing no resources for any locales. Here is what the feature.xml looks like:

<?xml version="1.0" encoding="utf-8"?>
<Feature xmlns="http://schemas.microsoft.com/sharepoint/"
         Id="C595997F-F3DD-4677-82CF-02AF9FB73451"
         Title="$Resources:Resource_hidden_feature_DO_NOT_LOCALIZE"
         Description="$Resources:Resource_hidden_feature_DO_NOT_LOCALIZE"
         RequireResources="true"
         Hidden="false"
         Scope="Site">
  <ActivationDependencies>
    <ActivationDependency FeatureId="0D7EE02B-F92F-4ed2-97F7-349AEC1E0517" />
    <ActivationDependency FeatureId="5730DE72-D669-4fc7-9EA1-BC50826EF575" />
    <ActivationDependency FeatureId="C3BAA93D-B3DE-424c-850A-E19253068473" />
  </ActivationDependencies>
</Feature>

You might ask why would you use a resource-hidden feature instead of a regular hidden feature with the attribute Hidden=”true”?  Simply because the two have different behaviors:

·         Activation – Hidden features auto-activate in the feature dependency chain. Resource-hidden features do not.

·         Deactivation – Hidden features which are dependent features, deactivate when the last feature depending upon them deactivates. Resource-hidden features do not.

·         Dependency  Tree – Hidden features cannot have any ActivationDependencies. Resource-hidden features can.

Remember resource-hidden features cannot be seen in the UI and do not auto-activate so they must be programmatically activated by adding them to a SPFeatureCollection.

Tuesday, March 24, 2009

10 Best Practices

If you have not already done so.  Read “10 Best Practices For Building SharePoint Solutions” by E. Wilansky, T. Stojecki, P. Olszewski and S. Kowalewski that just came out in this month’s MSDN Magazine.  This is a great article that covers a lot of basic ground on designing SharePoint applications and how to partition them.  It has many great references.

Monday, March 23, 2009

Using WindowsIdentity.Impersonate in SharePoint applicatons

Linking legacy code to your SharePoint application can pose several issues.  One of these issues is how to run the code as the correct user.  When threads enter your business logic through IIS and SharePoint they already impersonate the user connecting to the Web Application.  Threads in the SPTimerService run as the timer service process user. Threads in your custom SPWindowService run as the service process user that you have specified.  Getting your thread to assume the right WindowsIdentity can be a challenge.

WindowsIdentity.Impersonate should not be used as a method to access SPSite objects in pure non-legacy SharePoint applications.  That should be done by passing an SPUserToken object into the SPSite constructor.  Still legacy code may require the change in WindowsIdentity and glue code may access the SPSite object to communicate data back into SharePoint.  There are two steps to accomplishing this. 

First convert the SPUser to a WindowsIdentity. To accomplish this, create the user principal name (UPN) for the user.  Then instantiate a new WindowsIdentity using the UPN.

private static string GetUpn(SPUser spUser)
{
    string[] tmp = spUser.LoginName.Split('\\');
    System.DirectoryServices.ActiveDirectory.Domain domain =
        System.DirectoryServices.ActiveDirectory.Domain.GetCurrentDomain();
    return tmp[1] + "@" + domain.Name;
}
.
.
.
SPUser spUser = GetMySPUser();
WindowsIdentity spUserIdentity = new WindowsIdentity(GetUpn(spUser));

Restrictions: This approach will only work when the user is actually a member of the Domain.GetCurrentDomain.  Otherwise you need to search for the domain name through the active directory service. Also this approach will only work if the process user has the local security policy “Act As Part of the Operating System” = “true”.  By default the NT Authority\Network Service user has this privilege. Additionally the WindowsIdentity instantiation is also restricted to the Server 2003 or Sever 2008 operating systems, but so is SharePoint.

Next perform the impersonation.

WindowsImpersonationContext context = spUserIdentity.Impersonate();
try {
    MyLegacyData data = ExecuteLegacyLogic();
    using (SPSite site = new SPSite(mySiteId))
    {
        using (SPWeb web = site.OpenWeb(myWeb)
        {
            AddLegacyDataResults( web, data );
        }
    }
}
finally
{
    context.Undo();
}

Notes: In the above block the SPSite object access is the same as if were performed using new SPSite(mySiteId, spUser.UserToken).

Restrictions: Never run this code block inside a SPSecurity.RunWithElevatedPrivileges delegate.  This appears to be unsupported by SharePoint.  The resulting SPSite and SPWeb objects will be unusable.  In this condition, a StackOverflowExcetion will be thrown if you attempt to access an SPUser in the SPWeb.Users collection and will bring down the entire process.

Outside of the above restriction, the code appears to work as expected.

Friday, March 20, 2009

How to create a new user for an SPWeb

It seems that if a user needs to be added to a SPWeb object one should just call SPWeb.Users.Add. Unfortunately, this does not work and you will get an exception.  To add a user correctly you need to define the users access rights. This is most easily done using the predefined roles.  Here is a small foreign method that does the job correctly.

private void AddUser(SPWeb web, SPRoleType roleType, string login, string email, string name, string notes)
{
    SPRoleDefinition roleDefinition = web.RoleDefinitions.GetByType(roleType);
    SPRoleAssignment roleAssignment = new SPRoleAssignment(login, email, name, notes);
    roleAssignment.RoleDefinitionBindings.Add(roleDefinition);
    web.RoleAssignments.Add(roleAssignment);
}

Remember to always get SPRoleDefinition objects using the SPRoleDefinitionCollection.GetByType method and never using the [string] indexer.  The indexer takes the localized name of the role. Using a string like “Viewer” will work in English but will not in any other language. SPRoleType is an enumeration that is locale independent.

Monday, March 9, 2009

SharePoint uses action states in SPObjectStatus

An action state is a state that indicates that an action is being performed.  The SPObjectStatus used by the SPPersistedObject.Status has three such states Provisioning, Unprovisioning, and Upgrading this allows SPPersistedObjects to undergo long running operations.  Here is a quick summary of all the states:

Name

Meaning

Details

Disabled

OFF

New or fully removed object

Online

ON

Object fully setup

Provisioning

Action State

Moving to ON

Unprovisioning

Action State

Moving to OFF

Upgrading

Action State

Changing object versions

Offline

FAILED

Your dead

One of the major misconceptions with new SharePoint developers is that ON and OFF are really Online and Offline, but they are not. ON and OFF are represented by Online and Disabled.  Offline has the same meaning it does in SQLServer. Your object is dead beyond use.  This is data corruption, hardware failure, network failure, etc.

SharePoint maps the Provisioning and Unprovisioning states differently depending on the object.  Here are some examples:

Object

Provisioning

Unprovisioning

SPWindowsServerInstance

Starting

Stopping

SPSolution

Deploying

Retracting

SPDatabase

Creating

Dropping

It is best practice to code any custom SPPersistedObjects to set the Provisioning and Unprovisioning action states correctly.  Particularly if your Provision and Unprovision methods are long running.