Saturday, November 15, 2014

Rolling out Nov 2014 CU for SP2013 broke Enterprise Search

Against better judgement, I tried this week to install the November 2014 Cumulative Update for SharePoint 2013 almost immediately when it was announced. The installation on our single-server farm failed, I suspect due insufficient disk space (one more motivation to consider moving our demo landscape to the Azure cloud…). Besides that the November CU was thus not installed, the more problematic consequence was that parts of our SharePoint landscape appeared broken. The installation made some changes during its faulted execution, that were apparently not all rolled back:
An unhandled exception of type 'System.ServiceModel.Security.MessageSecurityException' occurred in Microsoft.Office.Server.Search.dll
Additional information: The HTTP request was forbidden with client authentication scheme 'Anonymous'.
This error occurred on trying to construct a KeywordQuery instance. Being in the SharePoint business for a longer time, I decided to not spend too much time trying to locate the problem cause; and just start with the simple first approach to reboot the server. And how surprising: this worked, and our SharePoint 2013 farm is again working correct. Yet without the Nov 2014 CU, for which in the meantime Microsoft already issued a corrective fix. But now I’ll wait with trying to roll that out until proven in the field, and/or we actually need it in our SharePoint 2013 landscape.

Wednesday, November 5, 2014

Recover from SharePoint 2013 Search and CryptoGraphic mismatch - 'Key does not exist'

SharePoint Search Application is applied to crawl external data via Duet Enterprise 2.0. In the Duet Enterprise authentication flow from SharePoint to SAP, the SSA process via Business Connectivity Services invokes Secure Token Service to runtime create an X.509 authentication user certificate for the SharePoint account under which the search crawling is executed. (See 'How authentication works in Duet Enterprise 2.0').
This worked fine, until I upgraded the SharePoint 2013 landscape to the latest released cumulative updates: Sept + Oct 2014. Part of the upgrade steps is to temporarily disable the SharePoint Search services, and restart them after the CU installations. However, afterwards it appeared that the runtime Duet Enterprise SSO behavior was broken. The crawl log on the external content source reported structurally the error Exception in invoking the ODataExtensionProvider of type 'OBA.Server.Canary.ObaOdataServerExtensionProvider'. And the ULS contains on constant basis the error 'The search connector framework caught an exception from BDC: Exception in invoking the ODataExtensionProvider of type 'OBA.Server.Canary.ObaOdataServerExtensionProvider'. (Key does not exist. )'
But this is only when the BCS OData service is invoked from Search Crawling context. Using the same SharePoint user credentials to interactively retrieve SAP data in a SharePoint site still works, and successful retrieves the external SAP data applying Duet Enterprise 2.0 Single Sign-On.
Recovery fix:
Restart the SharePoint Search service (OSearch15), to force a reset of the runtime memory in that process and resync with CryptoGraphic on Windows OS level.

Monday, November 3, 2014

On-the-fly add client-side filtering and sorting to GridView

ASP.Net GridView is a powerful UI-control to visualize an overview of (business) data entities. Also standard / COTS products (e.g. for SharePoint) make heavily usage of the GridView control and it's capabilities.
In case of using a COTS product, it can be challenging to address requests from endusers wrt the grid behavior. You do not have the option to change the server-side behaviour yourself, but are dependent on the supplier. Ok, so server-side falls off; but in these days we prefer client-side anyhow. As it gives a faster interactive ui-responsiveness and thus a better user-experience.
In our scenario, the customer requested to add filtering and sorting ui-behaviour to an overview grid. As the output of GridView in the browser is simple an HTML Table element, I searched on the internet for any javascript library to sort and filter on tables. There are several of these available. I picked the combination of List.js and jQuery.TableSorter.js.
Next step is to activate their clientside behaviour in the rendered GridView output. This requires some straightforward jQuery-coding: select the Table element, enrich it which new child elements that are needed by the sorting and filtering libraries, runtime import the javascript libraries, and activate the sorting respectively filtering clientside behaviour.
/* Add client-side filtering and sorting to the requests overview. */ $.getScript( "/.../scripts/list.js", function( data, textStatus, jqxhr ) { $("#RequestsOverview tbody").addClass("list"); var filters = '<tr > \ <td><div id="filterPH1"> </div></td> \ <td><div id="filterPH2"> </div></td> \ <td><input type="text" id="date" class="search" placeholder="Filter"</td> \ <td><input type="text" id="description" class="search" placeholder="Filter"</td> \ <td><input type="text" id="state" class="search" placeholder="Filter"</td> \ </tr>'; $("#RequestsOverview thead tr").after(filters); $("#RequestsOverview").parent().attr('id', 'RequestsOverviewDiv'); $("#RequestsOverview .wf-id-event").each(function(i) { $(this).parent().children().each(function(i) { switch(i) { case 2: $(this).addClass("date"); break; case 3: $(this).addClass("description"); break; case 4: $(this).addClass("state"); break; } }); }); var userList = new (List)('RequestsOverviewDiv', { valueNames: ['date', 'description', 'state'] } ); }); $.getScript( "/.../scripts/jquery.tablesorter.js", function( data, textStatus, jqxhr ) { $("#RequestsOverview").tablesorter( { cssHeader: "headerSort", headers: { 0: { sorter: false}, 1: {sorter: false} }, dateFormat: 'pt' }); });

Result:

Without clientside plug-in of sorting and filtering:
Grid ui-behaviour enriched with sorting and filtering:
Limitation:
As the plugged-in sorting and filtering works on the client-side available data, it cannot be used in case of server-side GridView paging. For that it is required to also sort and filter server-side, or replace the server-side paging by a clientside approach. The latter is typically not desirable, as this requires that all the data is immediately send to the client; while the user may be interested in only the first page.