Archive for June, 2008

Packaging Branding and Themes for Deployment in SharePoint Environments

Posted in Sharepoint Server, Windows Sharepoint Services on June 26th, 2008 by Alonso Robles – 1 Comment

Last week, a colleague asked me to conduct a presentation for some colleagues to discuss best practices concerning SharePoint branding and themes. The presentation was not meant to teach anyone how to create master pages, page layouts, cascading style sheets, or write web pages, but rather, how to package branding and themes for deployment in SharePoint environments As such, I did my homework and demonstrated some approaches in a two hour virtual meeting last night. The purpose of this post is to recap the approaches and practices and provide a reference to the sample Visual Studio 2008 projects that were generated during the session.

Packaging SharePoint Themes

SharePoint themes are an interesting feature in SharePoint that allow site owners to quickly change the appearance of colors, icons, and images buy injecting an additional style sheet that overrides some of the existing styles found in the core.css style sheet. Creating a custom theme involves a couple of simple steps:

  1. Creating a new folder in the 12/TEMPLATE/THEMES directory
  2. Creating a theme.css file to override the out of the box styles defined in the core.css style sheet in the directory created in the previous step
  3. Creating a mossExtension.css file which is appended to theme.css file to create a the actual style sheet that is actually used when viewing pages in the SharePoint site
  4. Creating a <directory name>.inf file that contains some basic setup information about the theme
  5. Adding all the images and icons referenced in the custom style sheets in step 2 and 3 to the new directory created in step 1
  6. Modifying the SPTHEMES.XML file in the 12/TEMPLATE/LAYOUTS/1033 directory

A word of caution! Modifying the SPTHEMES.XML is not a recommended customization practice since this file maybe overwritten by future SharePoint service packs.

It’s easy enough to take an existing theme directory out of the 12/TEMPLATE/THEMES directory, make a copy of it, rename the directory, rename the INF file, edit the INF, theme.css, and mossExtension.css file to create a new theme. However, this approach is not practical in a production SharePoint farm. The practical approach is to use the WSS solution framework to create our own solution package to deploy the custom theme. For more information, I covered the creation of solution packages (WSP files) in detail in a previous post. Let’s take a quick look at the solution manifest for our theme package:

<?xml version=1.0encoding=utf-8 ?>
<Solution xmlns=http://schemas.microsoft.com/sharepoint/
         
DeploymentServerType=ApplicationServer
         
ResetWebServer=TRUE
         
SolutionId=D250636F-0A26-4019-8425-A5232D592C10>
 
<TemplateFiles>
 
<TemplateFile Location=LAYOUTS/1033/SPTHEMES.XML/>
 
<TemplateFile Location=LAYOUTS/1033/OOB_SPTHEMES.XML/>
 
<TemplateFile Location=THEMES/MYNEWTHEME/MYNEWTHEME.INF/>
 
<TemplateFile Location=THEMES/MYNEWTHEME/mossExtension.css/>
 
<TemplateFile Location=THEMES/MYNEWTHEME/theme.css/>
 
<!– Additional images and icons (gif, jpg, png files)
      
can be added here using <TemplateFile> elements –>
 
</TemplateFiles>
</Solution>

The solution includes a modified SPTHEMES.XML file where we added an element to define the custom theme named MYNEWTHEME. You can also see that we included a copy of the original SPTHEMES.XML file and renamed it OOB_SPTHEMES.XML since it’s always a good idea to have back up copy of the file we modified. Finally, you see the critical MYNEWTHEME.INF, mossExtension.css, and theme.css files. For the sake of brevity, additional image and icon files were excluded on purpose.

The WSP file was then generated using a directive file and the MAKECAB utility (directive files and the MAKECAB utility are also covered in my previous post) and deployed using the STSADM utility.

Packaging Branding

There are many different SharePoint Products and Technologies branding techniques. In the presentation, I demonstrated how quickly and easily we can use a solution to deploy custom style sheets, master pages, and page layouts and how we can use a feature receiver to programmatically apply the branding using the object model. Again for the sake of brevity, the demonstration illustrated how a master page can be deployed and applied. However, a similar approach can be used for page layouts, cascading style sheets, XSL files, image files, and any other branding components and artifacts.

The solution manifest to accomplish our task is relatively basic. Here it is:

<?xml version=1.0encoding=utf-8 ?>
<Solution xmlns=http://schemas.microsoft.com/sharepoint/
         
DeploymentServerType=WebFrontEnd
         
SolutionId=A250636F-0A26-4019-8425-A5232D592C10>
 
<FeatureManifests>
 
<FeatureManifest Location=MyBranding\feature.xml/>
 
</FeatureManifests>
 <Assemblies>
  <Assembly DeploymentTarget=GlobalAssemblyCache
           
Location=CustomThemeFeature.dll />
 
</Assemblies>
</Solution>

As you can see, the solution manifest only includes a feature manifest and an assembly that will be deployed to the GAC. The assembly only contains a custom feature receiver class that programatically applies the custom master page and the custom theme discussed earlier in this post.

Let’s take a look at the feature manifest:

<Feature xmlns=http://schemas.microsoft.com/sharepoint/
        
Id=D250636F-0A26-4019-8425-A5232D592C11
        
Description=My custom master page feature.
        
Title=My Custom Branding
        
ReceiverAssembly=CustomThemeFeature, Version=1.0.0.0, PublicKeyToken=1ff5d2fddf39f61b, Culture=neutral
        
ReceiverClass=CustomThemeFeature.FeatureReceiver
        
Scope=Web>
 <ElementManifests>
 
<ElementManifest Location=elements.xml/>
  <ElementFile Location=mycustom.master/>
 </ElementManifests>
</Feature>

The feature manifest is also pretty simple as it includes one element manifest and one element file. The element file is the custom master page that was created. The element manifest will declare a module that will be used to populate the master page gallery with the custom master page. An important thing to notice here is the ReceiverAssembly and ReceiverClass attributes in the Feature element. These attributes tell the WSS solution framework to use a custom assembly and feature receiver class to handle the feature related events. We will look at the feature receiver class in a bit. First lets take a look the element manifest:

<Elements xmlns=http://schemas.microsoft.com/sharepoint/>
 
<Module Name=MasterPages
         List=116
        
Url=_catalogs/masterpage>
  <File Url=mycustom.master
        Type=GhostableInLibrary />
 </Module>
</Elements>

The element manifest is simploy responsible for populating the master page gallery with the custom master page. If our solution and feature also had custom page layouts, those can be added to the master page gallery by adding File child elements to the Module element. Additionally, we could add more modules to populate the style library with custom style sheets and/or XSL files or add other media files to other SharePoint libraries.

Finally let’s take a look at the custom feature receiver class:

using Microsoft.SharePoint;

namespace CustomThemeFeature {
 public class FeatureReceiver: SPFeatureReceiver
{
 
public override void FeatureActivated(SPFeatureReceiverProperties properties) {
  
SPWeb site = (SPWeb)properties.Feature.Parent;
  
site.MasterUrl = “/_catalogs/masterpage/mycustom.master”;
  
site.CustomMasterUrl = “/_catalogs/masterpage/mycustom.master”;
  
site.ApplyTheme(“MYNEWTHEME”);
  
site.Update();
 
}
 
public override void FeatureDeactivating(SPFeatureReceiverProperties properties) {}
  
public override void FeatureInstalled(SPFeatureReceiverProperties properties) {}
  
public override void FeatureUninstalling(SPFeatureReceiverProperties properties) {}
 
}
}

The class simply takes advantage of the feature activated event and to set the values of the master pages and apply a theme to the SPWeb object where the feature is activated.

Similar to the custom theme discussed earlier in this post, a WSP solution file was created using a directive file and the MAKECAB utility. The solution was then deployed with the STSADM utility. The feature was installed with the STSADM utility as well.

Upcoming Los Angeles SharePoint User Group Meeting – June 17, 2008

Posted in Sharepoint Server, Windows Sharepoint Services on June 13th, 2008 by Alonso Robles – Be the first to comment

The Los Angeles SharePoint User Group (LASPUG) will be having their monthly meeting this coming Tuesday, June 17th, 2008 at 6:30 PM. The meeting is virtual so make sure you mark your calendars and attend regardless of where you are.

The meeting agenda includes two presenters:

  • Dan Kruger from Quest Software will be giving us an over view of Quest’s Development Studio for SharePoint.
  • Jim Duncan (a former MVP), Senior SharePoint Architect of ShareSquared, will be presenting a dive into Using the Business Data Catalog from SharePoint.

More information is available at http://www.laspug.org/Lists/Events%20Calendar/DispForm.aspx?ID=10

Enabling the SharePoint Safe Mode Call Stack, Disabling Custom Errors and Enabiling Compilation Debugging

Posted in ASP.NET, Internet Information Services, Sharepoint Server, Windows Sharepoint Services on June 9th, 2008 by Alonso Robles – Be the first to comment

When developling for SharePoint, I find myself always turning on the call stack and disabiling the custom errors in my development environment. It really does help when trying to debug run-time problems. I know there a few posts out there that describe how to do this, but I figured I would repost it as a reference for myself (which you are welcome to use).

Just remember that I do this in my development environment only. I don’t recommend changing the web.config files in any other environment.

Enabling the Call Stack

Set the value CallStack attribute in the SafeMode element in the web.config file to true.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <configuration>
  ...
  <SharePoint>
   <SafeMode MaxControls="200"
             CallStack="true"
             DirectFileDependencies="10"
             TotalFileDependencies="50"
             AllowPageLevelTrace="false">
    ...
   </SafeMode>
   ...
 </SharePoint>
 ...
</configuration>

Disabling Custom Errors

Set the value of the mode attribute in the customErrors element to Off.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <configuration>
  ...
  <system.web>
   ...
   <customErrors mode="Off" />
   ...
  </system.web>
 ...
</configuration>

Enabiling Compilation Debugging

Set the value of the debug attriute in the compilation element to true.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <configuration>
  ...
  <system.web>
   ...
   <compilation debug="true">
    ...
   </compilation>
   ...
  </system.web>
 ...
</configuration>

 Putting it all together

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <configuration>
  ...
  <SharePoint>
   <SafeMode MaxControls="200"
             CallStack="true"
             DirectFileDependencies="10"
             TotalFileDependencies="50"
             AllowPageLevelTrace="false">
    ...
   </SafeMode>
   ...
 </SharePoint>
 <system.web>
   ...
   <customErrors mode="Off" />
   ...
   <compilation debug="true">
    ...
   </compilation>
   ...
  </system.web>
 ...
</configuration>

Daniel Larson’s Best Practices for Elevated Privilege in SharePoint

Posted in Sharepoint Server, Windows Sharepoint Services on June 6th, 2008 by Alonso Robles – Be the first to comment

[via Daniel Larson]

Daniel Larson, a MOSS MVP, has been ranting over the past few days about the use of the SPSecurity.RunWithElevatedPrivileges method. While I have been amused with his rants, I share his concerns and frustrations as a result of using the method in my SharePoint development experience and seeing the method abused and missused in many code reviews. Today, he posted a list of his best practices for gaining “elevated privileges” SharePoint.

Daniel Larson’s list of best practives for elevated privileges in SharePoint:

  • Avoid using SPSecurity.RunwithElevatedPrivilege to access the SharePoint object model. Instead, use the SPUserToken to impersonate with SPSite.
  • If you do use SPSecurity.RunwithElevatedPrivilege, dispose of all objects in the delegate. Do not pass SharePoint objects out of the RunwithElevatedPrivilege  method.
  • Only use SPSecurity.RunwithElevatedPrivilege to make network calls under the application pool identity. Don’t use it for elevation of privilege of SharePoint objects.
  • Always use the SPSite constructor with an SPUserToken to create an elevated privilege security context in SharePoint. To impersonate the system, use the SystemAccount.UserToken property of the current SPSite context, such as:
    var site = new SPSite(SPContext.Current.Site.ID,  SPContext.Current.Site.SystemAccount.UserToken);
  • Avoid passing SharePoint objects between different security contexts (SPSite instances), with the exception of the SPUserToken used in the SPSite ctor. An SPUser object created from SPSite A cannot (reliably) be passed to SPSite B. This can be the source of obscure bugs in production that are difficult to reproduce in development. For example, an SPUser reference created from SPContext.Current.Site cannot reliably be used in an elevated site context, as the user reference may take on a different meaning in the alternate context.
  • Never use elevated privilege to bypass security– always use it to work with security.
  • Restrict what assemblies can use elevated privilege by running in minimal trust, avoiding the GAC, and auditing any CAS policies deployed with vendor solutions.

Creating a SharePoint Solution for an InfoPath Form Template Deployment

Posted in InfoPath, Sharepoint Server on June 4th, 2008 by Alonso Robles – 10 Comments

Summary: Learn to create a WSS solution package (WSP file) to deploy an InfoPath Form template (XSN file).

Applies to: Microsoft Office SharePoint Server 2007, Microsoft Office InfoPath 2007, Microsoft Office Forms Server 2007

Introduction

InfoPath browser-enabled form template deployments are easy enough to do via the InfoPath client when the template does not require administrator approval. However even when administrator approval is not required, but the SharePoint governance plan requires script-able deployments of all InfoPath forms due to quality assurance and user acceptance testing requirements we need a mechanism to package our forms in a WSS solution package.

In this situation we are left with a few options, the easiest option is to deploy the form template using Central Administration in our development environment and then use Mark Wagner’s SharePoint Solution Exporter tool to extract the WSP file. This option is a bit limited however. The solutions generated by InfoPath Form Services after a form is uploaded using Central Administration contain a single form template and have some really unpleasant naming conventions (GUID are not pretty to look at).

Another option, and the topic of this tutorial, is to create a solution package from scratch. This option requires more work but provides more flexibility. We can include more than one form template (XSN file) per solution. We can comply with form, feature, and solution naming schemes. The following steps are required to create a solution package using this option:

  1. Create and publish an InfoPath browser-enabled from template(s)
  2. Create a solution manifest
  3. Create a feature manifest
  4. Create an element manifest
  5. Create a data description file
  6. Create and deploy the solution package (and activate the feature)

The following sub sections will discuss how to perform the steps above.

Create and Publish the InfoPath Browser-Enabled From Template

There are plenty of resources already available on how to create browser-enabled form templates and what the different types of browser-enabled form templates InfoPath Forms Services can use. So for the sake of simplicity, I will use only one form for this tutorial. The only thing that we need here is to make sure we have a published browser-enabled form template.

Follow the steps below to create a sample InfoPath Form Template:

  1. Open Microsoft Office InfoPath 2007
  2. Using the Getting Started modal dialog, click once on the Sample - Expense Report template under the Customize a Sample heading (center of the modal dialog window) and click the Design this form link under the Form tasks heading (right side of the modal dialog window)
  3. Using the application menu, select File > Publish…
  4. If the an information window appears telling you “the form template must be saved it can be published,” click the OK button and save the form template somewhere (name it something appropriate like Expense Report for example)
  5. Select the To a network location radio button and click the Next button in the Publishing Wizard
  6. Provide the Form template path and file name (I made a directory called c:\wspinfopath and saved the template there, remember the location that ou chose as we will use this location later in the tutorial) in the Publishing Wizard
  7. Provide the Form template name (I used Expense Report) and click the Next button in the Publishing Wizard
  8. Clear the text box (make it empty) and click the Next button in the Publishing Wizard
  9. If prompted about the access path, click the OK button in the alert prompt
  10. Verify the form name, publish path (remember this value), make sure the access path is empty, and the security level is not Restricted (InfoPath Forms Services does not support the Restricted security level)
  11. Click the Publish button in the Publishing Wizard
  12. Click the Close button in the Publishing Wizard
  13. Close Microsoft Office InfoPath 2007

Visit the InfoPath Developer Portal for additional InfoPath development resources. You can also download my sample published InfoPath Form Template here.

Create the Solution Manifest

In order for Windows SharePoint Services 3.0 to know what to do with a solution package (WSP file) we need to add the required meta data in the form of a solution manifest. This file must be named manifest.xml in order for WSS to find it in the package. You can use any XML or text editor to create the file. I used Visual Studio, but it really doesn’t matter.

Follow the steps below to create a solution manifest:

  1. Open your favorite XML or Text editor and create a file named manifest.xml
  2. Save the file to the publish path location of the InfoPath form template (I hope you remembered your path, mine was c:\wspinfopath) and name it manifest.xml
  3. Copy and paste the XML code sample below, save the file, and exit your XML or Text editor
<?xml version="1.0" encoding="utf-8" ?>
<Solution xmlns="http://schemas.microsoft.com/sharepoint/"
          SolutionId="39E1D478-A2BD-4B39-9842-49CA69369BFE"
          DeploymentServerType="WebFrontEnd">
  <FeatureManifests>
    <FeatureManifest Location="myInfoPathFormTemplate\feature.xml"/>
  </FeatureManifests>
</Solution>

When creating your own solution manifest, make sure you generate a new solution id. You can also download my sample solution manifest here.

Create the Feature Manifest

The steps for creating the feature manifest are identical to the steps we used to the the solution manifest with two exceptions. The exceptions are name the file something different (I use feature.xml for this tutorial) and the content that you save in it. So fire up your editor of choice and put the following XML code in the file.

<?xml version="1.0" encoding="utf-8" ?>
<Feature xmlns="http://schemas.microsoft.com/sharepoint/"
         Id="41CEE181-9440-4536-A1DA-73F41D2155B7"
         Title="My InfoPath Form Template Feature"
         Description="This feature contains the 1 InfoPath form template, but can contain more than one."
         Version="12.0.0.0"
         Scope="Site"
         DefaultResourceFile="ipfscore"
         ReceiverClass="Microsoft.Office.InfoPath.Server.Administration.XsnFeatureReceiver"
         ReceiverAssembly="Microsoft.Office.InfoPath.Server, Version=12.0.0.0,
                           Culture=neutral, PublicKeyToken=71e9bce111e9429c" >
  <ActivationDependencies>
    <ActivationDependency FeatureId="C88C4FF1-DBF5-4649-AD9F-C6C426EBCBF5"/>
  </ActivationDependencies>
  <ElementManifests>
    <ElementManifest Location="element.xml"/>
    <ElementFile Location="ExpenseReport.xsn"/>
  </ElementManifests>
  <Properties>
    <Property Key="FeatureName"
              Value="My InfoPath Form Template Feature"/>
  </Properties>
</Feature>

When creating your own feature manifest, make sure you:

  • Generate a unique id for the Id attribute of the Feature root element
  • Give your feature a meaningful title in the Title attribute of the Feature root element
  • Give your feature a meaningful description in the Description attribute of the Feature root element

There are a ton of things going on in the feature manifest. I am not going to go into the details of what each node means and what other possible attributes you can use. That topic deserves a post (or many posts) of its own. Instead, let me just point out some key points:

  • The ActivationDependencies node makes sure that InfoPath Forms Services (IPFS) is available and active before our feature is activated. IPFS is an enterprise feature and will require either an Enterprise or Internet CAL.
  • I am not sure why we need the FeatureName in the key-value property pairs in the Propertynode. I am assuming that XsnFeatureReceiver class uses it, but I have not really played with those properties.
  • The ReceiverClass and ReceiverAssemblyattributes are important so that IPFS takes the appropriate actions during the various feature events (such as the install, un-install, activate and deactivate events).
  • If you have more than one XSN file that you want to deploy with this feature, then just add additional ElementFile nodes.
  • The scope of the feature must be a site collection (yes the Site value is correct and intentional in the Scope attribute of the Featureroot element). Remember that when an InfoPath form is uploaded via Central Administration, it must then be activated to a site collection. I am not sure what would happen if a different scope is used as I have not tried it. You are welcome to give it a shot.

Like the solution manifest, you can also download my sample feature manifest here.

Create the Element Manifest

We are more than halfway done… I think. Just kidding we are almost there. The next file we need to create is the element manifest. Basically it is just like the feature manifest, but again the file name and the content of the file are a bit different. Fire up your editor… again. This file will be called element.xml.

<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Module Name="XSN" Url="FormServerTemplates" RootWebOnly="TRUE">
    <File Url="ExpenseReport.xsn"
          Name="ExpenseReport.xsn"
          Type="GhostableInLibrary"/>
  </Module>
</Elements>

You can do some interesting things with element manifests and we could spend a ton of time exploring this manifest. But we won’t because that is yet another topic that is deserving of its own post (or more). Just know that this file and its XML code are responsible for telling the WSS run-time to provision the form template to the Form Template Library in the root website of the site collection.

By the way, if you added more than one XSN file to the feature manifest because you have more than one form template to deploy with your solution, then you will want to add additional File elements for those files. There should be a one to one correlation between the form templates listed in the feature manifest and the element manifest.

I know you are expecting by now… so download my sample element manifest here if you like.

Create the Data Description File

When all is said and done, the solution package (WSP file) is just a cabinet file and is created using the MAKECAB utility. But in order for the utility to know how to create the file we have to pass it a data description file (DDF file) as an argument. The DDF file is just a plain text file with its own syntax that is pretty easy to follow. So for the last time (I promise) fire up your favorite text editor and put the following contents in it. (This file will be called wsp.ddf.)

; wsp.ddf (Alonso Robles)
.OPTION EXPLICIT     ; Generate errors
.Set CabinetNameTemplate=myInfoPathFormSolution.wsp    
.Set DiskDirectoryTemplate=CDROM ; All cabinets go in a single directory
.Set CompressionType=MSZIP ;** All files are compressed in cabinet files
.Set UniqueFiles="ON"
.Set Cabinet=on
.Set DiskDirectory1=Package
; Add Solution Manifest
manifest.xml   manifest.xml
; Add Feature Manifests
feature.xml    myInfoPathFormTemplate\feature.xml
; Add Element Manifests
element.xml    myInfoPathFormTemplate\element.xml
; Add Element Files
ExpenseReport.xsn  myInfoPathFormTemplate\ExpenseReport.xsn

You may feel overwhelmed with the contents of the DDF file. It’s okay that’s normal. You may also be wondering why I used a feature folder hierarchy in the file when we created a folder for a feature at all throughout the tutorial. And you are probably guessing that I am not going to go into the details of the DDF file in this post. And you would be right if you think I am going to tell you that the DDF file is another topic deserving its own post. What you may not know, is that I have covered the DDF file in some detail in a previous post: Creating Solution Packages for WSS 3.0 and MOSS 2007 Deployments.

Oh yeah, almost forgot… you can download my sample data description file here.

Create and Deploy the Solution Package (and Activate the Feature)

This next part is accomplished using the command line. I am going to assume that you have the MAKECAB utility installed and that you have both MAKECAB and the STSADM utility accessible via the your environment variables. If you don’t you may need to update your environment variables to make the utilities accessible (or use absolute paths) when using them. Fire up a command line window and let’s get started. Below you will find the commands that I used to build and deploy the solution package (with a few modifications to generalize the commands) followed by a brief explanation:

cd c:\wspinfopath
makecab -F wsp.ddf
stsadm -o addsolution -filename myInfoPathFormSolution.wsp
stsadm -o execadmsvcjobs
stsadm -o deploysolution -name myInfoPathFormSolution.wsp -immediate
stsadm -o execadmsvcjobs
stsadm -o activatefeature -name myInfoPathFormTemplate -url http://mymoss

Quickly reviewing the commands above, we can see that we changed our working directory to the location of the publish path of the InfoPath form template (and the solution files). Then we generate the WSP file with the MAKECAP utility. Finally, using the STSADM utility we added the solution, deployed it, and activated the feature (for more information STSADM operations see my post on the 189 STSADM Operations). 

Conclusion

This post covered how to create a WSS solution package to deploy InfoPath browser-enabled form templates. While this method may not be required for all Microsoft Office SharePoint Server 2007 or Microsoft Office Forms Server 2007 implementation, it does offer some flexibility in order to allow us to comply with solution, feature, and form template naming conventions. In addition, it provides the ability to create script-able deployments that can be uniformly applied to multiple environments.

Additional Resources

Upcoming Conferences

Posted in Sharepoint Server, Web Development, Windows Sharepoint Services on June 2nd, 2008 by Alonso Robles – Be the first to comment

Two conferences were announced last week that I want to share with you:

PDC2008 [via Andrew Connell] – Regristration for the Microsoft Professional Developers Conference 2008 is now open and is scheduled to take place in Los Angeles on October 27-30 at the Los Angeles Convention Center.

SharePoint Best Practices and Governance Conference [via Bill English] – The conference has been announced and will be taking place in Washington DC on September 15-17.

I would like to attend both of these, but I am not sure if I will be able to.