How to Set a Property Bag Key as an Indexed (Queriable via Search) Programmatically using C# Client Side Object Model (CSOM)

Sathish Nadarajan
 
Solution Architect
March 30, 2017
 
Rate this article
 
Views
2976

Recently in our projects, we are using a lot of Property Bag Values. But in some specific requirement, we were trying to Search the Property Bag from the SharePoint Keyword Query. To do that, we want the Property Bag Key to be Indexed as Queryable. That, we need to do programmatically as part of our Provisioning. Let us see, how to do that. The code is very straight forward.

Basically, we are updating a Property Bag called vti_indexedpropertykeys with the values Encoded.

 namespace Console.Office365
 {
     using Microsoft.SharePoint.Client;
     using OfficeDevPnP.Core;
     using System;
     using System.Linq;
     class Program
     {
         static void Main(string[] args)
         {
             AuthenticationManager authManager = new AuthenticationManager();
             var clientContext = authManager.GetSharePointOnlineAuthenticatedContextTenant("https://***.sharepoint.com/sites/CommunitySite/", "Sathish@******.com", "**********");
             Web web = clientContext.Web;
             clientContext.Load(clientContext.Web);
 
             clientContext.Load(clientContext.Site);
             clientContext.Load(clientContext.Site.RootWeb);
             PropertyValues properties = clientContext.Web.AllProperties;
             clientContext.Load(properties);
             clientContext.ExecuteQuery();
 
             // Get the Existing Property Bag Values from the Indexxed Property Keys
             var oldPropertyBagValue = clientContext.Web.PropertyBagContainsKey("vti_indexedpropertykeys") ? Convert.ToString(properties["vti_indexedpropertykeys"]) : string.Empty;
 
             string[] O365Properties = new string[] { "PropertyBagKey1", "PropertyBagKey2", "PropertyBagKey3"};
             
 
             string newPropertyBagValue = string.Empty;
 
             // Get the New Property Bag Values.  In our case, it is propertybagkey1, propertybagkey2 etc., 
             foreach (var propertiesString in O365Properties)
             {
                 newPropertyBagValue += Convert.ToBase64String(System.Text.Encoding.Unicode.GetBytes(propertiesString)) + "|";
             }
 
             // Add the new values to the existing ones.
             newPropertyBagValue = oldPropertyBagValue + newPropertyBagValue;
 
             // take the Unique Items.  There could be changes that a key can be repeated.  So always using Distinct.
             var distinctNewPropertyBagValue = newPropertyBagValue.Split('|').Distinct().ToArray();
 
             // Update the Property Bag Key
             properties["vti_indexedpropertykeys"] = string.Join("|", distinctNewPropertyBagValue).Trim();
 
 
             web.Update();
             clientContext.Load(web.AllProperties);
             clientContext.ExecuteQuery();
         }
     }
 }
 

Happy Coding,

Sathish Nadarajan.

Author Info

Sathish Nadarajan
 
Solution Architect
 
Rate this article
 
Sathish is a Microsoft MVP for SharePoint (Office Servers and Services) having 15+ years of experience in Microsoft Technologies. He holds a Masters Degree in Computer Aided Design and Business ...read more
 

How to do the Batch Search ExecuteQueries in SharePoint 2013 using Client Side Object Model in C#

Sathish Nadarajan
 
Solution Architect
February 26, 2016
 
Rate this article
 
Views
9265

In one of the Older Article, we saw within a WebPart, how to execute the ExecuteQueries in a Server Side Coding. Now, I met with the same kind of requirement, but the difference is, here I am executing this search from a WebAPI. Already, we saw here how to create a basic WebAPI.

Let me share the piece of code, which is straight forward. Am not explaining this method as it is a Static and does not have any other external dependencies.

 private static List<DocTopic> GetTopicDocumentCountBatch(TermCollection docTopicsTermCollection, string locationTermID, ClientContext clientContext)
         {
 //The List of KeywordQuery which will be converted as an Array later
             List<KeywordQuery> keywordQueriesList = new List<KeywordQuery>();
 //The List of QueryID which will be converted as an Array later
             List<string> queryIdsList = new List<string>();
             string contentSiteURL = Convert.ToString(ConfigurationManager.AppSettings["ContentSiteURL"]);
             Dictionary<string, string> docTopicQueryID = new Dictionary<string, string>();
 
 //Framing the Queries
             foreach (Term docTopicTerm in docTopicsTermCollection)
             {
                 KeywordQuery keywordQuery = new KeywordQuery(clientContext);
                 keywordQuery.QueryText = string.Format("(IsDocument:True OR contentclass:STS_ListItem)  Tags:#0{0} GVIDoc:[{1}] SPSiteUrl:" + contentSiteURL + " (ContentTypeId:0x010100458DCE3990BC4C658D4AB1D0CA3B9782* OR ContentTypeId:0x0120D520A808* OR ContentType:GVIarticle)", locationTermID, docTopicTerm.Name); ;
                 keywordQuery.IgnoreSafeQueryPropertiesTemplateUrl = true;
                 keywordQuery.SelectProperties.Add("ContentType");
                 keywordQuery.SelectProperties.Add("ContentTypeId");
                 keywordQuery.SelectProperties.Add("GVIDoc");
                 keywordQuery.SourceId = Guid.NewGuid();
                 keywordQueriesList.Add(keywordQuery);
                 queryIdsList.Add(Convert.ToString(keywordQuery.SourceId));
                 docTopicQueryID.Add(Convert.ToString(keywordQuery.SourceId), docTopicTerm.Name);
             }
 //Convert the KeywordQuery and QueryID into array,
             KeywordQuery[] keywordQueries = keywordQueriesList.ToArray();
             string[] queryIds = queryIdsList.ToArray();
 //Initialize the SearchExecutor
             SearchExecutor searchExecutor = new SearchExecutor(clientContext);
 //Actual use of ExecuteQueries method
             var results = searchExecutor.ExecuteQueries(queryIds, keywordQueries, false);
             clientContext.ExecuteQuery();
 //Iterating the Result Set.
             List<DocTopic> docTopicsList = new List<DocTopic>();
            if (results.Value.Count > 0)
             {
                 foreach (var result in results.Value)
                 {
                     if (result.Value[0].ResultRows.Count() > 0)
                     {
                         DocTopic docTopic = new DocTopic();
 
                         docTopic.Title = Convert.ToString(docTopicQueryID[result.Key]);
                         docTopic.Url = "[" + docTopic.Title + "]";
                         docTopic.TotalCount = result.Value[0].ResultRows.Count();
                         docTopic.VideoCount = Convert.ToString(result.Value[0].ResultRows.SelectMany(m => m).Where(k => k.Key.Equals("ContentTypeId")).Select(m => m.Value).Where(y => y.ToString().Contains("0x0120D520A808")).Count());
                         docTopic.ArticleCount = Convert.ToString(result.Value[0].ResultRows.SelectMany(m => m).Where(k => k.Key.Equals("ContentType")).Select(m => m.Value).Where(y => y.ToString().Contains("GVIarticle")).Count());
                         docTopic.DocumentCount = Convert.ToString(result.Value[0].ResultRows.SelectMany(m => m).Where(k => k.Key.Equals("ContentTypeId")).Select(m => m.Value).Where(y => y.ToString().Contains("0x010100458DCE3990BC4C658D4AB1D0CA3B9782")).Count());
 
                         docTopicsList.Add(docTopic);
                     }
                 }
             }
             return docTopicsList;
 
         }
 

Happy Coding,

Sathish Nadarajan.

Author Info

Sathish Nadarajan
 
Solution Architect
 
Rate this article
 
Sathish is a Microsoft MVP for SharePoint (Office Servers and Services) having 15+ years of experience in Microsoft Technologies. He holds a Masters Degree in Computer Aided Design and Business ...read more
 

How to call a Search API using REST using JavaScript from SharePoint Hosted App in SharePoint 2013

Sathish Nadarajan
 
Solution Architect
April 15, 2015
 
Rate this article
 
Views
22412

In this article, let us see, how to create a simple SharePoint Hosted Application and make a REST API call using the JavaScript in SharePoint 2013.

Let us go with a step by step procedures.

1. Open the Visual Studio with “Run as Administrator”

image

2. On the New Project, Select “App for SharePoint 2013”

3. Give a Site Collection on which we want to deploy our App. I would suggest, for the development purpose, Give any of the “Developer Site” template.

image

4. Select the “SharePoint Hosted” on the dropdown and select “Finish”.

5. The solution will looks like as below.

image

6. Our App is going to get launched with this Default.aspx. If you closely look at that page, there is a reference for a file called “App.Js”. Actually this is the file which we are going to do most of our Activities.

7. As all of us know, that the SharePoint Hosted App cannot use any Server Side Coding. Hence, all the coding needs to be done by using JavaScript CSOM only.

8. That’s the reason, this App.Js is getting more importance.

9. Let us open App.Js and you can find the document.ready Event readily available for us.

10. There are certain functionalities by default written to show a sample for us.

11. We are not going to use them.

12. The App.Js looks like

 'use strict';
 
 var context = SP.ClientContext.get_current();
 var user = context.get_web().get_currentUser();
 
 // This code runs when the DOM is ready and creates a context object which is needed to use the SharePoint object model
 $(document).ready(function () {
     getUserName();
 });
 
 // This function prepares, loads, and then executes a SharePoint query to get the current users information
 function getUserName() {
     context.load(user);
     context.executeQueryAsync(onGetUserNameSuccess, onGetUserNameFail);
 }
 
 // This function is executed if the above call is successful
 // It replaces the contents of the 'message' element with the user name
 function onGetUserNameSuccess() {
     $('#message').text('Hello ' + user.get_title());
 }
 
 // This function is executed if the above call fails
 function onGetUserNameFail(sender, args) {
     alert('Failed to get user name. Error:' + args.get_message());
 }
 

13. Now let me modify this App.Js as below. The Javascripts are self-explanatory.

 'use strict';
 
 var context = SP.ClientContext.get_current();
 var user = context.get_web().get_currentUser();
 var Results;
 
 // This code runs when the DOM is ready and creates a context object which is needed to use the SharePoint object model
 $(document).ready(function () {
     //getUserName();
     showToolbar();
 });
 
 function showToolbar()
 {
     $("toolbarDiv").show();
 }
 
 function executeQuery(queryTerms)
 {
     Results = {
         element: '',
         url: '',
         init: function (element) {
             Results.element = element;
             Results.url = _spPageContextInfo.webAbsoluteUrl + "/_api/search/query?querytext='" + queryTerms + "'";
         },
         load: function () {
             $.ajax({
                 url:Results.url,
                 method: "GET",
                 headers: { "ACCEPT": "application/json;odata=verbose" },
                 success: Results.onSuccess,
                 error : Results.onError
             });
         },
         onError: function (error) {
             alert(JSON.stringify(error));
         },
         onSuccess: function (data) {
 
             var results = data.d.query.PrimaryQueryResult.RelevantResults.Table.Rows.results;
 
             $("#resultsDiv").append('<table>');
 
             $.each(results, function () {
                 $("#resultsDiv").append('<tr>');
                 $.each(this.Cells.results, function () {
                     $("#resultsDiv").append('<td>' + this.Value + '</td>');
                 });
                 $("#resultsDiv").append('</tr>');
             });
 
             $("#resultsDiv").append('</table>');
 
 
             
         }
     }
 
     Results.init($("resultsDiv"));
     Results.load();
 }
 
 // This function prepares, loads, and then executes a SharePoint query to get the current users information
 function getUserName() {
     context.load(user);
     context.executeQueryAsync(onGetUserNameSuccess, onGetUserNameFail);
 }
 
 // This function is executed if the above call is successful
 // It replaces the contents of the 'message' element with the user name
 function onGetUserNameSuccess() {
     $('#message').text('Hello ' + user.get_title());
 }
 
 // This function is executed if the above call fails
 function onGetUserNameFail(sender, args) {
     alert('Failed to get user name. Error:' + args.get_message());
 }
 

14. And the Default.aspx will be like

 <%-- The following 4 lines are ASP.NET directives needed when using SharePoint components --%>
 
 <%@ Page Inherits="Microsoft.SharePoint.WebPartPages.WebPartPage, Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" MasterPageFile="~masterurl/default.master" Language="C#" %>
 
 <%@ Register TagPrefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
 <%@ Register TagPrefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
 <%@ Register TagPrefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
 
 <%-- The markup and script in the following Content element will be placed in the <head> of the page --%>
 <asp:Content ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">
     <script type="text/javascript" src="../Scripts/jquery-1.7.1.min.js"></script>
     <script type="text/javascript" src="/_layouts/15/sp.runtime.js"></script>
     <script type="text/javascript" src="/_layouts/15/sp.js"></script>
 
     <!-- Add your CSS styles to the following file -->
     <link rel="Stylesheet" type="text/css" href="../Content/App.css" />
 
     <!-- Add your JavaScript to the following file -->
     <script type="text/javascript" src="../Scripts/App.js"></script>
 </asp:Content>
 
 <%-- The markup in the following Content element will be placed in the TitleArea of the page --%>
 <asp:Content ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea" runat="server">
     Page Title
 </asp:Content>
 
 <%-- The markup and script in the following Content element will be placed in the <body> of the page --%>
 <asp:Content ContentPlaceHolderID="PlaceHolderMain" runat="server">
 
     <div>
         <p id="message">
             <!-- The following content will be replaced with the user name when you run the app - see App.js -->
             initializing...
         </p>
     </div>
 
     <div id="toolbarDiv" >
         <input type="text" style="width:200px" id="queryTerms" />
         <button onclick="executeQuery($get('queryTerms').value);return false;">Search</button>
     </div>
     <div id="resultsDiv">
 
     </div>
 </asp:Content>
 

15. With this we are ready to deployment. But before the deployment, make sure that our APP has appropriate permission to do a search. For that, on the AppManifest.xml file, the following permission level should be given.

image

DOWNLOAD THE SOURCE HERE

Happy Coding.

Sathish Nadarajan.

Author Info

Sathish Nadarajan
 
Solution Architect
 
Rate this article
 
Sathish is a Microsoft MVP for SharePoint (Office Servers and Services) having 15+ years of experience in Microsoft Technologies. He holds a Masters Degree in Computer Aided Design and Business ...read more
 

Cross Site Publishing – Managed Property and Crawled Property – Part 5

Sathish Nadarajan
 
Solution Architect
March 2, 2015
 
Rate this article
 
Views
15127

Managed Property and Crawled Property

Before diving deep into this, let us try to understand what these properties are at a high level. This will definitely help us for a better understanding.

A crawled property is content and metadata that is extracted from an item, such as a document or a URL, during a crawl. In simple, a crawled property is nothing but a metadata for a SiteColumn. It may not be handled by the developers, but with the help of a Managed Property, we can extract the metadata from Crawled Property. We cannot create the Crawled Property on our own. SharePoint will create the Crawled Property. We can create the Managed Property and Map the Managed Property to the Crawled Property. So that these Managed Properties will be used by the search queries, webparts etc.,

Now, coming to the step by step approach.

1. Let us do a Full Crawl. To do a full crawl, let me login to the Central Admin -> Search Service Application.

image

2. Click on the Content Sources. Select the Content Source and from the Context Menu, Select the “Start Full Crawl”

image

3. During the Crawl, the status will be “Crawling Full”

image

4. Wait until the Status becomes “Idle”. This means the Crawl Completed. View the logs for verification. If any error happened during the Crawl, it would have been captured on the Crawl Logs. But as of now, as we don’t have much on our farm, there is no error.

image

5. Once, the crawl completed, make sure the Crawled Property got created. For that, let us go to Central Admin -> Search Service Application-> Search Schema. Select the Crawled Property Link.

6. Search for a keyword called “Demo”. We will be able to see the following property.

image

7. Make sure that Managed Properties got created.

image

8. With this, our Managed Properties and Crawled Properties got created and mapped Properly. If the Managed Property does not created by default, then we need to create it manually using PowerShell Scripts.

9. We can use the below script to create the Managed Property.

#Get the Search SErvice Application

$cat = Get-SPEnterpriseSearchMetadataCategory –SearchApplication $searchapp –Identity $_.Category

#Get the Crawled Property First

$cp = Get-SPEnterpriseSearchMetadataCrawledProperty -SearchApplication $searchapp -name $_.CrawledPropertyName -Category $cat -ea silentlycontinue

#If the Crawled Property is not null, then go inside

if ($cp)

{

# Check whether Managed Property already exists

$property = Get-SPEnterpriseSearchMetadataManagedProperty -SearchApplication $searchapp -Identity $_.ManagedPropertyName -ea silentlycontinue

if ($property)

{

Write-Host -f yellow "Cannot create managed property" $_.ManagedPropertyName "because it already exists"

$ExistingManagedProp = "Cannot create managed property " + $_.ManagedPropertyName + " because it already exists" | out-file "$path\ExistingManagedProp.txt" -append

}

else

{

# If already not there, then create Managed Property

New-SPEnterpriseSearchMetadataManagedProperty -Name $_.ManagedPropertyName -SearchApplication $searchapp -Type $_.Type -Description $_.Description

#Get the managed Property which Just now, we created

$mp = Get-SPEnterpriseSearchMetadataManagedProperty -SearchApplication $searchapp -Identity $_.ManagedPropertyName

#Map the Managed Property with the Corresponding Crawled Property

New-SPEnterpriseSearchMetadataMapping -SearchApplication $searchapp -ManagedProperty $mp –CrawledProperty $cp

}

}

else

{

Write-Host -f Yellow "The specified crawled property " $_.CrawledPropertyName " does not exists… Please check whether you have given valid crawled property name"

$a = "The specified crawled property " + $_.CrawledPropertyName + " does not exists… Please check whether you have given valid crawled property name"| out-file "$path\CrawledPropErrorLogs.txt" -append

}

10. The Managed Property should be Retrievable, Searchable, Queryable, Refinable etc., For that, we can execute the below script.

$searchapp = Get-SPEnterpriseSearchServiceApplication

$ManagedProperty = Get-SPEnterpriseSearchMetadataManagedProperty -SearchApplication $searchapp -Identity $_.ManagedPropertyName -ea silentlycontinue

if($ManagedProperty)

{

$ManagedProperty.Searchable = $true

$ManagedProperty.Queryable = $true

$ManagedProperty.Sortable = $true

$ManagedProperty.Retrievable = $true

$ManagedProperty.Refinable = $true

$ManagedProperty.SafeForAnonymous = $true

$ManagedProperty.update()

write-host "The searchable, queryable, Sortable, Retrievable and Refinable for the managed property" $_.ManagedPropertyName "has been enabled successfully …… Done !" -fore green

}

else

{

Write-Host -f Yellow "The specified managed property " $_.ManagedPropertyName " does not exists… Please check whether you have given valid managed property name"

$a = "The specified managed property " + $_.ManagedPropertyName + " does not exists… Please check whether you have given valid crawled property name"| out-file $OutputPath -append

}

Let us see about the Enable Library as a Catalog in Part6

Happy Coding.

Sathish Nadarajan.

Author Info

Sathish Nadarajan
 
Solution Architect
 
Rate this article
 
Sathish is a Microsoft MVP for SharePoint (Office Servers and Services) having 15+ years of experience in Microsoft Technologies. He holds a Masters Degree in Computer Aided Design and Business ...read more
 

How to Update Managed Property as Searchable, Queryable, Sortable, Refinable, Retrievable in SharePoint 2013 using PowerShell

Sathish Nadarajan
 
Solution Architect
February 3, 2015
 
Rate this article
 
Views
20352

In the previous article, we saw How to create a Managed Property in SharePoint 2013 using PowerShell.

In this article, let us see how to Update Managed Property with various properties.

The script is as follows.

 $LogTime = Get-Date -Format yyyy-MM-dd_hh-mm
 $LogFile = ".UpdateManagedPropertyPatch-$LogTime.rtf"
 
 #start-transcript $logfile
 
 # Add SharePoint PowerShell Snapin
 
 
 if ( (Get-PSSnapin -Name Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue) -eq $null ) {
     Add-PSSnapin Microsoft.SharePoint.Powershell
 }
 
 $scriptBase = split-path $SCRIPT:MyInvocation.MyCommand.Path -parent
 Set-Location $scriptBase
 
 $OutputPath = $scriptBase + "" + "ManagedPropErrors.txt"
 
 
 if (test-path $OutputPath)
 {
     remove-item $OutputPath
 }
 
 
 $csvfile = $scriptBase + "" + "EditManagedProp.csv"
 Import-csv $csvfile | where {
 
 $searchapp = Get-SPEnterpriseSearchServiceApplication
 
 $ManagedProperty = Get-SPEnterpriseSearchMetadataManagedProperty -SearchApplication $searchapp -Identity $_.ManagedPropertyName -ea silentlycontinue
 
 if($ManagedProperty)
 {
     $ManagedProperty.Searchable = $true
     $ManagedProperty.Queryable = $true
     $ManagedProperty.Sortable = $true
     $ManagedProperty.Retrievable = $true
     $ManagedProperty.Refinable = $true
     $ManagedProperty.SafeForAnonymous = $true
     $ManagedProperty.update()
     write-host "The searchable, queryable, Sortable, Retrievable and Refinable for the managed property" $_.ManagedPropertyName "has been enabled successfully ...... Done !" -fore green
 }
 else
 {
     Write-Host -f Yellow "The specified managed property " $_.ManagedPropertyName " does not exists... Please check whether you have given valid managed property name"
     $a = "The specified managed property " + $_.ManagedPropertyName + " does not exists... Please check whether you have given valid crawled property name"| out-file $OutputPath -append
 }
 
 
 }
 #stop-transcript 
 

DOWNLOAD HERE

Happy Coding.

Sathish Nadarajan.

Author Info

Sathish Nadarajan
 
Solution Architect
 
Rate this article
 
Sathish is a Microsoft MVP for SharePoint (Office Servers and Services) having 15+ years of experience in Microsoft Technologies. He holds a Masters Degree in Computer Aided Design and Business ...read more
 

Leave a comment