Saturday, 7 April 2012

SharePoint: Basics of Content Types

The content types are reusable collection of site columns which can have behavior (Information management policies, events, workflows), forms, document templates. It represents an item in SharePoint list or library giving a special meaning to it. They enable organizations to maintain and organize the content in consistent manner throughout their system.

The content types are of three types. viz. Site content type, list content type and enterprise content types.

Site Content Types

The content types created using declarative manner in element manifest are termed as site content types. They are created and stored in Site Content Type gallery present at root site of site collection.

Content types can be created in both declarative (in element manifest) as well as programmatic manner. Following are the steps to show how to create a custom content type in declarative fashion. This example add the site columns created in my other blog Basics of Site Columns to a custom content type named Book.

1.       In Visual Studio 2010, open the SPCustomDevelopment project created in blog post Basics of Site Columns .
2.       In Solution Explorer, right-click the Features node and then click Add Feature as shown in Figure 1.

Figure 1: Add Content Type Feature
3.       Name the feature as SPCustomDevelopment – Content Types and give appropriate description. Ensure that the feature scope is set to Site. As Site Content Type gallery in which the content type gets created is present at root web of Site collection. Hence scope of the feature creating declarative content type must be set to Site as shown in Figure 2.

Figure 2: Name the Feature
4.       Rename the Feature 1 folder to Content Types as shown in Figure 3 for better readability.

Figure 3: Rename the Feature folder
5.       In Solution Explorer, right-click the SPCustomDevelopment project, select Add, and then select New Item as shown in Figure 4. Type the name as Content Types

Figure 4: Add an Empty Element manifest
6.       Open the Elements.xml file inside Content Types project item and then replace the file content with the following code example.


  <ContentType ID="0x0100921DB927A11B42709A0C51C4A37EA816"
               Name="Book"
               Group="SharePoint 2010 Custom Development"
               Overwrite="TRUE"
               Version="0"
               >
    <FieldRefs>
      <FieldRef ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" Name="Title" Required="TRUE" DisplayName="Book Name"/>
      <FieldRef ID="{6F87C38C-5218-45D8-905E-877D694ECC31}" Name="Technology"/>
      <FieldRef ID="{52AE411D-32FB-484C-A04F-ED6C7E41A593}" Name="Publication"/>
      <FieldRef ID="{7D8A68DA-3A2D-444D-A721-1E7A6633402B}" Name="PriceOfBook"/>
      <FieldRef ID="{E93762F1-6F7E-4DFC-9161-0B3B35A7BE35}" Name="BookAuthors"/>
    </FieldRefs>
   </ContentType>


7.       Save the file.
8.       Add the Content Types project item to Content Types feature as shown in Figure 5.

Figure 5: Associate Element manifest to Feature
9.       Click on Package folder to open Package Designer. Ensure that Content Types project item is not associated with any other feature. In addition, ensure that Site Columns feature is activated first than Content Types feature.

Figure 6: Package Designer
10.   Right click the solution name and then click Deploy as shown in Figure 7. Visual Studio 2010 will build and deploy the solution to the farm/ site collection depending upon the deployment methodology selected in Step 2.

Figure 7: Build and Deploy solution
11.   VS 2010 will activate both Site Columns and Content Types feature while deployment.
12.   To check whether Book content type is properly created. Go to Site Settings at root site of local site collection. Then click Site Settings to open Site Settings page. Click on Site Content Types link present under Galleries section. Click on Book content type link to verify it is created correctly as shown in figure 8.

Figure 8: Book Content Type
 
The Book content type is inherited from Item content type. Content type inheritance is controlled by ID attribute value.  ID attribute consists of three parts as shown in below figure 9.

Figure 9: Content Type inheritance using ID property


List Content types

When any site content type is associated to the list/ library, SharePoint behind the scenes creates a new local copy of content type inherited from site content type and then attached it with the list/library. Such new copies of content type associated with list are termed as List Content types. The content type Id of list content type is different than that of site content type.

Unlike site content types which are stored in file system (SharePoint root), list content types are stored in content database. In case site content type is changed declaratively then SharePoint does not propagate those changes to list content types. However, changes made through browser or programmatically can be pushed to list content types but to be very honest I have seen even that failing couple of occasions. So recommendation is to cross check all the child list content types once the changes are propagated.

The declarative site column propagation issues are applied to content type propagation too. Hence recommendation is to create all content types required for all phases in in one go or to use Feature Upgrade concept to add new fields to existing content types. I still remember how bad this content type propagation has haunted me in past….

Below is the code to create content types programmatically. (given as image purposefully to promote recommended declarative manner of creating content type)

Figure 10: Create content type programmatically

Note that content type Id attribute generation logic  remains same as that of declarative way.


Enterprise level content types

SharePoint 2010 now supports the enterprise level content types which are created in a special site collection called as Content Type Hub. This content type syndication allows consistency of content type schema over multiple site collection through Managed Metadata Service application. The enterprise content types can be either declaratively or programmatically in Content Type Hub. Then they can be published/ unpublished/ republished to the other site collections.


Following is the criteria for deciding where you want to create content type:
  • If you want a Content Type to be available to a specific site (and its sub sites), define it in the site Content Type Gallery.
  • If you want a Content Type to be available to all sites in a Site Collection, define it in the Site Collection Content Type Gallery.
  • If you want to create a Content Type to be used across your entire farm or across multiple Site Collections (at the enterprise level), define a Site Collection to be a “Content Type hub.” The Content Type created in the hub can then be associated with each Site Collection using the Managed Metadata service. Once an enterprise Content Type is published, it can’t be changed within the local Site Collection.



Attach Event Receiver to content type

The event receiver can be attached to content type in the content type element as shown below.

   
  <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/events">
      <Receivers xmlns:spe="http://schemas.microsoft.com/sharepoint/events">
        <Receiver>
          <Name>ItemAdding</Name>
          <Type>ItemAdding</Type>
          <SequenceNumber>10000</SequenceNumber>
          <Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
          <Class>$SharePoint.Type.eb7f7632-da7a-4f4e-83cc-d1effc4a627e.FullName$</Class>
          <Data></Data>
          <Filter></Filter>
        </Receiver>
      </Receivers>
  </XmlDocument>
   

Note: Above sample make use of Replaceable Tokens in Visual Studio 2010. You can find all such tokens at http://msdn.microsoft.com/en-us/library/ee231545%28VS.100%29.aspx.



Associate Custom Forms with content type

The content type can be associated with custom list forms (application pages) using FormUrls as shown below.

   
 <XmlDocuments>
    <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms/url">
       <FormUrls xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms/url">
         <Display>_layouts/SPCustomDevelopment/BookForms/DisplayForm.aspx</Display>
         <Edit>_layouts/SPCustomDevelopment/BookForms/EditForm.aspx</Edit>
         <New>_layouts/SPCustomDevelopment/BookForms/NewForm.aspx</New>
       </FormUrls>
     </XmlDocument>
  </XmlDocuments>
 

If you have created the list forms directly in List/ Library using SharePoint Designer or as Modules, you can use them as shown below.

   
 <XmlDocuments>
    <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms/url">
       <FormUrls xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms/url">
         <Display>~list/Item/CustDisplayForm.aspx</Display>
         <Edit>~list/Item/CustEditForm.aspx</Edit>
         <New>~list/Item/CustNewForm.aspx</New>
       </FormUrls>
     </XmlDocument>
  </XmlDocuments>
 

You can also create custom form templates (.ascx) and then associate them with content type using FormTemplates as shown below.

 
 <XmlDocuments>
    <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
      <FormTemplates  xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
        <Display>BookCustomDispForm</Display>
        <Edit>BookCustomEditForm</Edit>
        <New>BookCustomNewForm</New>
      </FormTemplates>
    </XmlDocument>
  </XmlDocuments>
   

By default, SharePoint uses ListForm form template present in SharePointRoot\Template\ControlTemplates\DefaultTemplates.ascx as custom form template for most of the OOB content types.  
  


Associating workflow to content type

Workflows can be associated with the content types using AssociationCategories tag in Workflow element in element manifest file as shown below.

 
  <Workflow
     Name="Book Approval Workflow"
     Description="This workflow is used to approve the book to be published."
     Id="d827937e-0911-4230-bd8f-e1b97a8277a6"
     CodeBesideClass="SPCustomDevelopment.BookApprovalWorkflow.BookApprovalWorkflow"
     CodeBesideAssembly="$assemblyname$">
    <Categories/>
    <MetaData>
      <AssociationCategories>ContentType;0x0100921DB927A11B42709A0C51C4A37EA816</AssociationCategories>
      <StatusPageUrl>_layouts/WrkStat.aspx</StatusPageUrl>
    </MetaData>
  </Workflow>
   

Workflows can be associated with multiple content types by using ;# as separator as shown below.

 
  <Workflow
     Name="Book Approval Workflow"
     Description="This workflow is used to approve the book to be published."
     Id="d827937e-0911-4230-bd8f-e1b97a8277a6"
     CodeBesideClass="SPCustomDevelopment.BookApprovalWorkflow.BookApprovalWorkflow"
     CodeBesideAssembly="$assemblyname$">
    <Categories/>
    <MetaData>
      <AssociationCategories>ContentType;0x0100921DB927A11B42709A0C51C4A37EA816;#ContentType;0x0100DCF5DCB7D735430EB17812839250E585</AssociationCategories>
      <StatusPageUrl>_layouts/WrkStat.aspx</StatusPageUrl>
    </MetaData>
  </Workflow>
   

If just ContentType is mentioned as a value of AssociationCategories tag then workflow gets attached with all the content types.

Now finally, if you know the cure of Absent mindedness, I am in desperate need your consultation.

Saturday, 31 March 2012

Embedding Dynamic PowerPoint Decks into SharePoint 2010 page

Few hours to Earth Hour (31st March 2012, 8.30-9.30 PM) now and atmosphere has really gone cloudy and filled with pleasant smell which happens on first rain. I will take this as Mother Nature’s appreciation for Earth Hour :-)

In last week, I was trying to add PowerPoint decks to the web page in SharePoint which satisfies some criteria. There were two approaches to do so.
1.       Use Fast Search PowerPoint Preview functionality
2.       Use Office Web Apps to display the PowerPoint Deck using Page Viewer webpart or in iframe

I chose later approach as I felt it easy and quick. So I uploaded the PowerPoint Deck to a document library. Opened it using office web apps. Copied the url into clipboard. Then I added Page Viewer web part to web part page and set the url property of it to the PowerPoint Deck url in clipboard. Easy it is…but surprisingly Page Viewer web part gave an error…“This content cannot be displayed in a iframe”.

After little bit of googling, I came to know the reason. Steven Van de Craen in his blog has thrown a light on it. Excel services and Office Web Apps pages render the “X-FRAME-OPTIONS:SAMEORIGIN” response header which causes this error. Steven has also given a solution to it in his Codeplex project which removes this culprit header using HttpModule.

Even though Steven’s solution is lucrative and easy, I was not able to use it because of two reasons….
1.       It opens a gateway to Clickjacking attacks
2.       It uses HttpModule which is not allowed in the SharePoint Governance at my client place due to many valid reasons.  

Further googling, I found another blog by Sean Earp which uses the PowerPointFrame.aspx instead of PowerPoint.aspx. But unlike PowerPoint.aspx which accepts the PowerPoint deck url as query string, PowerPointFrame.aspx uses some guid which somehow points to the PowerPoint deck.

Figure 1 : PowerPoint.aspx and PowerPointFrame.aspx urls


Hence this solution is good only when your PowerPoint deck to be displayed on a page is fixed. In my case however, it was dynamic. I wanted to embed the PowerPoint deck which satisfies some criteria. So after little bit of digging, I was able to figure it out how PowerPointFrame.aspx query string guid is constructed. Here is the code snippet I used to generate the guid.


//listItem represents PowerPoint deck item in doc lib
string powerpointGuid = string.Format("F{0}m{1}m{2}m", SPContext.Current.Site.ID.ToString("N"),
SPContext.Current.Web.ID.ToString("N"),
listItem.UniqueId.ToString("N"));


Here is how my custom web part looks with PowerPoint decks. It displays the decks in iframes.

Figure 2 : My PowerPoint Deck custom webpart


You also can use this logic but beware that Microsoft can change this guid format in any of its SharePoint updates. If you are using it, don't forget to add popout=1 into the PowerPointFrame.aspx's query string. If you figure it out what is SlideId query string parameter, then please ensure that you are telling me that first.

Earth Hour has been started…Need to start mine one now

Saturday, 24 March 2012

Basics of SharePoint Features

SharePoint feature acts as container of the functionalities or customizations. These functionalities/ customizations are created either by declaratively or programmatically and can be made available or unavailable by activating or deactivating the feature.

SharePoint feature has following scopes
1.       Farm - feature contained functionality becomes available to whole farm
2.       Webapplication - feature contained functionality becomes available to the web application in which feature is activated
3.       Site  - feature contained functionality becomes available to the site collection in which feature is activated
4.       Web - feature contained functionality becomes available to the sub-site in which feature is activated

The SharePoint feature contains following type of files
1.       Feature manifest - Feature.xml
2.       Element manifest - Element.xml
3.       Element File - any other file than feature.xml and element.xml. It can be .master, .webpart, .aspx, resx, .css etc file.

Feature Manifest
The below figure shows the attributes of feature manifest file apart from UpgradeSolutions.

Figure 1 : Feature Manifest


Element Manifest
Element manifest file contains CAML definitions of various SharePoint content elements. Some of them are mentioned below.

Figure 2 : Element Manifest


Following table lists down the content elements with their purposes.

Content Element Tag
Purpose
<ContentType />
Creates content type
<ContentTypeBinding />
Binds the content type with list instance
<Control />
Adds control into the delegate controls present in master page
<CustomAction />

  • Create link at predefined SharePoint locations
  • Create buttons in ribbon
<CustomActionGroup />
Creates group for custom actions
<FeatureSiteTemplateAssociation />
Staples the features to existing site definitions
<Field />
Creates Site column
<HideCustomAction />
Hides the existing custom actions link
<ListInstance />
Creates the list instance
<ListTemplate />

Creates custom list definitions
<Module />
Uploads any file to SharePoint document libraries
<PropertyBag />
Creates property in the property bag collection for the list item, file, folder, or website
<Receivers />
Registers the SharePoint list related event
<WebTemplate />
Create feature based site template
<Workflow />
Defines custom workflow schema
<WorkflowActions />
Defines custom workflow activity
<WorkflowAssociation />
Associates the workflow with list/ content types


Few Design level considerations

1.       Feature must be scoped at appropriate level so that feature functionality is only available in desired places.
2.       In case there are multiple functionalities that need to be added through the feature, then it is better to have separate feature for each one of them so that you can individually turn on/off those through feature activation/deactivation. This will ensure one functionality is not affecting other.
e.g. Consider a feature which adds a web part to the page layout using AllUserWebpart element. Activating this feature multiple times results in multiple web part addition to the page layout. Hence if you are adding a new functionality in the same feature, you will need to deactivate/ activate it. This in turn will result in multiple web parts addition to the page layout which is undesired.
3.       The feature can be made configurable using the feature property bag collection
e.g. Suppose you want to create a feature which applies your custom master page to the site in feature receiver code. Then it is better to add a property to the feature as shown in below figure.

Figure 3 : Feature Properties

This property then can be used to apply the master page in feature receiver code

Figure 4 : Feature Receiver

4.       Feature dependencies and hidden features
Feature dependencies always work in hierarchical manner. If you make the parent feature hidden then it will get auto activated on dependent feature activation.Good read about feature dependencies here.


Feature Receiver
Feature supports following events.

    
    public class DemoEventReceiver : SPFeatureReceiver
    {
        //Raised after a feature has been activated.
        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
        }

        // Raised before a feature is deactivated.
        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        {
        }

        // Raised after a feature has been installed.
        public override void FeatureInstalled(SPFeatureReceiverProperties properties)
        {
        }

        // Raised before a feature is uninstalled.
        public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
        {
        }

        // Raised when a feature is upgrading. This event is newly added in SharePoint 2010 
        public override void FeatureUpgrading(SPFeatureReceiverProperties properties, string upgradeActionName, System.Collections.Generic.IDictionary<string, string> parameters)
        {
        }
    }




Deployment challenges

Following are the feature operations not supported in solution upgrade (stsadm upgradesolution command). 
  • Removing old Features in a new version of a solution.
  • Adding new Features in a solution upgrade.
  • Updating or changing the receiver assembly for existing Features in a new version of a solution.
  • Adding or changing Feature elements (Element.xml files) in a new version of a solution.
  • Adding or changing Feature properties in a new version of a solution.
  • Changing the ID or scope of old Features in a new version of a solution.
  • Removing Feature elements (Element.xml files) in a new version of a solution.
  • Removing Feature properties in a new version of a solution.

One can say, a simple workaround for overcoming these challenges is to retract, delete and redeploy the wsp package. But beware, there is a catch! You should before deactivate/ uninstall the features which are supposed to be removed or whose feature Ids are to be changed. Otherwise, it leaves dangling feature entries in SharePoint content database, which will give troubles especially when you are upgrading from MOSS 2007 to SharePoint 2010. You can find such dangling features either by running the stsadm preupgradecheck command or closely monitoring the SharePoint ULS logs.

Now SharePoint 2010 has brought a very interesting functionality called Feature Upgrade which comes into picture when stsadm upgradesolution command is used. It addresses some of the challenges mentioned above. Nobody explains this functionality better than The Chris Obrien in his FeatureUpgrade blog series.

The SharePoint features can be forcefully activated through stsadm/ powsershell scripts. But you should not use it unless it is must.


God…you there? ….are my prayers loud enough?