How to read SharePoint Managed Metadata Look-up (Taxonomy Field) value using Client Object Model?

The below Console Application code explains you how to read SharePoint Managed Metadata Look-up (Taxonomy Field) value using Client Object Model.

using System;
using System.Text;
using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.Taxonomy;

namespace CSOMRnD
{
class Program
{
static void Main(string[] args)
{

using (ClientContext context = new ClientContext(“SiteURL”))
{
context.ExecutingWebRequest += new EventHandler(clientContext_ExecutingWebRequest);
context.AuthenticationMode = ClientAuthenticationMode.Default;
context.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;

List list = context.Web.Lists.GetByTitle(“ListName”);

CamlQuery query = new CamlQuery();

query.ViewXml = “pass your query”;

ListItemCollection items = list.GetItems(query);
context.Load(items);
context.ExecuteQuery();

foreach (ListItem item in items)
{
StringBuilder sb_ProductFieldValue = new StringBuilder();

TaxonomyFieldValueCollection taxProductFieldValueColl = item[“Product”] as TaxonomyFieldValueCollection;

if (taxProductFieldValueColl != null)
{
foreach (TaxonomyFieldValue taxProductFieldValue in taxProductFieldValueColl)
{
if (taxProductFieldValue.Label.Trim() != null)
sb_ProductFieldValue.Append(taxProductFieldValue.Label + “|”);
else
sb_ProductFieldValue.Append(“Empty”);
}
}
Console.WriteLine(sb_ProductFieldValue.ToString());
}
Console.ReadLine();
}
}

static void clientContext_ExecutingWebRequest(object sender, WebRequestEventArgs e)
{
e.WebRequestExecutor.WebRequest.Headers.Add(“X-FORMS_BASED_AUTH_ACCEPTED”, “f”);
}

}
}

How to use taxonomy hidden field?

Problem:

In one of our SharePoint list we have more than 10 look-up columns with managed metadata type. One fine day our UAT SharePoint site went very low and the CPU utilization in DB Servers associated with the UAT farm started increasing up to 80%. At this point of time the total number of UAT users involved in testing are only 4 to 7. We have around 25k+ terms stored under different terms sets.

Cause:
When we started investigating we found that below key points

1) CAML query calls coming from the custom pages to get managed metadata column values are the most expensive queries on the DB server side.

2) This behavior is happening only when we access those particular custom pages for the first time after an IIS reset.

We all know SharePoint will take more time when we load anything after IIS Reset. But it should not consume more CPU and get into deadlock situation.

Imagine the situation if we move this code to production with 10 to 15 concurrent users? The whole UAT SharePoint farm users and shared resources will be affected because of the CAML Query Issue after any IIS reset.

Solution:

When we approached MS, they suggested “Every taxonomy field of the item should have a hidden field together; e.g. with the Category (taxonomy) field, there should also be a hidden field named something like Category_0 (in my farm), try to use this field in the view fields instead and see if it will improve the results. The reason is that the hidden field is not a lookup field that it shouldn’t need to do any follow up queries to SQL but 1 single query should do the job. Note that the hidden field doesn’t just contain the value that it will also contain the Taxonomy ID, so after getting the value of the hidden field, you will need to parse it to extract the field value. But this should minimize the queries sending to SQL.”

When we modified our CAML queries with the hidden column, we found that the CPU utilization is not increasing and the site performance also very decent.

I am not sure is there any better way to improve this. If you have any ideas / feedback please let me know.

Important Note:
The timer job which updates the taxonomy look-up column will not update this hidden column until there is a change in the item where it is looked-up. We were informed by MS that they are working on this issue.

To validate the hidden column names, I am using SharePoint 2013 Client Browser tool

https://spcb.codeplex.com/releases/view/119035

Sample JavaScript Code

var siteUrl = ‘/’;

var listfld_Product;
var listfld_Release;

var listfld_Product_str;
var listfld_Release_str;

var Inputstr = ‘Product A’;

function retrieveInternalNames()
{
try
{
var clientContext = new SP.ClientContext(siteUrl);
var oList = clientContext.get_web().get_lists().getByTitle(‘CA_Product_Master_List’);
clientContext.load(oList);

listfld_Product = oList.get_fields().getByTitle(“Product_0”);
listfld_Release = oList.get_fields().getByTitle(“Release_0”);

clientContext.load(listfld_Product);
clientContext.load(listfld_Release);

clientContext.executeQueryAsync(function ()
{
listfld_Product_str = listfld_Product.get_internalName();
listfld_Release_str = listfld_Release.get_internalName();
retrieveListItems();

},
function (sender, args)
{
alert(‘Request failed. ‘ + args.get_message() + ‘\n’ + args.get_stackTrace());
});
}
catch (err)
{
alert(err.message);
}
}

function retrieveListItems()
{
try
{
var clientContext = new SP.ClientContext(siteUrl);
var oList = clientContext.get_web().get_lists().getByTitle(‘CA_Product_Master_List’);

var camlQuery = new SP.CamlQuery();

camlQuery.set_viewXml(“<View><ViewFields><FieldRef Name=’” + listfld_Product_str + “‘ Type=’Notes’/><FieldRef Name=’” + listfld_Release_str + “‘ Type=’Notes’/></ViewFields><Query> <Where> <BeginsWith> <FieldRef Name=’” + listfld_Product_str + “‘ /><Value Type=’Notes’>” + Inputstr + “|” + “</Value> </BeginsWith> </Where> </Query></View>”)

this.collListItem = oList.getItems(camlQuery);
clientContext.load(collListItem);
clientContext.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceeded), Function.createDelegate(this, this.onQueryFailed));
}
catch (err)
{
alert(err.message);
}
}

function onQuerySucceeded(sender, args)
{
var listItemInfo = ”;
var listItemEnumerator = collListItem.getEnumerator();
while (listItemEnumerator.moveNext())
{
var oListItem = listItemEnumerator.get_current();

var releaseArray = oListItem.get_item(listfld_Release.get_internalName()).split(‘;’);
var rleaseInfo = ”;
for (var i = 0; i < releaseArray.length; i++)
{
rleaseInfo += releaseArray[i].split(“|”)[0] + “;”
}

listItemInfo += oListItem.get_item(listfld_Product.get_internalName()).split(“|”)[0] + ‘
‘ + rleaseInfo + ‘

‘;
}
document.getElementById(‘div_Prod_Data’).innerHTML = listItemInfo;
}

function onQueryFailed(sender, args)
{
alert(‘Request failed. ‘ + args.get_message() + ‘\n’ + args.get_stackTrace());
}

_spBodyOnLoadFunctionNames.push(“retrieveInternalNames”);

O365 Custom JavaScript Injection using PowerShell

Custom action fetches an external script and includes it in the page. So at run time the script will self execute as an anonymous function.

Following are few scenarios you may need this functionality in your SharePoint Projects:

1) Override the new sub site link (https://tenant.sharepoint.com/sites/dev/_layouts/15/newsbweb.aspx) under Site Contents  with your site provisioning app URL

2) Redirect the user to specific page

3) Inject third-party JavaScript libraries such as Jquery, Knockout, AngularJs, etc.,

4) Add dynamic html (global navigation / company copy rights information on the bottom of your page) content on your sharepoint page at run time without even modifying the actual master page.

In the below example, I have explained how to inject Jquery file to one of my web. The source files can be placed in CDN / File Share / Common Location such as App Catalog.

Please feel free to change the logic as per your requirement.

Note: The logic remains same for JSOM code also.

inject_action.png

O365 / SharePoint Online – Apply Theme – CSOM & PowerShell

As you know, Web.ApplyTheme method applies a theme with the specified components to this site.

For more information refer – https://msdn.microsoft.com/en-us/library/microsoft.sharepoint.client.web.applytheme.aspx

Here fontSchemeUrl and backgroundImageUrl parameters can accept null values. But when I tried to pass $null or null or Empty String to these two parameters via PowerShell, I got the following error:

“Exception calling “ApplyTheme” with “4” argument(s): “The ‘fontSchemeUrl’ argument is invalid.”.Exception.Message”

Then i tried with Out-Null instead of $null or null or Empty String. Trust me it worked like a charm.

Actually the Out-Null cmdlet deletes output instead of sending it down the pipeline.

This is my final code.

Hope this helps.

fixed.png

 

 

Connect SharePoint Framework Apps with Office 365 Service Endpoints using Office Graph APIs

As you aware, SharePoint Framework 1.4.1 supports MSGraphClient.

MSGraphClient is used to perform REST calls against Microsoft Graph. The Microsoft Graph JavaScript client library is a lightweight wrapper around the Microsoft Graph API. This class allows developers to start making REST calls to MSGraph without needing to initialize the the MSGraph client library.

Note: Microsoft Graph API is replacing the previously released GraphHttpClient, which is now considered to be deprecated.

In this post, I am going to show you a SharePoint Framework WebPart to fetch my User Profile details using Microsoft Graph API. I consider that you have a SharePoint Framework HelloWorldWebPart WebPart, if you don’t, take a look at this article.

Note: API Management can be performed only on first release tenant.

  • Import the MSGraphClient in the HelloWorldWebPart.ts file as shown below

importgrpahclient

  • Write the following code snippet inside the render function.

render.png

  • Open the package-solution.json file and update the Graph API permission

graphapipermission

  • Update the CDN cdnBasePath parameter in write-manifests.json file as per your setup
  • Execute the gulp bundle and gulp package-solution with ship attribute to prepare the build
  • Upload the CDN files in the CDN location specified in the write-manifests.json file
  • Upload the SPPKG file in the app catalog site. As shown below, We have to approve the Microsoft Graph API permission requested by the developer in the package-solution.json.

helloworddeploy.png

  • Click Deploy
  • Open the New SharePoint Admin Center and click on API Management
  • Select the permission and approve the request

approvehelloworld.png

  • Install the HelloWorld WebPart in a SharePoint Site and add the same in a page
  • Verify if HelloWorld WebPart is printing the current user display name and mail in browser console.

Simple Watermark function for HTML Inputbox

One of the simplest way to create Watermark functionality for the HTML Input control 

<input
type=”text”
value=”Search Wiki”
name=”visitors_name”
onblur=”if(value==”) value = ‘Search Wiki'”
onfocus=”if(value==’Search Wiki’) value = ””
/>

Searching SharePoint Results from Windows Explorer using OSDX and Custom RSS File

Environment:

SharePoint 2013 Enterprise Search with Windows 7 Operating Systems

Introduction:

To understand what is a OSDX file and how to add an OSDX file as a search provider in Windows Explorer please refer the below links:

https://www.nothingbutsharepoint.com/sites/eusp/Pages/sharepoint-2010-search-locations-in-windows-7.aspx

http://technet.microsoft.com/en-us/library/ff899315(v=office.14).aspx

Problem:

When I use the OOB SharePoint RSS file to show the results in the windows explorer I was not able to map the custom managed properties to the windows attributes such as Summary,  thumbnail, etc.,

The OOB SharePoint RSS file located in the following location:

http://<Site>/_layouts/srchrss.aspx

Regarding this issue, when I approached some MVPs and Microsoft Windows Development team they replied that it is not possible to map the SharePoint managed properties with the windows explorer search result attributes.

Some of the articles are also explaining the same

http://msdn.microsoft.com/en-us/library/dd742951(v=VS.85).aspx

https://communities.netapp.com/blogs/TheSharePointGuy/2011/09/22/windows-7-sharepoint-search-connector

So what is the solution for this?

Solution:

Windows 7 is the first OS with the capability to use external search providers as federated search locations – and yes, this federated location can also be SharePoint!  In general, all search providers can be federated if it’s OpenSearch 1.0/1.1 compatible or, in other words, can provide the search results in RSS/Atom format.

So that means if I have to create my own RSS feeding file then my custom code should return the SharePoint search results in RSS/Atom format. So I started exploring what is the best way to get the search results. Then I found a interesting feature in SharePoint 2013 called “SharePoint 2013 Search REST API”. This new REST service is the best way to go in a variety of application scenarios. External Applications to SharePoint that require search functionality can also leverage this service as the endpoint for communication into the Search platform. The old search.asmx SOAP web service is marked as deprecated in SP2013, and the new Search REST service is the replacement.

Location of the Search Rest service

The Search REST service is located at the following URI: http://host/site/_api/search

See more about this from the below link

http://blogs.msdn.com/b/nadeemis/archive/2012/08/24/sharepoint-2013-search-rest-api.aspx

Using the above mentioned API I am supplying the keyword to the API and getting the XML output. From the XML output I am extracting the necessary XML Node values and populating the output in the format of RSS/Atom using the below code:

Front end Code

<%@ Page Language=”C#” AutoEventWireup=”true” CodeBehind=”SearchAppliedRSS.aspx.cs” Inherits=”SearchResultsRSS.Layouts.SearchResultsRSS.SearchAppliedRSS” ContentType=”text\xml” %>

<asp:Repeater ID=”ResultRSSRepeater” runat=”server”>

<HeaderTemplate>

<rss version=”2.0″>

<channel>

<title>Nucleus</title>

<link>Configure you site URL</link>

<description>

Nucleus Search Center Site.

</description>

</HeaderTemplate>

<ItemTemplate>

<item>

<title><%# RemoveIllegalCharacters(DataBinder.Eval(Container.DataItem, “Title”)) %></title>

<link>Item URL</link>

<description><%# RemoveIllegalCharacters(DataBinder.Eval(Container.DataItem, “Description”))%></description>

<category><%# RemoveIllegalCharacters(DataBinder.Eval(Container.DataItem, “Category”)) %></category>

<pubDate><%# RemoveIllegalCharacters(DataBinder.Eval(Container.DataItem, “LastModifiedTime”))%></pubDate>

<author><%# RemoveIllegalCharacters(DataBinder.Eval(Container.DataItem, “Author”))%></author>

</item>

</ItemTemplate>

<FooterTemplate>

</channel>

</rss>

</FooterTemplate>

</asp:Repeater>

Back end Code

protected void Page_Load(object sender, EventArgs e)

{

string keyword = Request.QueryString[“keyword”];

string query = “http://<Site Name>/_api/search/query?querytext='” + keyword + “‘&sourceid=’c9a51276-5b58-423c-88cb-a64297974cb4’&selectproperties=’Author,TCItemType,TCItemName,Description,LastModifiedTime'”;

WebRequest req = WebRequest.Create(query);

NetworkCredential myCred = new NetworkCredential(“<Admin Account User ID>”,”Password”,”Domain Name”);

req.Credentials = myCred;

WebResponse resp = req.GetResponse();

System.IO.StreamReader sr = new System.IO.StreamReader(resp.GetResponseStream());

// process response..

XDocument oDataXML = XDocument.Load(sr, LoadOptions.None);

XNamespace atom = “http://www.w3.org/2005/Atom&#8221;;

XNamespace d = “http://schemas.microsoft.com/ado/2007/08/dataservices&#8221;;

XNamespace m = “http://schemas.microsoft.com/ado/2007/08/dataservices/metadata&#8221;;

List<XElement> items = oDataXML.Descendants(d + “query”)

.Elements(d + “PrimaryQueryResult”)

.Elements(d + “RelevantResults”)

.Elements(d + “Table”)

.Elements(d + “Rows”)

.Elements(d + “element”)

.ToList();

// Extracting the values from XML..

DataTable dt = new DataTable();

dt.Columns.Add(“Title”);

dt.Columns.Add(“Author”);

dt.Columns.Add(“Category”);

dt.Columns.Add(“Description”);

dt.Columns.Add(“LastModifiedTime”);

foreach (XElement item in items)

{

DataRow dr = dt.NewRow();

//XElement xItem = item.Element(d + “Cells”).Descendants(d + “Key”).First();

foreach (XElement xItem in item.Element(d + “Cells”).Descendants(d + “Key”))

{

if (xItem.Value == “TCItemName”)

{

dr[“Title”] = xItem.Parent.Element(d + “Value”).Value;

}

else if (xItem.Value == “Author”)

{

dr[“Author”] = xItem.Parent.Element(d + “Value”).Value;

}

else if (xItem.Value == “Description”)

{

dr[“Description”] = xItem.Parent.Element(d + “Value”).Value;

}

else if (xItem.Value == “LastModifiedTime”)

{

dr[“LastModifiedTime”] = xItem.Parent.Element(d + “Value”).Value;

}

dr[“Category”] = “Teamcenter Item”;

}

dt.Rows.Add(dr);

}

// data-bind to ListView..

ResultRSSRepeater.DataSource = dt;

ResultRSSRepeater.DataBind();

}

protected string RemoveIllegalCharacters(object input)

{

// cast the input to a string

string data = input.ToString();

// replace illegal characters in XML documents with their entity references

data = data.Replace(“&”, “&amp;”);

data = data.Replace(“\””, “&quot;”);

data = data.Replace(“‘”, “&apos;”);

data = data.Replace(“<“, “&lt;”);

data = data.Replace(“>”, “&gt;”);

return data;

}

Finally instead of configuring the SharePoint OOB search RSS file, I have configured the customized RSS Feed file which I have created using the above code in the OSDX file.

How to create RSS?

http://net.tutsplus.com/tutorials/asp-net/how-to-build-an-rss-feed-with-asp-net/

Now I am able to see the results with the format I have specified in the code. Please see the below screen:

search-result-in-we