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.