blog.scoreman.net

Archive for August, 2013

Microsoft.Office.Server.Search.Administration exceptions in Event Log

Thursday, August 22nd, 2013

If you see any of the exceptions below in the Event Viewer on your SharePoint farm make sure that you have check “This service application is the default storage location for Keywords” and “This service application is the default storage location for column specific term sets” on the Managed Metadata Service Application Proxy in your farm. There are some posts online saying that the search service account or search crawl account needs read permission on the Managed Metadata Service Application but that was not needed in my SharePoint 2013 environment.

Error message 1

The Execute method of job definition Microsoft.Office.Server.Search.Administration.CustomDictionaryDeploymentJobDefinition (ID <GUID>) threw an exception. More information is included below.

Failed to run flow Microsoft.CustomDictionaryDeployment. Correlation Id: <GUID>.

Error message 2:

The Execute method of job definition Microsoft.Office.Server.Search.Administration.QueryClassificationDictionaryUpdateTimerJobDefinition (ID <GUID>) threw an exception. More information is included below.

Unable to locate Managed Metadata Proxy which is default keyword taxonomy for SSA <GUID>

Aggregating tasks using SharePoint Search JavaScript Object Model

Wednesday, August 21st, 2013

This is a follow up post on my previous post where I showed how you could use search and REST to aggregate a user’s tasks. This example will show the same thing except I use the JavaScript Client Object Model. The example is written as a SharePoint-hosted app using Visual Studio 2012 Update 3.

For this example to Work you will have to add a reference to sp.search.js like below or you could use Script on Demand to load it JavaScript code.

<script type="text/javascript" src="/_layouts/15/sp.search.js"></script>

For simplicity all error handling has been removed from the example code. Here is how the code in App.js looks like:

'use strict';

var context = SP.ClientContext.get_current();

$(document).ready(function () {
    getCurrentUserDisplayName().then(getUserTasks).then(displayResult);
});

function getCurrentUserDisplayName() {
    var deferred = jQuery.Deferred();
    var user = context.get_web().get_currentUser();

    context.load(user);
    context.executeQueryAsync(function () { deferred.resolve(user); });

    return deferred.promise();
}

function getUserTasks(user) {
    var deferred = jQuery.Deferred();
    var currentUserDisplayName = user.get_title();

    var keywordQuery = new Microsoft.SharePoint.Client.Search.Query.KeywordQuery(context);
    keywordQuery.set_queryText("ContentTypeId:0x0108* NOT Status:Completed AND AssignedTo:" + currentUserDisplayName);
    keywordQuery.set
    var searchExecutor = new Microsoft.SharePoint.Client.Search.Query.SearchExecutor(context);
    var results = searchExecutor.executeQuery(keywordQuery);

    context.executeQueryAsync(function () { deferred.resolve(results); });

    return deferred.promise();
}

function displayResult(results) {
    var viewModel = function () {
        var self = this;
        self.tasks = ko.observableArray();

        jQuery.each(results.m_value.ResultTables[0].ResultRows, function () {
            self.tasks.push({
                title: ko.observable(this.Title),
                url: ko.observable(this.Path)
            });
        });
    };

    ko.applyBindings(new viewModel());
}

Aggregating tasks using SharePoint Search REST API

Tuesday, August 20th, 2013

This is a short example of how you can use SharePoint Search REST Search to aggregate all tasks assigned to the current user that are not set to completed. The example is a SharePoint-hosted app that makes two REST calls. The first one is for retrieving the full name of the user currently logged in. The second call is to the search API and executes the query. For this app to Work you will have to add QueryAsUserIgnoreAppPrincipal permisson.

For the filtering of all tasks, except the ones with status set to completed, to Work the crawled properties ows_Status will have to be added to the managed property Status. If you want to list all tasks regardless of status just remove “NOT Status:Completed”.

'use strict';

jQuery(document).ready(function () {
    getCurrentUserDisplayName().then(getUserTasks).then(displayResult);
});

function getCurrentUserDisplayName() {
    var url = _spPageContextInfo.webAbsoluteUrl + "/_api/web/currentuser";
    return jQuery.ajax(url, { method: "GET", headers: { "accept": "application/json;odata=verbose" } });
}

function getUserTasks(data) {
    var currentUserDisplayName = data.d.Title;
    var url = _spPageContextInfo.webAbsoluteUrl + "/_api/search/query?selectproperties='Title,Path'&querytext='ContentTypeId:0x0108* NOT Status:Completed AND AssignedTo:" + currentUserDisplayName + "'";
    return jQuery.ajax(url, { method: "GET", headers: { "accept": "application/json;odata=verbose" } });
}

function displayResult(data) {
    var viewModel = function () {
        var self = this;
        self.tasks = ko.observableArray();

        jQuery.each(data.d.query.PrimaryQueryResult.RelevantResults.Table.Rows.results, function () {
            self.tasks.push({
                title: ko.observable(getValueByKey('Title', this.Cells.results)),
                url: ko.observable(getValueByKey('Path', this.Cells.results))
            });
        });
    };

    ko.applyBindings(new viewModel());
}

function getValueByKey(key, results) {
    var postItem = jQuery.grep(results, function (e) {
        if (e.Key === key)
            return e;
    })[0].Value;

    return postItem;
}

In displayResult I’m using Knockout JavaScript library to bind the result to my UI but you are free to do whatever you you want with the result. Thanks to Cas van Lersel for the helper function getValueByKey that parses the key value pairs that are returned by SharePoint.