Wednesday, 25 November 2015

Setting up My Sites in SharePoint 2013


This article describes step-by-step process of setting up the my site infrastructure in the SharePoint Farm.
Prerequisite for setting up My Sites is having user profiles import or sync up and running. You can read more on user profiles sync in my previous article.
When this has been configured, we can start configuring my sites:
The first step us to go create (according to the best practices) own web application for hosting my sites. Go to the central administration, Application management, “Manage web applications”
01
And create a dedicated web application (sd2013:101 in my example here)
02
Now, the next step would be to create a site collection in the root of the newly created web application. You can of course create it inside some other managed path other than root, but since we have dedicated Web Application, root seems like an obvious choice.
Site Collection must have “2013” experience and use “My Site Host” template.
03
After Site Collection has been created, click on the “Managed Paths”  in the web application that you created to host My Sites.
04
Add a new managed path with wildcard inclusion. I prefer to use “my” as the My Site managed path, but you can of course pick up anything else.
05
The next thing is to check service connections for the Web Application which will host my sites. Click on the “Service Connections” button to…
06
..see if right service applications are set up.
If you choose “Custom” (instead of the “Default”) in the Edit the following group of connections drop down, select any service applications to which you want to connect the web application. The most important ones re User Profile service application, the managed metadata service application, and the Search service application.
In my case, I’ll just proceed with “default”
07
Now it’s time to set up the self service site creation. Go back to the Web application management, chose the application that you created to host My Sites, and click on the “Self Service Site Creation” button.
08
Click “On” in the “Site Collections” radio box, and enter your managed path in the “Start a Site” field (with “Prompt users to create a team site under” chosen)
09
Now, the next step is to grant users permission to create new site collections (for my sites). Click on the “Permission Policy” button in the Web Application management, with the web application which hosts the my sites selected.
10
In the”Manage Permission Policy Levels”, click on the “Add Permission Policy Level”
11
Call it however you want (“MySite Subsite Creation” in my case), and grant the “Create Subsites” permission.
12
Now, the new permission policy level should appear among other policy levels…
13
And we need to grant that policy level to the users. Click on the “Users Policy” button in the Web Application management, with the web application that you created to host My Sites selected…
14
Click on the “Add users” link…
15
From all zones…
16
And select the users which you want to have rights to create my sites. On my case, it will be “Everyone”.
17
18
Select your newly created policy level…
19
And now you should see “Everyone” with the new policy selected.
20
OK, everything has been set up and prepared so far. Now, finally, let’s set up the my sites. Go to the Central Administration –> Application Management, and select “Manage service applications”.
21
Then select the “User Profile Service Application”
22
In the “User Profile Service Application”, click on “Setup My Sites”
23
This is where you need to set up the search center, my host location (in my case – root site collection of the Web Application that serves as the host) and personal site location (managed path within the host web application – “my” in my case). Take a look at the screenshot for all the other fields (which I have used in my case):
24
The only remaining thing would be to set up the timer job for activity feed. Go to the Central Administration –> Monitoring –>Timer Job –> Review job definitions
25
Find the “User Profile Service Application – Activity Feed Job”, and set up the activity feed sync timer according to your needs.
26
timer
And, that’s it.
Go to the my site now, and you will be notified of my site creation for your self. Take care of your profile, follow people. Upload you private documents, share documents, follow documents – enjoy being social! Smile
27
28
29

Ref: http://blog.sharedove.com/adisjugo/index.php/2012/07/25/visual-guide-setting-up-my-sites-in-sharepoint-2013/

Wednesday, 12 August 2015

Feature Upgrade Issue: Deleted SPWebs : An error occurred while enumerating through a collection


Introduction

Recently I published a post about issues when upgrading Site Scope features in SharePoint. The issue was related to deleted Site Collections which were still in the recycle bin.
After resolving this issue I decided to do some testing with other deleted SharePoint objects. The next logical object type to delete was an SPWeb object.
Unfortunately further issues were found and the following section explains how they were found and the approach to resolve them.

How the Issue was Approached

The approach taken was the following:-
  • Build a Web Scoped Feature marked v1.0.0.0
  • Install the SharePoint Solution
  • Create a number of Webs and Activate the feature on those webs
  • Delete one of the Webs
  • Update the Web Scoped Feature to v2.0.0.0
  • Upgrade the SharePoint Solution to deploy the new version of the Web Scoped Feature
  • Use Install-SPFeature [FeatureName] –Force to upgrade the feature
  • Run a PowerShell command to execute the SPSite.QueryFeatures() function
The following PowerShell was run to query for Features that need to be upgraded.

$site=Get-SPSite http://sharepoint; $site.QueryFeatures("Web", $true);
The result of the script displayed the following:-
1
$site.QueryFeatures("Web",$true);  An error occurred while enumerating through a collection: Unable to access web scoped feature (Id: f41cc668-37e5-4743-b4a8-74d1db3fd8a4) because it references  a non-existent or broken web (Id: 3bd828cf-b747-4111-b888-5953b0d9aaa3) on sit e 'http://dev.itsp.local'.  Exception: System.ArgumentException: Value does not  fall within the expected range.    at Microsoft.SharePoint.SPWebCollection.get_Item(Guid id)    at Microsoft.SharePoint.SPFeatureEnumeratorBase.GetCachedWeb(SPSite site, Gu id webId, Guid featureId). At line:1 char:20 + $site.QueryFeatures >> ("Web",$true)     + CategoryInfo          : InvalidOperation: (Microsoft.Share...esultCollec    tion:SPFeatureQueryResultCollection) [], RuntimeException     + FullyQualifiedErrorId : BadEnumeration

Solution

The approach to solving this issue was not to write a workaround but to run a script which checks for deleted SPWeb objects in the site collection.
1
$site = Get-SPSite http://sharepoint; $site.RecycleBin | ?{$_.ItemType -eq "Web"};
The script will display the SharePoint Web Objects that have been deleted and are still found in the site collections recycle bin.
The deleted SPWeb objects can be removed from the recycle bin using the following PowerShell command.
1
$site = Get-SPSite http://sharepoint;  $deletedWebs = $site.RecycleBin | ?{$_.ItemType -eq "Web"}; $deletedWebs | % {$site.RecycleBin.Delete($_.Id)}
This will delete the SPWeb objects from the recycle bin and the Feature Upgrade process can continue.
Please be careful when running this script! Only run it when you know that none of the SharePoint Web sites are not needed!

Tuesday, 21 July 2015

Upgrade Site columns and content type

Ref:
http://blogs.msdn.com/b/vesku/archive/2011/07/29/webtemplate-training-materials-lab-4-upgrading-existing-sites-with-feature-versioning.aspx

Exercise 1 – Creating upgrade application page

In this exercise we will create simple application page to list features, which could be upgraded. This exercise will familiarize you to feature framework object model and how we can use that for upgrading features granularly. Notice that depending on the actual deployment, you might actually want to upgrade your features using PowerShell, not by adding this kind of additional application page to site settings page also to avoid accidental upgrades by other end users.

Task 1 – Adding custom application page to solution

1. Expand Layouts folder in the Solution Explorer
2. Right click Contoso.Intranet folder and choose Add – New Item…
3. Choose Application Page template and name it as UpgradePage.aspx
clip_image002
4. Click Add
5. Locate ContentPlaceHolder with the Id PlaceHolderMain
6. Update place holder as in the following code snipped to include two different tables
image
7. Save changes
8. Open Upgradepage.aspx.cs file under the aspx file
9. Add following using statements
image
10. Add override for CreateChildIControls method as follows below the Page_Load method · Notice that we use QueryFeatures method to query features which can be upgraded
image
11. Add following DisplayFeature method below the CreateChildControls method
image
12. Add btnUpgrade_Click event handler below DisplayFeature method

image

using System;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using System.Collections;
using System.Collections.Generic;
using System.Web.UI.WebControls;

namespace TestDWEContentType.Layouts.TestDWEContentType
{
    public partial class UpgradePage : LayoutsPageBase
    {
        protected void Page_Load(object sender, EventArgs e)
        {
        }

        protected override void CreateChildControls()
        {
            //query features, which have newer versions available
            SPFeatureQueryResultCollection features = SPContext.Current.Site.QueryFeatures(SPFeatureScope.Site, true);
            IEnumerator<SPFeature> featureEnumerator = features.GetEnumerator();
            while (featureEnumerator.MoveNext())
            {
                SPFeature feature = featureEnumerator.Current;
                DisplayFeature(tblFeaturesToUpgrade, feature);
            }
            //Query all features
            features = SPContext.Current.Site.QueryFeatures(SPFeatureScope.Site, false);
            featureEnumerator = features.GetEnumerator();
            while (featureEnumerator.MoveNext())
            {
                SPFeature feature = featureEnumerator.Current;
                DisplayFeature(tblFeatures, feature);
            }
            base.CreateChildControls();
        }

        private void DisplayFeature(Table tbl, SPFeature feature)
        {
            Label lblFeature = new Label()
            {
                Text = feature.Definition.DisplayName
            };
            Label lblFeatureVersion = new Label()
            {
                Text = feature.Definition.Version.ToString()
            };
            Label lblFeatureActiveVersion = new Label()
            {
                Text = feature.Version.ToString()
            };
            Button btnUpgrade = new Button()
            {
                Text="Upgrade",
                Enabled = feature.Version != feature.Definition.Version
            };
            btnUpgrade.Attributes.Add("FeatureID",feature.DefinitionId.ToString());
            btnUpgrade.Click += new EventHandler(btnUpgrade_Click);

            TableRow row = new TableRow();
            TableCell cell = new TableCell();
            cell.Controls.Add(lblFeature);
            row.Cells.Add(cell);
            cell = new TableCell();
            cell.Controls.Add(lblFeatureVersion);
            row.Cells.Add(cell);
            cell = new TableCell();
            cell.Controls.Add(lblFeatureActiveVersion);
            row.Cells.Add(cell);
            cell = new TableCell();
            cell.Controls.Add(btnUpgrade);
            row.Cells.Add(cell);
            tbl.Rows.Add(row);
        }

        void btnUpgrade_Click(object sender, EventArgs e)
        {
            string featureId = ((Button)sender).Attributes["FeatureID"];
            SPFeature feature = SPContext.Current.SiteFeatures[new Guid(featureId)];
            feature.Upgrade(false);
        }
    }
}


13. Right click the SPIs folder in the solution explorer and choose Add – New Folder
14. Name folder as CustomActions
15. Right click CustomActions folder and choose Add – New
16. Choose Empty template and name it as FeatureUpgradeSiteSettings and click Add
17. Update the Elements.xml file for the custom action as follows
image
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <CustomActionGroup Id="PEIntranetGroup" Description="PE specific links" Title="PF Configuration" Location="Microsoft.SharePoint.SiteSettings" ImageUrl="/_layouts/images/centraladmin_configurationwizards_48x48.png" Sequence="9999" xmlns="http://schemas.microsoft.com/sharepoint/"></CustomActionGroup>

  <CustomAction Id="PEIntranetConfigurationLink" Description="Use this functionality to review feature versions activated on the site and to upgrade features." Title="PE Feature Upgrade" GroupId="PEIntranetGroup" Location="Microsoft.SharePoint.SiteSettings" RequireSiteAdministrator="FALSE" Sequence="203" xmlns="http://schemas.microsoft.com/sharepoint/">
    <UrlAction Url="~site/_layouts/PEIntranet/UpgradePage.aspx"/>
  </CustomAction>
</Elements>


18. Update feature association for the just added custom action FeatureUpgradeSiteSettings so that it’s activated in the SiteMainResources feature
clip_image003
19. Open SiteMainResources feature and use properties window to set the version to 1.0.0.0
clip_image005
20. Right click Contoso.Intranet and choose Deploy
21. Move to address http://intranet.contoso.com
22. Move the Site Settings from the Site Actions
23. Click Site collection features under the Site Collection Administration
24. Activate Contoso.Intranet Site Main Resources feature
25. Move back to Site Settings page and ensure that the Site Collection Feature Upgrade link is present under the Contoso Configuration
image
26. Click Site Collection Feature Upgrade link is present under the Contoso Configuration to ensure that code is working properly
  • Page should list all activated features in site collection scope and their version
  • Notice that look and feel depends on which master page has been enabled for the system pages.
clip_image009

Task 2 – Updating features and content types

1. Move back to Visual Studio side
2. Expand SPIs folder, right click SiteColumns and choose Add – New Item
3. Choose Empty Element and name it as v2Fields
clip_image011
4. Update the Elements.xml as in the following code snipped
image
5. Save changes
6. Expand Features node and open up Contoso.Intranet Site Main Resources feature
7. Associate the v2Fields to Contoso.Intranet Site Main Resources feature. You can use packaging explorer to ensure the current associations.
  • This is done for new site collections, so that now added field is added automatically when new sites are created. Steps to modify existing sites will follow up later in this exercise.
clip_image012
8. Expand SPIs folder and ContentTypes folder in the solution explorer
9. Open Contract content type element.xml file and review the content – notice that our field is not present and it should not be added here either
image
clip_image014[1]Upgrading content types – what to do and what not to do?
IMPORTANT
You should NEVER EVER update content type definition which has been already deployed to any site collection. This would not result outcome you’re looking for. When we are updating existing content types, we’ll need to do two different things.
Update initial definition for new site collections – even for this, you should not update actual ContentType definition, since that would break reference to it from existing site collections. What we’ll need to do is to add some code to add newly added field to existing site collection from feature receiver.
Update existing content types – Most reliable way to do this also by using code – by adding required changes to feature upgrade method, which is called when feature is upgraded to latest version.
We’ll cover both approaches in following steps in this exercise.
10. Open Page content type element.xml file and review the content, notice hat our new field is not present and should not be added here either
image
11. Let’s start by handling upgrade scenario for existing site collections. Expand the SiteMainResources feature node and open up SiteMainResources.Template.xml file by double clicking it
clip_image013
12. Update the template file as follows, so that there’s few upgrade actions to perform, when we upgrade from previous version to newer one
  • Notice that we use one out of the box feature upgrade action and then we’ll include two custom feature upgrade actions to handle more specific updates on our existing site collection.


image
<?xml version="1.0" encoding="utf-8" ?>
<Feature xmlns="http://schemas.microsoft.com/sharepoint/">
  <UpgradeActions>
    <VersionRange EndVersion="2.0.0.0">
      <ApplyElementManifests>
        <ElementManifest Location="TestDWESiteColumns\Elements.xml"/>
      </ApplyElementManifests>
      <CustomUpgradeAction Name="AddFieldToContentType">
        <Parameters>
          <Parameter Name="FieldId">B8D4ABA4-E4D5-43B0-AEA8-B4C8B6F0AB88</Parameter>
          <Parameter Name="ContentTypeId">0x0100D35D88BD185F40439841F4381B9E82FD</Parameter>
          <Parameter Name="UpdateChilds">true</Parameter>
        </Parameters>
      </CustomUpgradeAction>     
    </VersionRange>
    <VersionRange EndVersion="4.0.0.0">
      <ApplyElementManifests>
        <ElementManifest Location="TestDWESiteColumns\Elements.xml"/>
      </ApplyElementManifests>
      <CustomUpgradeAction Name="UpdateSiteColumn">
        <Parameters>
          <Parameter Name="FieldId">B8D4ABA4-E4D5-43B0-AEA8-B4C8B6F0AB88</Parameter>
          <Parameter Name="ContentTypeId">0x0100D35D88BD185F40439841F4381B9E82FD</Parameter>
          <Parameter Name="UpdateChilds">true</Parameter>
        </Parameters>
      </CustomUpgradeAction>
    </VersionRange>
  </UpgradeActions>
</Feature>

13. Update [PAGEID] and [CONTRACTID] stamps in the just copied xml element with the proper identifiers. You can locate the ID’s from the following locations. These refer to unique identifiers of the content types in following files:
  • [PAGEID] – SPIs – ContentTypes – Page – Elements.xml
  • [CONTRACTID] – SPIs – ContentTypes – Contract – Elements.xml

clip_image014More on feature upgrade options and techniques
You can find more information on the feature upgrade options and techniques from Internet. In this case we used ApplyElementManifest first to introduce new field to site collection. After that we are using CustomUpgradeAction element to which we write the required code in following step – in this case are also using custom upgrade action to provision newly added fields to existing content type.
There’s also out of the box element for updating existing content type declaratively, but since this element have been having some issues in certain cumulative updates, it’s more reliable to use custom code, which we will include to our feature receiver. This also gives us additional change to perform additional confirmation or code validation, if needed for the code.
14. Since we will manipulate Publishign object model, we’ll need to add reference to Microsoft.SharePoint.Pulbishing.dll
15. Right click References in the Contoso.Intranet project and choose Add Reference…
clip_image015
16. Move to Browse tab and move to folder C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\ISAPI
17. Select Microsoft.SharePoint.Publishing.dll and click OK
18. Open SiteMainResources.EventReceiver.cs to see the content of the feature receiver
19. Add following override for FeatureUpgrading below FeatureDeactivating method
image
  • Notice that we place our actual business logic code for updating existing sites outside of the feature receiver, which gives us possibility to test that business logic separately without need for feature receiver deployments etc.
 public override void FeatureUpgrading(SPFeatureReceiverProperties properties, string upgradeActionName, System.Collections.Generic.IDictionary<string, string> parameters)
        {
            if (properties.Feature.Parent is SPSite)
            {
                SPWeb web = ((SPSite)properties.Feature.Parent).RootWeb;
                switch (upgradeActionName)
                {
                    case "AddFieldToContentType":
                        string fieldId = parameters["FieldId"];
                        string contentTypeId = parameters["ContentTypeId"];
                        bool updateChilds = true;
                        bool flag;
                        updateChilds = bool.TryParse(parameters["UpdateChilds"], out flag);
                        UpgradeManager.AddFieldToContentType(web, contentTypeId, fieldId, updateChilds);
                        break;
                    case "UpdateSiteColumn":
                        string sFieldId = parameters["FieldId"];
                        string sContentTypeId = parameters["ContentTypeId"];
                        bool sUpdateChilds = true;
                        bool sFlag;
                        sUpdateChilds = bool.TryParse(parameters["UpdateChilds"], out sFlag);
                        UpgradeManager.UpdateSiteColumn(web, sContentTypeId, sFieldId, sUpdateChilds);
                        break;
                }
            }
        }
20. Let’s continue by adding that required business logic to our project by right clicking Contoso.Intranet and choose Add – Folder
21. Rename newly added folder as ApplicationLogic
22. Right click ApplicationLogic folder and choose – Add Item…
23. Choose Class and name it as UpgradeManager.cs
image
24. Your solution should be looking like in following picture
clip_image002[1]
25. Open just added UpgradeManager.cs file
26. Add following using statements to file
image
27. Let’s also change the class to be static and include required business logic methods as follows
image

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Publishing;
using Microsoft.SharePoint.WebPartPages;
using System.Web.UI.WebControls.WebParts;

namespace TestDWEContentType.ApplicationLogic
{
    public static class UpgradeManager
    {
        public static void AddFieldToContentType(SPWeb web, string contentTypeId, string siteColumnId, bool updateChilds)
        {
            SPContentType type = web.ContentTypes[new SPContentTypeId(contentTypeId)];
            type.FieldLinks.Add(new SPFieldLink(web.Fields[new Guid(siteColumnId)]));
            type.Update(updateChilds, updateChilds);
        }

        public static void UpdateSiteColumn(SPWeb web, string contentTypeId, string siteColumnId, bool updateChilds)
        {
            SPField field = web.Fields[new Guid(siteColumnId)];
            field.PushChangesToLists = updateChilds;
            field.Update();
        }
    }
}


28. Before this class can be used in feature receiver, we’ll need to also add using statement for that, so let’s open SiteMainResources.EventReceiver.cs to see the content of the feature receiver
29. Add following using statements to file
image
30. Open Contoso.Intranet Site Main Resources feature in designer and use properties window to set the version to 2.0.0.0
clip_image017
31. Right click Contoso.Intranet and choose Build
  • Notice that until now we’ve only added code for handling upgrade of the existing structures, we’ll still need to ensure that if new site collections are created where this site collection scoped feature is activated, content types will match on latest requirements
32. To handle content type change requirements in proper way, let’s open SiteMainResources.EventReceiver.cs one more time. Let’s update the feature activated event as follows – notice that we add the required code for adding programmatically field to content types.
image

  • Again – just to emphasis why we did above add-in to feature activation, not on xml. This is for newly created site collections, since we should NOT be updating ContentType xml definition anymore, since we have already that used in one site collection in our environment.
33. Update [PageID] and [CONTRACTID] stamps in the just copied xml element with the proper identifiers. You can locate the ID’s from the following locations. These refer to unique identifiers of the content types in following files:
  • [PAGEID] – SPIs – ContentTypes – Page – Elements.xml
  • [CONTRACTID] – SPIs – ContentTypes – Contract – Elements.xml
23. Right click Contoso.Intranet and choose Package
  • Note. DO NOT DEPLOY PACKAGE DIRECTLY FROM VISUAL STUDIO, since we will imitate production upgrades in following steps and if you use Visual Studio, your upgrade option is not available since Visual Studio will “try to help you” and it reinstalls features using activate/deactive commands, which doesn’t happen in actual production deployments.
24. Right click Contoso.Intranet and choose Open Folder in File Explorer
25. Move to bin – debug sub folder and verify that you have compiled successful Contoso.Intranet.wsp file, which is the actual solution package to be deployed
26. Copy current path to clip board, since we need to use that in PowerShell. If you are using defined guidance, path is following - C:\StudentWebTemplate\Labs\Contoso.Intranet\Contoso.Intranet\bin\Debug
27. Open SharePoint 2010 Management Shell from Start | All Programs | Microsoft SharePoint 2010 Products
28. Run following command in the PowerShell window
  • Notice that path depends on your solution structure location


Update-SPSolution -Identity contoso.intranet.wsp -LiteralPath "C:\Student\Labs\Contoso.Intranet\Contoso.Intranet\bin\Debug\Contoso.Intranet.wsp" –GACDeployment

clip_image014[1]Upgrade or Re-deploy
In this case we used Update-SPSolution cmdlet, but you could also do retract and deploy commands in PowerShell script. Difference is that when we use update command, none of the feature installed or uninstalled methods are executed, but if you have added features to your package, those don’t get installed either.
If you use retract – deploy method, feature installed and unistalled commands will be executed and possible new features are automatically installed. Key point to notice though that both options don’t activate or deactivate features in the sites, like Visual Studio does. This is critical difference between development and production environment deployments.
29. Run command “iisreset” in the PowerShell to ensure that updated xml files will be loaded to memory
30. Open Internet Explorer and browse to site http://intranet.contoso.com
31. Make sure that front page has not been checked out – you can publish it manually before moving forward
  • This is just due the code for the feature receiver, which doesn’t have exception handling if the page has been checked out.
32. Move to Site Settings page from the Site Actions
33. Click Site Collection Feature Upgrade link under Contoso Configuration
34. Notice that the Contoso.Intranet Site Main Resources feature is listed here as possibility to upgrade
clip_image019
35. Click Upgrade button
  • This will execute the FeatureUpgrading event definitions (code and xml based configurations)
36. Refresh page by pressing [F5] and verify that feature is not anymore listed to be upgrade
clip_image021
37. Move back to Site Settings page
38. Move to Site Content Types
39. Click Contoso.Intranet – Contract and ensure that Additional details fields has been added to content type
  • You might want to verify successful update also on content type instances provisioned to existing lists, like pages list. You can do this by moving to list where content type is used and checking content type properties from list settings.
clip_image023
40. Move back to front page of the site and verify that web part was successfully added to the page
clip_image025


clip_image014[2]Upgrading features without custom application page
In this exercise we created custom application page to update feature. Depending on environment, PowerShell is much more convenient so that you have full control when upgrade is executed and nobody will upgrade features accidently just from the browser user interface.



Monday, 1 June 2015

SharePoint Search PDF Document Preview using Acrobat

How to: SharePoint Search PDF Document Preview using Acrobat

Introduction

This is what we are looking to build, a SharePoint 2013 search experience where PDFs can be previewed within Search.
pdf_preview_demo

On a recent project I built a solution which made extensive use of the SharePoint 2013 search features. Microsoft have been pushing building solutions with SharePoint 2013 and I have to say it does give a great experience in terms of performance and functionality.
One of the main reasons for selecting search based solution is that it scales and this solution needed to provide quick access to documents. The complexity was that due to the nature of the documents they each had unique security permissions. The solution stored a few hundred thousand documents, this would have been a killer for performance if using traditional data querying methods.
95% of the documents were PDFs and I thought it would be cool if we could provide a preview of the PDF in the search results. Unfortunately we didn’t have Office Web Apps and so I started to think about how I could build something similar. The preview would work in a similar way to the search visualisation for Office when Office Web Apps is available.
At the time Office Web Apps wasn’t available and so we could use its ability to view PDFs.
One of the important goals was to ensure that the solution would show the PDF preview window in the hover panel but would also fail gracefully when a user didn’t have the necessary components installed on their machine.

The solution relies on the following:-
  • SharePoint 2013
  • SharePoint Search Centre
  • Custom Display Template
  • Acrobat Reader / Acrobat
  • Acrobat Reader / Acrobat’s Web Browser Browser Plugin
  • the PDF Object JavaScript library

Adobe Acrobat Reader Pre-requisite Configuration

As mentioned we need a few pre-requisites for this solution to work.
The user must have Acrobat or Acrobat Reader installed and configured to use the PDF Web Browser plugin. You can see my previous post, which explains how to enable the PDF Web Browser plugin.
http://blog.ithinksharepoint.com/2011/02/21/open-pdf-files-from-a-document-library-in-a-new-window/
Adobe Acrobat Reader can be downloaded from: https://get.adobe.com/uk/reader/

SharePoint 2013 Setup

So the SharePoint 2013 Search configuration requires the following:-
  • custom Search Item Display Template
  • custom Search Hover Panel Display Template
  • configured Search Result Type
The Search Result type is required to actually configure search to use our custom display templates to render PDF results with our preview hover panel.
We are expecting that you are using a search centre for the sake of this blog post but the solution could be deployed into any site collection.

Setting up display templates

Lets set this thing up. We will need to have a SharePoint 2013 Visual Studio project created so that we can put the display templates into source control, plus we need to be able to deploy them too!
  • Start Visual Studio 2012 / Visual Studio 2013
  • Create a new project using the SharePoint 2013 Empty Project
  • Give it a suitable name and location
pdf_vs_newproject
  • Provide the URL to the SharePoint search centre site collection that will be used for development.
  • Choose a Sandbox Solution
  • Click Create
Once we have a Visual Studio project setup we need to create our display templates. The best way to learn is to take an existing display template and hover panel and make a new set. Display Templates are found in the master page document library. This can be found in a site collection’s root web, for example. http://sharepoint/search/_catalogs/masterpages.
Within the Master Pages document library is a sub folder called DisplayTemplates, this is where the Display Templates for the site collection are stored. I suggest that you create your own folder within this so that you can differentiate your changes from the out of the box display templates.
The deployment of display templates is a little tricky because they are made up of two parts. A display template is made up of an html file which SharePoint parses and creates a JavaScript representation of automatically. This occurs each time the .html file is saved.
Unfortunately if you deploy a Display Template via a feature the JavaScript representation is not created automatically. To get around this, I used the following process:-
As we mentioned earlier, we will create our display templates by copying an existing display template, renaming and modifying. This is achieved by the following:-
  • Browse to your SharePoint site.
  • Click on the cog icon in the top right hand section of the page. Click on Site Settings.
  • Click on display page layouts and master pages Pages link under “Look and Feel”.
  • Browse to the Display Templates folder
  • Download the following html display templates
  • Item_PDF.html and Item_PDF_HoverPanel.html
Now that we have a copy of the display templates, we need to add them to our Visual Studio project Create a new feature in Visual Studio by clicking on the Features node in the Solution Explorer window and choosing new feature.
  • Rename the feature folder to an appropriate name such as:-
    • PDFPreviewTemplateWithAcrobatimport
  • Open the new feature and fill in the feature’s information.
pdf_vs_featuredef
Next we will add a SharePoint Project Item to deploy the Display Templates.
  • Right-Click on the project and choose new item
  • From within the SharePoint project items choose the Module project item and call it something appropriate such as “PDFDisplayTemplates”
  • Drag the files into the newly created Project Item
If you cannot drag them then you are likely running Visual Studio as Administrator and you will need to copy the files into the folder created for PDFDisplayTemplates project item and then use the View All Files icon (found at the top of solution explorer) and add them by right clicking on each item and choosing “Include in Project” from the menu.
  • Next, rename the files to something appropriate, like this
    • item_pdf.html –> item_pdf_acrobat.html
    • item_pdf_hoverpanel.html –> item_pdf_acrobat_hoverpanel.html
Once you have uploaded your files into Visual Studio then we need to edit the files and configure Visual Studio to deploy the files as part of the solution by changing the file properties in Visual Studio solution explorer to change your deployment type from “No Deployment” to “Element File”.
We also need to update the display templates so that the name and description allows a user to identify the template. These descritions are modified using the metadata for the display template which isactually provided by a set of headers in the .html file.
Please see the screenshots below, we have modified the name and description to:-
  • Name: PDF Item with Acrobat
  • Description: Displays a result tailored for a Portable Document Format (PDF) document and displays a preview using Adobe Acrobat.

Before:-
pdfitem_properties_before
After:-
pdfitem_properties_after
The last step is to add the PDFObject.js file to Visual Studio so that its deployed with the solution. We could do this in a number of ways, I am going to include it within the PDF Display Template feature so that we only have to activate the one feature.

Finally I am going to clean up the the feature’s element.xml file so that it is deployed into the correct location within SharePoint, if you remember it should be deployed into the masterpage document library.
So here is the element.xml before:-
pdffeature_elementsbefore
and here is the element.xml after:-
pdffeature_elements_after
Once you have updated your display template’s name then they are ready to be deployed to SharePoint via the visual studio solution. Install your solution and activate the feature that was created.

Modifying the display templates to show PDFs

Hopefully now you have the display templates uploaded into SharePoint, though they are just copies of an existing display templates, so we’ll need to update the display template with the code to show PDFs.
Next we need to modify the contents of the display template, I have already create updated versions which you can download but to lets give you an overview of what I have changed.

Item_Pdf_Acrobat.html

This has been modified so that the line reading
1
var hoverUrl = "~sitecollection/_catalogs/masterpage/Display Templates/Search/Item_PDF_HoverPanel.js";
is updated to the use are version of the hover panel.
1
var hoverUrl = "~sitecollection/_catalogs/masterpage/Display Templates/Search/item_pdf_acrobat_hoverpanel.js";

Item_Pdf_Acrobat_HoverPanel.html

This has also been modified to update the name and description metadata elements. The entire html has been replaced and rather than explain all the changes, download the solution zip file and take a look at the file within Visual Studio.
The standout piece is the following section, which is called after the display template is rendered using the AddPostRenderCallback() function. This checks to see if the file is a pdf, and if it is will try and create the Acrobat Web Viewer window, if it fails for whatever reason the preview div is hidden.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<!--#_
AddPostRenderCallback(ctx, function()
{
var csrId = ctx.CurrentItem.csr_id;
 
if(ctx.CurrentItem.SecondaryFileExtension=="pdf")
{
try
{
var employeePDFDocument = new PDFObject({
url: $urlHtmlEncode(ctx.CurrentItem.OriginalPath),
pdfOpenParams: {
navpanes: 0,
toolbar: 0,
statusbar: 0,
view: "FitV"
}
 
}).embed($htmlEncode(id + HP.ids.viewer));
}
catch(e)
{
var viewDivId = $htmlEncode(id + HP.ids.viewer);
var viewDiv = document.getElementById(viewDivId);
if(viewDiv!=null)
{
viewDiv.style.display = 'none';
}
 
}
}
 
});
 
_#-->
Next the display templates need to be updated, I will show you the following approach which is the way that Microsoft recommend when developing display templates.
  • browse to the master page catalogue using http://sharepoint/search/_layouts/15/masterpages
  • click on the library tab in the ribbon toolbar
  • click on open in windows explorer
    • if you get an error make sure that IE is setup to include the web site in the Local Intranet zone and also if you are developing on Windows Server 2008/2012 make sure you have the Desktop Experience feature installed.
  • Once you have the windows explorer folder open you can now copy and paste the files from Visual Studio into Display Templates folder. SharePoint will take care of updating the JavaScript representation of your html file
Now we have our updated display templates we need to configure them to be used!

Configure search result: Tell SharePoint about the display templates

The approach to configuring search to use our display templates is by setting up a result type. Search Result types are the new Search Scopes but with SharePoint 2013 they also allow you to specify how each search result is displayed. This is really powerful and one of my favourite features of SharePoint 2013!
This feature allows you to have a list of search results and if a search result for example had a custom content type with custom metadata that result could be displayed differently to show that additional information.
Anyway, on to setting up the custom search result type:-
  • browse to your SharePoint search centre site collection
  • click on the cog icon and then choose site settings
  • Click Search Result Types (under Site Collection Administrator heading)
  • Click new search result type
    • Name: PDF using Acrobat
    • Sources: All Sources
    • Type of Content: PDF
    • Display Template: PDF using Acrobat
    • Tick optimize for frequent use

Lets try it out!

Deploy the solution to your SharePoint environment and add some PDF content to your SharePoint sites. Perform an incremental crawl or wait for your continuous crawl to pick up the content.
If you perform a search for  pdf, you should get some search results with the content uploaded, as you hover over the PDF search result you should get a preview of the PDF!
pdf_preview_demo

Troubleshooting the solution

Then the solution was being built then there were a couple of problems that I had. To be honest most of the issues were down to the Adobe Acrobat configuration.
Please take a look at my post Opening PDFs in a New Window and the section

Ref: http://blog.ithinksharepoint.com/2014/06/12/how-to-create-pdf-search-document-preview-using-acrobat/