Monday, August 26, 2013

SharePoint 2013 Content Search Web Part (CSWP) in Variation Sites

The Content Search Web Part (CSWP) introduced in SharePoint 2013 displays search results in a way that we can change how search results appear on a page by using display templates. Each Content Search Web Part is associated with a search query and shows the results for that search query.

Even though there is a Query Builder option provided in the edit mode of the webpart, sometimes it is necessary to set the "QueryText" attribute of the Content Search Web Part Programmatically.

In a CSWP we can limit the search results to take from current site (This site) or from site collection (This site collection). But there is no way to specify another URL or relative URL without hardcoding the server name. In my case I wanted to read data from variation top sites as all of my language dependent SPLists were residing in <site_collection>/en and <site_collection>/fr level.


Therefore I had to extend OOB CSWP and create a custom CSWP for my use. My plan was to override the QueryText from the backend.


In order to override the QueryText attribute, I had to override the BeforeSerializeToClient event. So what I’m doing is;
  1. In the “Build Your Query” screen, in the Query Text field, add the path attribute and set my own value called “CurrentVariationLabel”, in addition to the other filters.
  2. Then in the “BeforeSerializeToClient” event, replace “CurrentVariationLabel” text with current variation label.
  3. I have written a private method called “GetCurrentVariationLabel” to get the current variation label.

protected override void OnLoad(EventArgs e)
{
   if (this.AppManager != null)
   {
     if (this.AppManager.QueryGroups.ContainsKey(this.QueryGroupName) &&
        this.AppManager.QueryGroups[this.QueryGroupName].DataProvider != null)
     {          this.AppManager.QueryGroups[this.QueryGroupName].DataProvider.BeforeSerializeToClient +=
      new BeforeSerializeToClientEventHandler(UpdateQueryText);
     }
   }
   base.OnLoad(e);
}

private void UpdateQueryText(object sender, BeforeSerializeToClientEventArgs e)
{
      DataProviderScriptWebPart dataProvider = sender as DataProviderScriptWebPart;
      dataProvider.QueryTemplate = dataProvider.QueryTemplate.Replace("CurrentVariationLabel", "\"" + GetCurrentVariationLabel() +"\"");
}

private static string GetCurrentVariationLabel()
{
   VariationLabel currentVL = null;

   if (SPContext.Current != null)
   {
      string currentUrl = SPContext.Current.Web.Url;
      ReadOnlyCollection<VariationLabel> variationLabels = null;
      if (Variations.Current != null)
      {
         variationLabels = Variations.Current.UserAccessibleLabels;
      }
      if (!String.IsNullOrEmpty(currentUrl) && variationLabels != null)
      {
         foreach (VariationLabel vl in variationLabels)
         {
            if (currentUrl.StartsWith(vl.TopWebUrl, StringComparison.CurrentCultureIgnoreCase))
            {
               currentVL = vl;
            }
         }
      }
    }

    if (currentVL != null)
    {
       return currentVL.TopWebUrl;
    }           
}

With the same approach, by changing GetCurrentVariationLabel() method, I can use my custom CSWP to limit results from any other sub-site as well.

Thursday, August 15, 2013

Custom Site Definitions and Web Templates with WorkflowServiceStore and WorkflowTask Features

I was trying to setup variations in one of my SharePoint 2013 sites and I used a custom web template to create my site collection. In my web template I activated all Publishing and other features as I used to do in SharePoint 2010.

<SiteFeatures>
 <!-- Workflow Expiration -->
 <Feature ID="C85E5759-F323-4EFB-B548-443D2216EFB5" />
 <!-- DLC Workflows -->
 <Feature ID="0AF5989A-3AEA-4519-8AB0-85D91ABE39FF" />
 <!-- "A44D2AA3-AFFC-4d58-8DB4-F4A3AF053188" -->
 <Feature ID="A44D2AA3-AFFC-4d58-8DB4-F4A3AF053188" />
 <Feature ID="A392DA98-270B-4e85-9769-04C0FDE267AA">
  <!-- PublishingPrerequisites -->
 </Feature>
 <Feature ID="7C637B23-06C4-472d-9A9A-7C175762C5C4">
  <!-- ViewFormPagesLockDown -->
 </Feature>
 <Feature ID="AEBC918D-B20F-4a11-A1DB-9ED84D79C87E">
  <!-- PublishingResources -->
  <Properties xmlns="http://schemas.microsoft.com/sharepoint/">
   <Property Key="AllowRss" Value="false"/>
   <Property Key="SimplePublishing" Value="false" />
   <Property Key="EnableModerationOnDocuments" Value="false" />
   <Property Key="EnableModerationOnImages" Value="false" />
   <Property Key="EnableModerationOnReusableContent" Value="false" />
   <Property Key="EnableSchedulingOnDocuments" Value="false" />
   <Property Key="EnableSchedulingOnImages" Value="false" />
   <Property Key="EnableApprovalWorkflowOnDocuments" Value="false" />
   <Property Key="EnableApprovalWorkflowOnImages" Value="false" />
  </Properties>
 </Feature>
 <Feature ID="F6924D36-2FA8-4f0b-B16D-06B7250180FA">
  <!-- Office SharePoint Server Publishing -->
 </Feature>
 <Feature ID="6E1E5426-2EBD-4871-8027-C5CA86371EAD">
 </Feature>
</SiteFeatures>
<WebFeatures>
 <!-- Include the common WSSListTemplateFeatures used by CMS -->
 <Feature ID="00BFEA71-DE22-43B2-A848-C05709900100" > </Feature>
 <Feature ID="00BFEA71-E717-4E80-AA17-D0C71B360101" > </Feature>
 <Feature ID="00BFEA71-52D4-45B3-B544-B1C71B620109" > </Feature>
 <Feature ID="00BFEA71-A83E-497E-9BA0-7A5C597D0107" > </Feature>
 <Feature ID="00BFEA71-4EA5-48D4-A4AD-305CF7030140" > </Feature>
 <Feature ID="00BFEA71-F600-43F6-A895-40C0DE7B0117" > </Feature>
 <Feature ID="22A9EF51-737B-4ff2-9346-694633FE4416">
  <!-- Publishing -->
  <Properties xmlns="http://schemas.microsoft.com/sharepoint/">
   <Property Key="ChromeMasterUrl" Value="~SiteCollection/_catalogs/masterpage/abc/abc_landing.master"/>
   <Property Key="DefaultPageLayout" Value="~SiteCollection/_catalogs/masterpage/PageFromDocLayout.aspx"/>
   <Property Key="WelcomePageUrl" Value="$Resources:osrvcore,List_Pages_UrlName;/home.aspx"/>
   <Property Key="PagesListUrl" Value=""/>
   <Property Key="AvailableWebTemplates" Value="*-CMSPUBLISHING#0;*-BLANKINTERNET#2;*-ENTERWIKI#0;*-SRCHCEN#0"/>
   <Property Key="AvailablePageLayouts" Value=""/>
   <Property Key="AlternateCssUrl" Value="" />
   <Property Key="SimplePublishing" Value="false" />
   <Property Key="EnableModerationOnPages" Value="false" />
   <Property Key="EnableModerationOnDocuments" Value="false" />
   <Property Key="EnableModerationOnImages" Value="false" />
   <Property Key="EnableSchedulingOnPages" Value="false" />
   <Property Key="EnableSchedulingOnDocuments" Value="false" />
   <Property Key="EnableSchedulingOnImages" Value="false" />
   <Property Key="EnableApprovalWorkflowOnPages" Value="false" />
   <Property Key="EnableApprovalWorkflowOnDocuments" Value="false" />
   <Property Key="EnableApprovalWorkflowOnImages" Value="false" />
  </Properties>
 </Feature>
 <Feature ID="541F5F57-C847-4e16-B59A-B31E90E6F9EA">
  <!-- Per-Web Portal Navigation Properties-->
  <Properties xmlns="http://schemas.microsoft.com/sharepoint/">
   <Property Key="InheritGlobalNavigation" Value="true"/>
   <Property Key="IncludeSubSites" Value="true"/>
   <Property Key="IncludePages" Value="false"/>
  </Properties>
 </Feature>
 <Feature ID="94C94CA6-B32F-4da9-A9E3-1F3D343D7ECB">
  <!-- Office SharePoint Server Publishing -->
 </Feature>   
</WebFeatures>

But my variations were failing and I could see following errors recorded in the variations log.

The Variations Create Hierarchies job failed with the following error message: Object reference not set to an instance of an object.
The variation system failed to create a new site variation for en under the en label. The field with Id {40270da4-0a34-4c14-8c30-59e065a28a4d} defined in feature {2c63df2b-ceab-42c6-aeff-b3968162d4b1} was found in the current site collection or in a subsite.

Even though the error message logged is not that clear, I came to know that SharePoint 2013 is using a new Workflow Management service to deal with Workflow related stuff and feature id mentioned in the log message is one of them called “Workflow Service Store”. I was getting this error since I didn’t activate that feature in my web template.

Solution:

Activate following Web features in the custom web template/ site definition.
<!-- Workflow Service Store -->
<Feature ID="2c63df2b-ceab-42c6-aeff-b3968162d4b1" />
<!-- Workflow Task -->
<Feature ID="57311b7a-9afd-4ff0-866e-9393ad6647b1" />