How to change the options in search drop down with CSOM

searchNavigation1

You can change the options in the drop down manually by going to Site Settings > Search > Search Settings and add or remove a link.

searchNavigation2

If you want to change the options of the drop down in the search bar, you unfortunately have to configure these for each web and not just for the root site collection. So you probably don’t want to configure it manually.

As you can’t you SSOM in SharePoint online you have to use the CSOM. You can’t access the search navigation in a “normal” way, because there is no object in CSOM for it. But you can get the search Navigation by its id (Thanks for the idea, Mikael):


public static void AddSearchNavigationNode(Web web, string title, string url)
{
var nav = web.Navigation;
NavigationNode searchNavigation = nav.GetNodeById(1040);
NavigationNodeCollection searchNavigationNodeCollection = searchNavigation.Children;
NavigationNodeCreationInformation searchNavigationNode = new NavigationNodeCreationInformation();
searchNavigationNode.Title = title;
searchNavigationNode.Url = url;
searchNavigationNode.IsExternal = true;
searchNavigationNode.AsLastNode = true;
searchNavigationNodeCollection.Add(searchNavigationNode);
web.Context.Load(searchNavigationNodeCollection);
web.Context.ExecuteQuery();
}

Please note that all the default options (Everything, People, This site) are getting removed, when adding a custom option via code.

How so set web properties within a web template

If you create a new web, based on a custom web template, you can set web properties like this:

  1. In your Visual Studio solution containing the web template, create a new module or use an existing one
  2. Paste the PropertyBag section into your module
  3. Put your module into a feature, that gets activated within your web template

    <?xml version="1.0" encoding="utf-8"?>
    <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
    <Module Name="MeetingPage">
    […]
    </Module>
    <PropertyBag Url="" ParentType="Web" RootWebOnly="FALSE">
    <Property Name="WebTemplateName" Type="string" Value="Atia-Template"/>
    </PropertyBag>
    </Elements>

In this example the Key “WebTemplateName” with Value “Atia-Template” is added to the web properties.
To check this you can use PowerShell:

$web=Get-SPWeb *your url*
$web.AllProperties

How to start a SharePoint 2013 Workflow on all list items via PowerShell

Unfortunately you can not use the same commands to start a SharePoint 2013 Workflow that you use to start a SharePoint 2010 Workflow via PowerShell.
Here’s what you’ve got to do:


$web = Get-SPWeb -Identity "http://portal.atia.com"
$wfm = New-object Microsoft.SharePoint.WorkflowServices.WorkflowServicesManager($web)
$list = $web.Lists["My List"]
$items = $list.Items
$sub = $wfm.GetWorkflowSubscriptionService()

$wfis = $wfm.GetWorkflowInstanceService()
$subscriptions = $sub.EnumerateSubscriptionsByList($list.ID)
$subscription = $subscriptions | Where-Object {$_.Name -eq 'IdeaCreated'}

#Optional step to filter list items (This example only selects the document sets, not the files)
$items=$items | Where-Object {$_.Folder -ne $null}

foreach($item in $items)
{
$object = New-Object 'system.collections.generic.dictionary[string,object]'
$wfis.StartWorkflowOnListItem($subscription, $item.ID, $object)
}
$web.Dispose()

How to install Workflow Manager 2013

  1. Download Microsoft Web Platform installer from https://www.microsoft.com/web/downloads/platform.aspx
    WF1
  2. Open Web Platform Installer. Select “Workflow Manager 1.0 Refresh”, click ‘Add’ and then ‘Install’.
    WF2
  3. Go through the configuration wizard and choose “Configure Workflow Manager with Custom Settings”
    WF3
    Supply user details and passwords, and accept the default values. Check “Allow Workflow management over HTTP on this computer” option if your system is not configured for HTTPS.
    WF4
    WF5
    WF6
    WF7
    WF8
    WF9
    WF10
    WF11
    WF12
    When you’ve finished the configuration wizard, check in IIS if the Application Pool “WorkflowMgmtPool” and the Site “Workflow Management Site” are running.
    WF17
    WF13
  4. Use PowerShell to connect your SharePoint to the Workflow Manager
    Register-SPWorkflowService -SPSite “*Url of you WebApplication or SiteCollection*" -WorkflowHostUri "http://workflow.example.com:12291" -AllowOAuthHttp
    (If you don’t know your WorkflowHostUri, check Get-WFFarm in PowerShell)
  5. Install Workflow Manager Client from Web Platform Installer
  6. Install Workflow Manager Tools 1.0 for Visual Studio 2012 from Web Platform Installer
  7. Check if Workflow Manager is configured correctly
    • Check in Central Administration (/_admin/WorkflowServiceStatus.aspx)
      WF14
    • Check in SharePoint DesignerTry to create a new Workflow and chose “SharePoint 2015 Workflow” as Platform Type.

Troubleshooting

  1. If you still can’t see the option “SharePoint 2013 Workflow” in SharePoint Designer, check if the following two hidden features are activated on your site collection. If not, use the PowerShell to do so (with –Force Attribute).
    WF15
    Workflow Service Store ID=”2c63df2b-ceab-42c6-aeff-b3968162d4b1″
    Workflow Task ID =”57311b7a-9afd-4ff0-866e-9393ad6647b1″
    Enable-SPFeature -Identity *Feature ID* –Url *SiteCollection URL* -Force
  2. Check if the Workflow Service Application Proxy is connected to your Web Application
    WF16

Uninstall Workflow Manager

If you want to uninstall Workflow Manger check this post.

Using multiple CSR Template Overrides on one Page

SharePoint 2013 ClientSideRendering is a great tool to customize list rendering. But when you put two or more ListViewWebParts on one page and want to use csr, things get complicated. This is because the registered template overrides are executed on all lists, even when you use JS-Link option in WebPart properties.
Microsoft tries to solve this problem by filtering the template overrides by ListTemplateType, BaseViewID and ViewStyle. But when you set up two (or more) custom lists via frontend, the all get ListTemplateType 100. And what happens, when you use two times the same list on one page…?
Now, after more than 2,5 years it was time to solve this problem. (Here is another solution: [1]).

Idea of CSR Framework to support multiple template overrides

My solution is to write one general template override which gets handed over multiple template override objects with filters. By evaluating the filters, the single general template override can decide if the code in an overidden object has to be executed or the default renderer has to be used.

Example: Footer Template Override

I will demonstrate the technique on the footer template. Here is a footer template override:

var leftWebPart_Override = {	
	Templates: {
		Footer: function(ctx) {
			return "Custom WP Footer 1";
		},
	}
};

As you see, this is standard SharePoint notation.
Then I define a CTXFilter:

var leftWebPart_CTXFilters = {		
	ListTitle: "CSR-Test-List"
};

One of my test list has the title ‘CSR-Test-List’.
Now, I register the override using my AtiaNuur.CSR Framework and initialize it:

AtiaNuur.CSR.RegisterTemplateOverrides(rightWebPart_Override, rightWebPart_CTXFilters);
AtiaNuur.CSR.init();

The output is something like this:
AtiaNuur.CSR
You see the customized WebPart on the left and a second uncustomized WebPart on the right. Both are custom lists (with ListTemplateType 100).

AtiaNuur.CSR Framework in detail

So what happens in AtiaNuur.CSR. The framework follows three steps. It doesn’t matter if it’s footer-, header-, body-, OnPreRender, fields- etc. override. Therefore I’ll demonstrate it on the footer template override. You can get the rest out of the code. These steps are:

  1. Filling an array with objects of render-function and filters
  2. Filtering on current context
  3. Calling rendering function

I’ll start in reverse order, as the rendering function is the most interesting and the rest will be easier to understand.

Calling rendering function (templateRenderer)

The CSR Object has two public methods:

  • RegisterTemplateOverrides(templateOverride, ctxFilters): which takes a standard SharePoint template override and CTX Filters.
  • init(): Doesn’t take any arguments. Finally registers the single general template override to the SharePoint SPClientTemplates.TemplateManager.

Let’s have a look at this single general template override. The basic construct is like this (here only for footer template):

var templateOverride = {
	Templates: {
          	Footer: function(ctx) { return templateRenderer(ctx, footers, RenderFooterTemplate); }
     	}
};

You this that it’s always called the templateRenderer function, which takes:

  • ctx: the context
  • footers: an array of objects with footer functions (or a return string) and filters
  • RenderFooterTemplate: SharePoint default rendering function for footer

Now, the templateRenderer iterates over all footers and determines, if the current function in the footer has to be executed or not. This works this way:

function templateRenderer(ctx, templateDefinitions, DefaultTemplate) {
	var returnHTML = null;
		
	templateDefinitions.forEach(function(templateDefinition) {
		if(renderingOnCTX(templateDefinition.CTXFilters, ctx)) {
			if(typeof templateDefinition.Renderer === "string")
				returnHTML = templateDefinition.Renderer;
			else if(typeof templateDefinition.Renderer === "function")
				returnHTML = templateDefinition.Renderer(ctx);
		}
	});
		
	if(returnHTML === null)
		returnHTML = DefaultTemplate(ctx);

	return returnHTML;
}

Filtering on current context (renderingOnCTX)

The renderingOnCTX function determines if the rendering function (templateDefinition.Renderer) has to be executed in current context or not. It simply does this by comparing any parameter in CTXFilters with corresponding parameter in ctx. So you can compare ListTitle, URLs and also WebPart-Number. It is also possible, to execute custom function, by adding them to the CTXFilter object.
Here is the renderingOnCTX function:

function renderingOnCTX(ctxFilters, ctx) {
	var renderingOnCTX = true;
	var ctxFilterNames = Object.getOwnPropertyNames(ctxFilters);
	ctxFilterNames.forEach(function(filterName) {
		if(typeof ctxFilters[filterName] !== "function" && ctx.hasOwnProperty(filterName))
			renderingOnCTX = renderingOnCTX && ctx[filterName] === ctxFilters[filterName] 		
		else if(typeof ctxFilters[filterName] === "function")
		{
			renderingOnCTX = renderingOnCTX && ctxFilters[filterName](ctx);
		}
	});
	return renderingOnCTX;
}

And this is a filter definition with a ctx property comparison and a custom function:

{		
	ListTitle: "Documents",
	FilterFunction: function(ctx) {
		return (ctx.ListTitle.length > 1);
	}
}

You can define as many filter functions as you like. Also the name can be whatever you like.

Filling an array with objects of render-function and filters (RegisterTemplateOverrides)

The last part is now to get create the footers array of objects. This happens in the AtiaNuur.CSR.RegisterTemplateOverrides function (I’m showing just the footer part):

function RegisterTemplateOverrides(curTemplateOverride, ctxFilters) {
	if(curTemplateOverride.Templates !== undefined) {
		if(curTemplateOverride.Templates.Footer !== undefined) {
			footers.push({CTXFilters: ctxFilters, Renderer: curTemplateOverride.Templates.Footer});
		}
	}
}

As you see I create each footers object out of the ctxFilters and the Footer function.

And the other template overrides?

All other template override functions follow the same principle as the footer. The Templates.Fields object has been a little bit trickier, but it also works the same way.

How to use

Add the atianuur.csr.js to your page using masterpage, JS-Link or any other way you like. I used the masterpage, and also added a csr.js file which defines the concrete template override:

<SharePoint:ScriptLink language="javascript" name="~sitecollection/Style Library/atianuur.csr.js" OnDemand="false" runat="server" Localizable="false" LoadAfterUI="false" />
<SharePoint:ScriptLink language="javascript" name="~sitecollection/Style Library/csr.js" OnDemand="false" runat="server" Localizable="false" LoadAfterUI="true" />

I uploaded both files to the style library (any other folder works as well). Then I load the AtiaNuur.CSR framework before and the csr.js file after the UI.

And here is some code out of the csr.js file, which hands over a standard template override and a CTXFilter object:

var leftWebPart_Override = {	
	Templates: {
		Header: "",
		Footer: function(ctx) {
			return "Custom WP Footer 1";
		},
		Fields: {
			"LinkTitle" : {
				View: "This is not the original link text"
			}
		}
	},
	OnPreRender: function(ctx){ alert("I'm prerendering"); }
};
var leftWebPart_CTXFilters = {		
	ListTitle: "CSR-Test-List"
};
AtiaNuur.CSR.RegisterTemplateOverrides(leftWebPart_Override, leftWebPart_CTXFilters);

In this example, I also overwrite the LinkTitle-Field and the OnPreRender function.

Disclaimer

The code to get the default renderer comes from Jim Brown [2].

Sources

And here are the complete sources: atianuur.csr.

References

[1]: http://www.myfatblog.co.uk/index.php/2013/09/listview-web-part-issues-with-jslink-and-display-templates-a-solution/
[2]: http://sharepoint.stackexchange.com/questions/112506/sharepoint-2013-js-link-return-default-field-rendering

Search has encountered a problem that prevents results from being returned

I got the following error in search results:

Fehlermeldung1

When looking into the Log-Files I found the following:

07/02/2015 13:17:56.99                w3wp.exe (0x6B58)                                      0x35AC SharePoint Server Search          Query                                         dka5      High      SearchServiceApplicationProxy::Execute--Error occured: System.ServiceModel.FaultException`1[System.ServiceModel.ExceptionDetail]: Tried IMS endpoints for operation Execute: Cannot plan query for index system SP687d6eeb0241. Index fragment '0' has no available cells. Cell statuses: [Cell I.0.0 on node IndexComponent1: Cell status is set to 'not available' (cell out of sync or seeding)] (Fault Detail is equal to An ExceptionDetail, likely created by IncludeExceptionDetailInFaults=true, whose value is: Microsoft.SharePoint.SPException: Tried IMS endpoints for operation Execute: Cannot plan query for index system SP687d6eeb0241. Index fragment '0' has no available cells. Cell statuses: [Cell I.0.0 on node IndexComponent1: Cell status is set to 'not available' (cell out of sync or seeding)]   ... 990a169d-5bdf-904e-2a6f-03276c7b13e1

Here is how to fix this issue:

1. Stop the SharePoint Timer Service (Server Manager > Tools > Services)

Fehlermeldung3

2. Clear the SharePoint configuration cache. Therefore navigate to \ProgramData\Microsoft\SharePoint\Config and find the folder that contains the file cache.ini.

Fehlermeldung2

Delete all files in that folder, except the cache.ini. Afterwards open cache.ino in notepad an replace the content with a simple 1. Save the file.

Fehlermeldung4

3. Restart the SharePoint Timer Service (Server Manager > Tools > Services)

4. Do an index reset in Central Administration (Manage Service Applications > Search Service Application > Crawling > Index Reset)

5. Do a full crawl (Manage Service Applications > Search Service Application > Crawling > Content Sources)

Afterwards your search results should work as expected.

Nintex Workflow Activity Template for Visual Studio

Nintex offers some project templates for Visual Studio. One for an activity and one for an action adapter. You can download them from Nintex SDK: Installing and using Visual Studio templates.

I installed and used them to develop a new activity. After creating a new solution with adapter and activity using Namespaces you get a bunch of errors.
My Namespace is “AtiaNuur.NintexWorkflows”. Here are my steps to setup und correct the two projects:

  • Create new Project of type Nintex Adapter
    • Name “AtiaNuur.NintexWorkflows.HelloWorld”
    • Solution HelloWorld
  • Set SolutionId in package to new Guid (Nintex creates allways the same SolutionId)
  • Add Project of Type Nintex Activity using Name “AtiaNuur.NintexWorkflows.HelloWorldActivity”
    • Change default Namespace to “AtiaNurr.NintexWorkflows.HelloWorld
  • In File AtiaNuur.NintexWorkflows.HelloWorldActivity.cs
    • remove Namespace in class Name
    • Also remove Namespace in PropertyDependencies
    • Remove ‘Activity’ from namespace

The File AtiaNuur.NintexWorkflows.HelloWorldActivity.cs should look like this now:
Nintex-Template-Repair

  • In AtiaNuur.NintexWorkflows.HelloWorldDialog.aspx.cs
    • Remove namespace in classname
  • In AtiaNuur.NintexWorkflows.HelloWorldDialog.aspx
    • Shorten Filename
    • Set new filename in NWAFile
    • Set new filename in .aspx prefix tags
    • Remove duplivate namespace in tag Page
  • Add new EmptyElement “NWAFile”
    • Delete Element.xml
    • Move *.nwa file into EmptyElement
    • Set DeploymentType to ElementFile
  • In .nwa File
    • Set Name, Category and Description
    • <ActivityType>AtiaNuur.NintexWorkflows.HelloWorld.HelloWorldActivity</ActivityType> insert Activity classname
    • <ActivityAssembly>AtiaNuur.NintexWorkflows.HelloWorldActivity, Version=1.0.0.0, Culture=neutral, PublicKeyToken=529ebf25b8a73f63</ActivityAssembly> get your own full filename using ILSpy
    • Remove duplicated Namespace in AdapterType
    • Correct icon filenames
    • Correct ConfigurationDialogUrl
  • In package > Advanced
    • Add Activity Assembly
  • In File “AtiaNuur.NintexWorkflows.HelloWorldAdapter.cs”
  • Create Feature according to https://cann0nf0dder.wordpress.com/2013/09/12/nintex-workflow-custom-actions/
    • Add Event Receiver
    • Change NWAFile Name and Path
    • Change Adapter Class Name

SharePoint Survey – Where People and Group field data is stored in database

In general survey data is saved in SQLs AllUserData Table in the Content Database. But the data for a “people and group” field is not. This data is stored in the AllUserDataJunctions table.
You can use the following SQL statement to get the People for a survey list with title “MySurvey”. You should also filter the result by FieldID, if you have more than one people and group field:

SELECT
tp_Title
,tp_RootFolder
,tp_Modified
,AllUserData.tp_Created
,[AllUserDataJunctions].[tp_SiteId]
,[AllUserDataJunctions].[tp_DeleteTransactionId]
,[AllUserDataJunctions].[tp_IsCurrentVersion]
,[AllUserDataJunctions].[tp_DocId]
,[tp_FieldId]
,[AllUserDataJunctions].[tp_Id]
,[tp_Ordinal]
,[tp_SourceListId]
FROM [SP230_Inhalt_Inet].[dbo].[AllUserDataJunctions]
Join [SP230_Inhalt_Inet].dbo.AllUserData on AllUserData.tp_DocId = AllUserDataJunctions.tp_DocId
Join [SP230_Inhalt_Inet].dbo.AllLists on AllLists.tp_ID = [AllUserDataJunctions].tp_SourceListId
Where tp_Title = 'MySurvey'

Problems with anonymous access for External Lists using Publishing Feature

While setting up external lists on a SharePoint 2013 Site Collection for anonymous access we came across a problem. We started the configuration of the External Content Type as explained in many blogs (Thanks Prashanth) :

1. Create the External Content Type in SharePoint Designer
2. Give execute permissions to a specific user (i.e. Max Mustermann) for the External Content Type, the BDC Model and the External System via central administration.
bild1
4. Export the External Content Type from SharePoint Designer (There is an option to export the External Content Type from Central Administration as well, but it doesn’t export all the details. You have to use the export function of SharePoint Designer).bild2
5. Open the exported bdcm-File in text editor. The exported file includes <AccessControlEntry> elements that specify what rights an individual user or group has to the External Content Type. Adding users to the BCS permissions via Central Administration creates additional entries in the XML of the model.  Look for <AccessControlList>-Entries in the whole document and replace the entries that where created for Max Musterman with the following:

Before After
<AccessControlList>
[…]
<AccessControlEntry Principal="domain\max.mustermann">
<Right BdcRight="Execute" />
</AccessControlEntry>
</AccessControlList>
<AccessControlList>
[…]
<AccessControlEntry Principal="NT Authority\Anonymous Logon">
<Right BdcRight="Execute" />
</AccessControlEntry>
</AccessControlList>

bild3
6. Save the file and go back to central administration.
7. Delete the External Content Type and the connected bdcm model and external system from business data connectivity service.

bild4
8. Import the bdcm-File into Central Administration with Permissions.bild5

We noticed that this scenario worked on most of our SharePoint servers, but not on every server. It took me a while to find out what the difference between the server configurations was. At first I found out, that it doesn’t work on the servers, where the SharePoint Publishing Feature is enabled. But it didn’t help to just disable the feature. After some googling I found the solution (Thanks Russ). There is a hidden feature named ViewFormPagesLockDown, which, if enabled, prevents anonymous user from accessing certain areas of a site collection.

9. You can disable it via PowerShell.

$lockdown = get-spfeature viewformpageslockdown

disable-spfeature $lockdown -url https://sitecollection

bild6

After disabling the feature via PowerShell, anonymous users where able to access my external list.

And if the list still isn’t loading, check if the anonymous users have  permissions on the root site collection to see the rendering templates, or just change the redering-mode of the list to server-side rendering.

SharePoint Page Layout Error: Only Content controls are allowed directly in a content page that contains Content controls

Today I got the following error, when I wanted to open and edit a page based on a custom page layout: Only Content controls are allowed directly in a content page that contains Content controls.

I found a lot of blog entries about that topic, and thanks to this one I finally found the solution:

The cause of the problem is a improper case for the control tags the page layout. Some of the contorls in my page layout used a lower case “c” instead of an uppercase “C”. I just changed <asp:content> to <asp:Content> in the whole document and afterwards all the pages based on that layout worked again.