maandag, december 07, 2015

Azure Resource Management: Switch-AzureMode is not recognized

For all of you working in Visual Studio with the Azure Resource Management (ARM) templates: When you get the PowerShell exception that the cmdlet Switch-AzureMode cannot be found, please take note of the following:

  • 23 November: Microsoft released Azure PowerShell 1.0 and deprecated / removed the former ARM Switch-AzureMode completely. Based on clear feedback this stateful model was absolutely not desired: https://azure.microsoft.com/nl-nl/blog/azps-1-0/
  • 30 November: Microsoft released Azure SDK 2.8. This incorporates new ARM templates for Visual Studio, based on the new ARM cmdlets. You can download the SDK over here: https://azure.microsoft.com/en-us/downloads/archive-net-downloads/
  • 30 November: Microsoft released Visual Studio 2015 update 1. This does not update Azure SDK. You will need to update the SDK yourself.

So bottom-line, don’t mix Azure PowerShell 1.0 with the former versions of Azure SDK pre 2.8.

Enjoy working with the ARM toolset! If you are looking for a tutorial, I recommend the following walkthrough: https://azure.microsoft.com/en-us/documentation/articles/vs-azure-tools-resource-groups-deployment-projects-create-deploy/

maandag, oktober 12, 2015

Client-side search webpart extension for filtering on followed sites

As all of you know SharePoint 2013 comes with a much improved search webpart infrastructure. One can even build search filters based on user profile properties in order to build personalized experiences (refer to the Technet article Query variables in SharePoint 2013).
Strangely, it is currently not possible to filter search results based on the followed sites. Take the scenario where you have hundreds of sites that have stored documents, list items, etc. and you want to show a list of recently added items to the user for all his followed sites.

(people that can't wait and want the ready-to-use solution: go straight to the ce_followedsites.html gist. Others, read along!)

JavaScript-only solutions have their limitations
Most examples in the blogosphere provide a JavaScript focused solution where you need to include the specific business rules into code for filtering and rendering. What I started to wondering whether it would be possible to extend the search webparts with a custom token expression. The whole benefit would be that the filtering business rules can be expressed by the power user using the query builder, and the rendering logic with a custom display template.

Cloud-ready solutions are preferred
Although a full-trust solution based on inheriting the OOTB webparts should be doable, most customers don't want to invest anymore in this route, but want to focus on cloud-ready customizations, i.e. it should be applicable to SharePoint Online. So I started investigating.

The idea is to catch the search queries before they are about to be sent to the server, and then inject the queries with the user's followed sites data. Therefore it is important to configure your search webparts so that the search queries are executed client-side. You can find this option in the options tab within the query builder.

Microsoft AJAX
First direction I took was to find out the whold wiring that takes place when the page is loaded. In the server-side generated aspx that is pushed to the browser I see the following statements appearing:

Sys.Application.add_init(function() {
    $create(Srch.ContentBySearch, {"alternateErrorMessage":"","delayLoadTemplateScripts":true,"groupTemplateId":"~sitecollection/_catalogs/masterpage/Display Templates/Content Web Parts/Group_Content.js","itemTemplateId":"~sitecollection/_catalogs/masterpage/Display Templates/Content Web Parts/Item_mydisplaytemplate.js","messages":[],"numberOfItems":50,"queryGroupName":"Default","renderTemplateId":"~sitecollection/_catalogs/masterpage/Display Templates/Content Web Parts/Control_mydisplaytemplate.js","shouldHideControlWhenEmpty":false,"showBestBets":false,"showDataErrors":true,"showDefinitions":false,"showDidYouMean":false,"showPersonalFavorites":false,"states":{}}, null, null, $get("ctl00_ctl54_g_96bccb53_bb46_4003_bbba_9765befa5ebf_csr"));
});
Sys.Application.add_init(function() {
    $create(Srch.DataProvider, {"availableSorts":[],"bypassResultTypes":true,"clientType":"ContentSearchRegular","collapseSpecification":"","delayLoadTemplateScripts":true,"enableInterleaving":false,"fallbackSort":[],"hitHighlightedProperties":["Title","Path","Author","SectionNames","SiteDescription"],"initialQueryState":{"k":"","o":null,"s":0,"r":null,"l":0,"m":"","d":0,"x":null,"e":-1},"maxPagesAfterCurrent":1,"messages":[],"processBestBets":false,"processPersonalFavorites":false,"properties":{"TryCache":true,"Scope":"{Site.URL}","UpdateLinksForCatalogItems":true,"EnableStacking":true,"ListId":"a42ba038-b804-4126-afe7-467143dd9777","ListItemId":41},"queryGroupName":"Default","queryPropertiesTemplateUrl":"querygroup://webroot/Paginas/Test-SearchFollowedSites.aspx?groupname=Default","queryTemplate":"{FollowedSites} (contentclass:STS_Site OR contentclass:STS_Web)","rankRules":[],"renderTemplateId":"DefaultDataProvider","resultsPerPage":50,"selectedProperties":["Path","Title","FileExtension","SecondaryFileExtension"],"selectedRefiners":[],"sourceID":"8413cd39-2156-4e00-b54d-11efd9abdb89","sourceLevel":"Ssa","sourceName":"Local SharePoint Results","states":{},"trimDuplicates":false}, null, null, $get("ctl00_ctl54_g_96bccb53_bb46_4003_bbba_9765befa5ebf_ctl00_csr"));
});
So what is this Sys-namespace and its Sys.Application? It appears to the Microsoft Ajax framework that is leveraged here.


The add-init-function adds callbacks onto a list of functions that will be called when the html document is ready, by the function Sys.Application.Init as part of the Microsoft AJAX framework.
Would it be that easy to intercept this add_init-event, scan the applied queries, replace the tokens and fire the original $create-function calls?

Unfortunate initialization wiring
Unfortunately, it isn't, as I recognized that there is also the Sys.Component flow that will initialize all registered components during start-up of the page. So we can't execute our components later in the lifecycle easily. After some digging through the JavaScript-file search.ClientControls.debug.js I found the function Srch.ScriptApplicationManager.prototype.$4b_1 which is responsible for kicking off the queries and wiring the results. But as you know, you should only integrate with APIs found in JavaScript files that start with sp and secondly, these kinds of obscure function names should be avoided at all times. Ok, so I looked for another route.

Another direction: intercept SearchExecutor
I went looking for the async-ajax-calls that are eventually put on the wire in order to request for search results. I then could intercept these async calls and inspect the queries inside in order to replace the token with the followed sites. Luckily there was this clear async call indeed: a SearchExecutor-request.

So I started with a simple interception:
var oldexecuteQueries = Microsoft.SharePoint.Client.Search.Query.SearchExecutor.prototype.executeQueries;
Microsoft.SharePoint.Client.Search.Query.SearchExecutor.prototype.executeQueries = 
   function() {  
      return oldexecuteQueries.apply(this, arguments); 
   }

So far so good. And by the way, this function is part of the file sp.search.debug.js so one is allowed to integrate with this API. Nevertheless, as soon as I introduced a second async call, things went ugly:

var oldexecuteQueries = Microsoft.SharePoint.Client.Search.Query.SearchExecutor.prototype.executeQueries; 
Microsoft.SharePoint.Client.Search.Query.SearchExecutor.prototype.executeQueries = function() {  
   var myargs = Array.prototype.slice.call(arguments);
   var oldargs = fetchFollowedSites(function() {
      oldexecuteQueries.apply(that, myargs);  
      ?? how to provide the result to the original caller?
   }
   return;
}

Also intercept executeQueryAsync
Nice we are able to replace the query with the followed sites, but how can we return the new result to the original caller, i.e. the search webpart? The trick is to also intercept the original executeQueryAsync and wait with executing it until we have fetched the followed sites!

var oldexecuteQueryAsync = SP.ClientRuntimeContext.prototype.executeQueryAsync;
SP.ClientRuntimeContext.prototype.executeQueryAsync = function() {
   if (somePendingQuery) {
      ...
      jQuery.when.apply(jQuery, this.pendingQueries).then(function() {
         ...
  oldexecuteQueryAsync.apply(that, myargs);
      });
   }
   else return oldexecuteQueryAsync.apply(this, arguments);
}
(left out some fragments for brevity; please look up full gist via the link shared above) 

And there you have it. A client-side solution that just intercepts search queries as they are put on the wire and replaces tokens with the user's followed sites. Enjoy!

Full solution available
Full solution available via the following gist: ce_followedsites.html

donderdag, oktober 08, 2015

WhatsApp integration with your CRM system

A Dutch retailer published some interesting news: they were successful in integrating their CRM system with the WhatsApp channel. WhatsApp is currently the most often used app on mobile devices:
  • 4 out of 10 users are using WhatsApp business-wise;
  • in average people receive 65 new messages per day;
  • People in the age range of 18 and 34 even receive 150 message per day, and send 60 messages per day on average.
Deep integration between WhatsApp and CRM
For me the catch in this news is the option that WhatsApp provides options to integrate the communication stream into one's backend system. When a customer sends a message, the CRM system provides full context information towards the employee: who, what, where.
http://www.frankwatching.com/archive/2015/10/05/whatsapp-als-servicekanaal-suitsupply-pakt-het-innovatief-aan-case/

dinsdag, september 22, 2015

TypeScript async/await example for the browser

With the release of TypeScript 1.6 it is now possible to start using the async and await operators in your TypeScript code! You will need to enable this experimental feature, and you will need to target ES6, as TypeScript 1.6 is currently only emitting ES6 generator / yield code for your async / await code. Then when you apply for example Babel to take your JavaScript ES6 code to ES5 code, it suddenly became possible to run your async / await enabled TypeScript code in the browser!

I have compiled a working sample project to show you the application. See the following GitHub repository: https://github.com/cveld/AsyncAwait-TypeScript-Example

The following components have been used:

  • Visual Studio 2015; not required, but you get perfect syntax highlighting;
  • ASP.NET 5 beta7 web project template;
  • TypeScript 1.6; starting from version 1.6 it supports the experimental async and await operators. You will need to set ES6 as the target. TypeScript 1.6 does not support transpiling into ES5 of await/async yet, but transpiles into ES6 generator / yield code;
  • Babel; a JavaScript transpiler;
  • Gulp; a stream based JavaScript task runner;
  • Babel Browser Polyfill; included in Babel; a JavaScript file that polyfills the Promise and regenerator objects (and more).
The TypeScript example:
function test() {
    console.log("awaiter to be called...");
    awaiter();    
}

async function awaiter() {
    var result = await asyncfunc();
    console.log(result);
}

function asyncfunc() {

    var p = new Promise<string>((resolve, reject) => {
        setTimeout(() => {
            resolve('a string');
            console.log("resolved");
        }, 2000);
    });

    return p;
}
The Gulp task that is responsible for processing the .ts-file towards an ES5-compabile .js-file:
gulp.task("compile:typescript", function () {
  var tsResult =
    gulp.src(["./**/**.ts", "!node_modules/**/**.ts"])
        .pipe(sourcemaps.init())
        .pipe(tsc(tsProject));

    tsResult.js
            .pipe(babel())            
            .pipe(ngAnnotate())
            .pipe(concat("app.js"))
            .pipe(sourcemaps.write("."))
    .pipe(gulp.dest("./wwwroot/js"));
    return;
});
And the gulp task that copies over the Babel Browser Polyfill .js:
var polyfill = './node_modules/gulp-babel/node_modules/babel-core/browser-polyfill.js';
gulp.task("copy:browser-polyfill", function() {
    gulp.src(polyfill).pipe(gulp.dest("./wwwroot/lib/babel"))
});
The modified tsconfig.json:
{
  "compilerOptions": {
    "noImplicitAny": false,
    "noEmitOnError": true,
    "removeComments": false,
    "sourceMap": false,
    "target": "es6",
    "experimentalAsyncFunctions": true,
    "jsx": "react"
  },
  "exclude": [
    "node_modules",
    "wwwroot"
  ]
}

vrijdag, mei 01, 2015

Office Patterns & Practices: remote provisioning framework

Most of you do probably know the Office Dev Center; the portal for (SharePoint) Office development. But who is familiar with the Office Dev Patterns & Practices initiative? This initiative lead by Microsoft has as main goal to provide a central repository for all code, solutions, patterns, examples with regards to (SharePoint) Office development. Their most important asset is their GIT repository of which the first delivery was done in May 2014.

https://github.com/OfficeDev/PnP/wiki

Office Patterns & Practices is also to be found on Channel9:

http://channel9.msdn.com/blogs/OfficeDevPnP

clip_image001

New: remote provisioning framework

A very interesting addition recently made is a first version of a remote provisioning framework  in order to provision sites based on templated configuration files. This requirement lives with lots of customers and using this framework we can provide faster solution to address the needs. Check the demo video on Channel9:

http://channel9.msdn.com/blogs/OfficeDevPnP/Introduction-to-PnP-site-remote-provisioning-engine

The Office Dev patterns & practices initiative therefore is really something to keep following closely.

Some questions I have:

  • To what extent is on-premise SharePoint server supported;
  • Are the publishing features already supported;
  • What to think of the automatic deployment of apps you want to install to the newly created sites;
  • Is there any collaboration between the (PowerShell-driven) desired state configuration team within Microsoft. Also they have made a (basis for) provisioning framework for SharePoint; albeit their focus to create the infrastructure side, i.e. the creation of a SharePoint farm. OfficeDevPnP will then proceed with the provisioning of sites, pages, etc.