TEZURE – Cost effective IOT apps using Javascript, Tessel & Azure


Cost effective IOT device using Javascript, Tessel & Azure

  • With the recent advancements to embedded hardware technologies, micro-controller product lines like Tessel, Espruino, RasberryPI etc where able to build compilers to breakdown Programs written in most popular programming languages in to Javascript, Python to Assembly code.

  • With Cloud providers such as Azure, AWS etc allow easy access to Queue and Storage services in a secured way, Industry experts predict that by 2020 the Internet of things (IoT) network will reach ~200 billion connected devices.

  • This blog post explains how to create a IOT device using Javascript, Tessel and Azure.

Tezure-SpyCam Demo

GitHub Site

Internet Of Things (IOT)

The Internet of Things (IoT) is the interconnection of uniquely identifiable embedded computing devices within the existing Internet infrastructure

Every Industry is getting Smarter

  • Smart Logistics
  • Smart Home
  • Smart Industries
  • Smart Healthcare
  • Smart Entertainment

With number of internet connected devices is exploding, there is a need for enabling and controlling services remotely.


  • Enabling services remotely
  • More targeted services
  • Data driven insights
  • Cost efficient

Tezure – SpyCam

  • Mobile controlled Surveillance Camera


  • Design & Build
  • C, C++ for Sensors/Devices
  • C#, JAVA for cloud services
  • C#, Java, Obj C for Mobile devices
  • Connectivity (IP & Non IP devices)
  • Security – Identity and Authorization
  • Scalability

Keep it simple

  • Cost efficient
  • End to End solutions using pure Javascript
  • Tessel based devices/sensors
  • X platform mobile apps using Cordova/PhoneGap

  • REST based access to Azure Service bus/Azure Blobs

Hello Tessel!

– Tessel is a microcontroller that runs JavaScript.
– It’s NodeJS-compatible and ships with Wifi built in.
– Its easier than ever make physical devices that connect to the web.
– Bridges the gap between Embedded devices and Web development

What Azure Offers

  • Azure Service bus
  • Queues, Topics, relays for messaging
  • Mobile services for push notifications and data tables
  • Azure store blobs
  • Images and Video storage
  • SAS (Shared Access Token) based authentication via REST
  • Supports Async access using NodeJS/Javascript

What PhoneGap Offers

  • PhoneGap is a free and open source framework that allows you to create X-Plat mobile apps using Web technologies
  • Mobile Apps can be created using HTML, Javascript and CSS
  • PhoneGap Build takes the pain out of compiling PhoneGap apps. Get app-store ready apps without the headache of maintaining native SDKs.

Tezure SpyCam – Architecture


- Tessel

  • Tessel setup consists of Tessel Microcontroller and Camera module
  • Nodejs packages can be installed inside the tessel devices
  • Current set up consists of tesselPollingService() function which continously checks for new message on Azure queue
  • On new message, Camera module takes a picture and uploads to Azure blob storage
  • ‘Tesselate’ NPM module is used to load the Camera Module functions.
  • ‘Async’ NPM module is used to process the Polling cycles asynchronously
require('tesselate')(['camera-vc0706'], function (tessel, modules) {
console.log("Executed action 2 : After Camera Load : cycle no : " + count );
listen_messages: function (callback) {
var options = {...

Source Code

- Azure service bus

  • Azure queue receives messages from the Mobile applications and authenticated via SAS token
  • Azure Blob storage receives Images from tessel devices and authenticated via SAS
  • CORS rules can be added to Azure storage to enable X-domain requests

- PhoneGap App

  • Sends a surveillance request message with Device ID and time stamp
  • Polls the Azure Storage to retreive image with DeviceID and time stamp
  • Built with end to end javascript
    Source Code


Few Gotcha’s

Provision OneDrive and set global administrator for OneDrive accounts in Office365

Recently I was working in a project to migrate all the SharePoint on-premise stuffs to Office365 including file shares. All the users had their on file shares mapped to their home drives on the PC. And the requirement is to move all the home drive data to OneDrive for Business and let the Global administrators to manage them efficiently.

Though Office 365 admin page have functionality to set Global admin for SharePoint sites, for OneDrive sites there is no OOB way to set a Global admin for all the sites. And its very tedious to set this manually for 400+ users.

Below script will help the IT pro’s to

1) Store the Office admin credentials

2) Provision OneDrive Sites for list of users

3) Assign administrator for provisioned OneDrive sites


Download the script and change the Variables in “Input Variables” section to suit your environment

#Input Variables Begin
 #Credentials Store Location
 #Log File location
 $Logfile = "C:\GG\OneDriveProvisionReport.log"
 #O365 Global admin
 $O365AdminAccount = "admin@spbreed04.onmicrosoft.com";
 #O365 Onedrive admin
 $OneDriveAdminAccount = "admin@spbreed04.onmicrosoft.com";
 #O365 Admin site URL
 $webUrl = "https://spbreed04-admin.sharepoint.com"
 #List of OneDrive users (seperated by CSV)
 $OneDriveUsers = "alans@spbreed04.onmicrosoft.com","admin@spbreed04.onmicrosoft.com" 
# Input Variables End

Click here the download the script.

Jumpstart AngularJS app development for O365 & E2E testing using Protractor

BDD (Behaviour Driven Development) and TDD ( Test Driven Development) has become cornerstone for modern Javascript app development but adopting these development strategies to SharePoint/Office 365 is not a trivial task.

I was intrigued to discover #Protractor, an AngularJS testing framework. With client side MVC/MVVM frameworks getting popular among the developers, AngularJS is the premier framework to develop Office365/SharePoint 2013 apps. Integrating TDD methodologies to app development model will help developers to deliver maintainable, flexible and extensible solutions and interfaces.

Below is the RevealJS presentation on how to create AngularJS based SharePoint app and execute end to end testing using #Protractor. I would like to thank Andrew Connell for introducing  RevealJS and AngularJS Apps


This presentation includes training videos and Source code to build SharePoint
1) Expenses AngularApp(SharePoint hosted App)
2) ExpensesAngularApp test (NodeJS project created using VS2013)
1. Expenses AngularApp:
– This is a SharePoint hosted app developed using popular angular framework.
– Utilizes best patterns and practises for angular framework based on HotTowel framework and Learning-Path- Manager-Code-Sample from Andrew Connell.
– Uses ShareCoffee Javascript library to make REST calls to SharePoint
– Available as a nuget package for easy install
2. ExpensesAngularApp test:
– This Project runs on NodeJS and executes End to End testing on Expenses Angular App
– Utilizes Protractor framework to do E2E testing
– Jasmine is used to write test specs
Source code: https://github.com/spbreed/spangularapp

My favorite Nuget Packages for WebAPI /MVC apps

Its been a while since I worked on a hardcore ASP.NET / MVC projects. I was not aware of some of the sleek Nuget packages which are used elsewhere.

When you create MVC/WebAPI project by default VS adds packages.config to maintain a record of all the Nuget packages added to the solution.

You can either add packages directly to this file or via “Manage Nuget packages” or  through PowerShell.

Here are some of my favorite packages.

<?xml version="1.0" encoding="utf-8"?>
 <package id="Antlr" version="" targetFramework="net451" />
 <package id="bootstrap" version="3.0.0" targetFramework="net451" />
 <package id="DotNetOpenAuth.AspNet" version="" targetFramework="net45" />
 <package id="DotNetOpenAuth.Core" version="" targetFramework="net45" />
 <package id="DotNetOpenAuth.OAuth.Consumer" version="" targetFramework="net45" />
 <package id="DotNetOpenAuth.OAuth.Core" version="" targetFramework="net45" />
 <package id="DotNetOpenAuth.OpenId.Core" version="" targetFramework="net45" />
 <package id="DotNetOpenAuth.OpenId.RelyingParty" version="" targetFramework="net45" />
 <package id="Elmah.Contrib.WebApi" version="" targetFramework="net45" />
 <package id="elmah.corelibrary" version="1.2.2" targetFramework="net45" />
 <package id="Elmah.MVC" version="2.1.1" targetFramework="net45" />
 <package id="EntityFramework" version="6.1.1" targetFramework="net451" />
 <package id="jQuery" version="1.10.2" targetFramework="net451" />
 <package id="jQuery.UI.Combined" version="1.11.1" targetFramework="net45" />
 <package id="jQuery.Validation" version="1.13.0" targetFramework="net45" />
 <package id="JsonValue" version="0.3.0" targetFramework="net45" />
 <package id="knockoutjs" version="3.2.0" targetFramework="net45" />
 <package id="Microsoft.AspNet.Cors" version="5.2.0" targetFramework="net451" />
 <package id="Microsoft.AspNet.Membership.OpenAuth" version="2.0.1" targetFramework="net451" />
 <package id="Microsoft.AspNet.Mvc" version="5.2.2" targetFramework="net45" />
 <package id="Microsoft.AspNet.Razor" version="3.2.2" targetFramework="net45" />
 <package id="Microsoft.AspNet.Web.Optimization" version="1.1.3" targetFramework="net451" />
 <package id="Microsoft.AspNet.WebApi" version="5.2.0" targetFramework="net451" />
 <package id="Microsoft.AspNet.WebApi.Client" version="5.2.2" targetFramework="net45" />
 <package id="Microsoft.AspNet.WebApi.Core" version="5.2.2" targetFramework="net45" />
 <package id="Microsoft.AspNet.WebApi.Cors" version="5.2.0" targetFramework="net451" />
 <package id="Microsoft.AspNet.WebApi.HelpPage" version="5.2.2" targetFramework="net45" />
 <package id="Microsoft.AspNet.WebApi.WebHost" version="5.2.2" targetFramework="net45" />
 <package id="Microsoft.AspNet.WebPages" version="3.2.2" targetFramework="net45" />
 <package id="Microsoft.AspNet.WebPages.Data" version="3.2.0" targetFramework="net451" />
 <package id="Microsoft.AspNet.WebPages.WebData" version="3.2.0" targetFramework="net451" />
 <package id="Microsoft.Bcl" version="1.1.9" targetFramework="net45" />
 <package id="Microsoft.Bcl.Build" version="1.0.14" targetFramework="net45" />
 <package id="Microsoft.Data.Edm" version="5.6.0" targetFramework="net451" />
 <package id="Microsoft.Data.OData" version="5.6.0" targetFramework="net451" />
 <package id="Microsoft.Data.Services.Client" version="5.6.0" targetFramework="net451" />
 <package id="Microsoft.jQuery.Unobtrusive.Ajax" version="3.2.0" targetFramework="net45" />
 <package id="Microsoft.jQuery.Unobtrusive.Validation" version="3.2.0" targetFramework="net45" />
 <package id="Microsoft.Net.Http" version="2.2.28" targetFramework="net45" />
 <package id="Microsoft.Web.Infrastructure" version="" targetFramework="net451" />
 <package id="Microsoft.WindowsAzure.ConfigurationManager" version="2.0.3" targetFramework="net451" />
 <package id="Modernizr" version="2.6.2" targetFramework="net451" />
 <package id="MvcSiteMapProvider.MVC5" version="4.6.15" targetFramework="net45" />
 <package id="MvcSiteMapProvider.MVC5.Core" version="4.6.15" targetFramework="net45" />
 <package id="MvcSiteMapProvider.Web" version="4.6.1" targetFramework="net45" />
 <package id="netfx-Guard" version="" targetFramework="net45" />
 <package id="Newtonsoft.Json" version="6.0.4" targetFramework="net451" />
 <package id="Ninject" version="" targetFramework="net45" />
 <package id="Ninject.Extensions.Logging" version="" targetFramework="net45" />
 <package id="Ninject.Extensions.Logging.Log4net" version="" targetFramework="net45" />
 <package id="Ninject.Web.Common" version="" targetFramework="net45" />
 <package id="Ninject.Web.WebApi" version="" targetFramework="net45" />
 <package id="NotFoundMvc" version="1.2.0" targetFramework="net45" />
 <package id="Pkcs12ProtectedConfigurationProvider" version="1.0.1" targetFramework="net45" />
 <package id="Postal.Mvc5" version="1.0.0" targetFramework="net45" />
 <package id="RazorEngine" version="3.4.1" targetFramework="net45" />
 <package id="Respond" version="1.2.0" targetFramework="net451" />
 <package id="ServiceStack.Text" version="4.0.31" targetFramework="net45" />
 <package id="System.Spatial" version="5.6.0" targetFramework="net451" />
 <package id="WebActivatorEx" version="2.0.1" targetFramework="net45" />
 <package id="WebApi.Core" version="0.3.0" targetFramework="net45" />
 <package id="WebApi.Enhancements" version="0.3.0" targetFramework="net45" />
 <package id="WebGrease" version="1.5.2" targetFramework="net451" />
 <package id="WindowsAzure.Storage" version="" targetFramework="net451" />



Powershell to change UPN/Sign-in names for Office 365 users


In many cases after running the DirSync, Office 365 users are created with user@domain.onmicrosoft.com as Primary UPN.



Internally MS maintains two domains for federated users. One is “user@domain.com” which is the replica of on premise AD and other with “user@domain.onmicrosoft.com” on Azure AD.

It seems if the Dirsync is ran without “E-Mail” attribute on AD, Azure assigns “onmicrosoft.com” as the default domain and primary UPN. Once the initial DirSync is complete, adding “Email” value to AD user object wont help.



As usual PowerShell comes to rescue. Idea is to use Windows Azure AD Module for Powershell and change the UPN of all the objects with .onmicrosoft UPN.


1) Download and Install Azure AD modules from http://technet.microsoft.com/library/jj151815.aspx

2) Connect to WAAD  service using Office 365 admin credentials

3) Filter all the users ending with .onmicrosoft.com  as their UPN

4) Change the UPN using Set-MsolUserPrincipalName

5) Generate reports before and after updates

Download the scripts here: Update-msolUpn.ps1 


#.SYNOPSIS ./Update-msolUpn.ps1
#PowerShell script to automate this task to change the all Office 365 user accounts with user@domain.onmicrosoft.com. to user@domain.com
#Install Azure AD modules from http://technet.microsoft.com/library/jj151815.aspx before running this.

#Get Modules
$env:PSModulePath=$env:PSModulePath+";"+"C:\Program Files (x86)\Microsoft SDKs\Windows Azure\PowerShell"
Import-Module Azure
Import-Module MSOnline

Get-Credential "office365admin@GSI.com" | Export-Clixml C:\GSI\scripts\GSIcred.xml #Store Credentials

#$count = 1 #For Testing the first result

$cred = Import-Clixml C:\GSI\scripts\GSIcred.xml

Connect-MsolService -Credential $cred

Get-MsolUser -All | Select-Object UserPrincipalName, Title, DisplayName, IsLicensed | export-csv –path C:\GSI\scripts\GSI_MSOL_Users_BeforeUpdate.csv

Get-MsolUser -All |
 Where { $_.UserPrincipalName.ToLower().EndsWith("onmicrosoft.com") } |
 ForEach {
 #if($count -eq 1) #For Testing the first result
 # {
 $upnVal = $_.UserPrincipalName.Split("@")[0] + "@GSI.com"
 Write-Host "Changing UPN value from: "$_.UserPrincipalName" to: " $upnVal -ForegroundColor Magenta
 Set-MsolUserPrincipalName -ObjectId $_.ObjectId -NewUserPrincipalName ($upnVal)
 # }

Get-MsolUser -All | Select-Object UserPrincipalName, Title, DisplayName, IsLicensed | export-csv –path C:\GSI\scripts\GSI_MSOL_Users_AfterUpdate.csv


Powershell to report memory leaks and assembly info on SharePoint 2013/2010 custom solutions.


Recently I was involved in a task to troubleshoot performance related issues on a SharePoint farm. On analyzing the farm I found more than 50 WSP’s are deployed. On further analysis some of these solutions had two major performance related issues:

SharePoint Objects are not disposed properly:

Windows SharePoint Services object model contains objects which are not managed by ASP.Net windows garbage collector. Developers must take precautions when using these objects to avoid their long-term retention in memory in the Microsoft .NET Framework.

In scenarios in which you use SharePoint objects extensively—for example, in SharePoint sites that use custom Web Parts—you can cause the following unusual behaviors by not disposing of SharePoint objects when you are finished with them. This results in

  • Frequent recycles of the Windows SharePoint Services application pool, especially during peak usage
  • Application crashes that appear as heap corruption in the debugger
  • High memory use for Microsoft Internet Information Services (IIS) worker processes
  • Poor system and application performance

For more details refer this link


 Production solutions built in debug mode instead of release mode:

The default build setting during development is “Debug” mode and it is a common mistake to allow this development time setting to find its way onto production servers during deployment.  This can often leads to

  • The compilation of ASP.NET pages takes longer (since some batch optimizations are disabled)
  • Code can execute slower (since some additional debug paths are enabled)
  • Much more memory is used within the application at runtime
  • Improper recycles of App pools etc

More details here: http://weblogs.asp.net/scottgu/Don_1920_t-run-production-ASP.NET-Applications-with-debug_3D001D20_true_1D20_-enabled


Though the only known solution is re-build these custom WSP’s using best practices, its important to develop a detailed report on each custom assemblies on GAC and provide a report to fix these issues. So idea is to build a powershell script to

1) Export all the WSP solutions

2) Extract the WSP’s

3) Run SPDispose check on each DLL

4) Identify the assembly is in “Debug” or release mode

5) Export the report to CSV




Before running the script install SPDisposeCheck tool from here


Download this script here:


#Creates SP Dispose report on all WSP's

Add-PSSnapin Microsoft.SharePoint.PowerShell -erroraction SilentlyContinue

$wspdir = "D:\WSP\WSPReport1" #Location to export all WSP's
$exportdir = "$wspdir\Export-$((get-date).toString('yyyyMMdd'))\"
$CSVLocation = "$wspdir\SPDisposeResults.csv"

#create directory

#Function to export all WSP's
function Export-AllWSPs
 Write-Host Exporting solutions to $wspdir
 foreach ($solution in Get-SPSolution)
 $id = $Solution.SolutionID
 $title = $Solution.Name
 $filename = $Solution.SolutionFile.Name
 Write-Host "Exporting $title to ¦\$filename" -nonewline
 try {
 Write-Host "– done" -foreground green
 Write-Host "– error : $_" -foreground red


#Function to extract all WSP Packages
function Extract-AllWSPs
 #Retrieve the wsp files in this folder and subfolders
 $s = [system.IO.SearchOption]::AllDirectories
 $fileEntries = [IO.Directory]::GetFiles($wspdir,"*.wsp",$s);
 foreach($fullFileName in $fileEntries)
 $fileName = $(Get-Item $fullFileName).Name;
 $dirName = $fileName.Replace(".wsp","");
 $extractPath = $exportdir + $dirName;
 $dir = [IO.Directory]::CreateDirectory($extractPath) 

 Write-Host "Export $fileName started" -ForegroundColor Red
 $destination = $extractPath
 C:\Windows\System32\extrac32.exe $fullFileName /e /Y /L $destination


#Function to get Assembly details
function Get-AssemblyCustomProperty
 $Property = $null

 $value = $null
 foreach ($attribute in $assembly.GetCustomAttributes($false))
 if ($attribute.GetType().ToString() -like "*$TypeNameLike*")
 if ($Property -ne $null)
 # Select-Object -ExpandProperty fails if property value is $null
 try {
 $value = $attribute | Select-Object -ExpandProperty $Property
 catch {
 $value = $null
 $value = $attribute


#Function to report SP Dispose check results
Function Get-SPDisposeResults()

 #Pause for 5 secs to ensure extract is complete
 Start-Sleep -s 5
 $Dir = get-childitem $wspdir -recurse
 $List = $Dir | where {$_.extension -eq ".dll"}
 $List | ForEach-Object {

 [string]$report = & "C:\Program Files (x86)\Microsoft\SharePoint Dispose Check\SPDisposeCheck.exe" $_.fullname
 #remove repetitive strings
 $report = $report -replace "Note: This tool may report errors which are not actually memory leaks, otherwise known as false positives. Further investigation should be done to identify and correct real errors. It is designed to assist developers in making sure their code adheres to best practices for memory allocation when using SharePoint APIs. Please see the following for more information: http://blogs.msdn.com/rogerla/ http://msdn2.microsoft.com/en-us/library/aa973248.aspx http://msdn2.microsoft.com/en-us/library/bb687949.aspx", ""
 $build = "RELEASE";
 try {
 $info = @{}
 $assembly = [Reflection.Assembly]::LoadFile($_.FullName)
 $attr = $assembly.GetCustomAttributes([Diagnostics.DebuggableAttribute], $false)
 $info.IsJITTrackingEnabled = Get-AssemblyCustomProperty -Assembly $assembly -TypeNameLike 'System.Diagnostics.DebuggableAttribute' -Property 'IsJITTrackingEnabled'
 #$info.IsJITOptimizerDisabled = Get-AssemblyCustomProperty -Assembly $assembly -TypeNameLike 'System.Diagnostics.DebuggableAttribute' -Property 'IsJITOptimizerDisabled'
 #$info.DebuggingFlags = Get-AssemblyCustomProperty -Assembly $assembly -TypeNameLike 'System.Diagnostics.DebuggableAttribute' -Property 'DebuggingFlags'
 #Write-Host $_.FullName: +" IsJITTrackingEnabled "+ $info.IsJITTrackingEnabled
 #Write-Host $_.FullName: +" IsJITOptimizerDisabled "+ $info.IsJITOptimizerDisabled
 #Write-Host $_.FullName: +" DebuggingFlags "+ $info.DebuggingFlags

 } catch {
 throw $_

 Write-Host $report

 # Create a hash table with all the data
 $hash = @{
 "Assembly" = $_.name
 "Report" = $report
 "Debug Mode enabled" = $info.IsJITTrackingEnabled

 # Convert the hash to an object and output to the pipeline
 New-Object PSObject -Property $hash

#Function calls
Get-SPDisposeResults | Export-Csv -NoTypeInformation -Path $CSVLocation


Azure hosted SharePoint apps using AngularJS and WebAPI – Part 3

This is final post of a three part series on exploring Azure hosted SharePoint apps using AngularJS and WebAPI.

Part 1: Why Cloud and AppModel?

Part 2: SQLAzure data via WebAPI:

Part 3: Azure hosted apps using AngularJS and WebAPI

Why AngularJS:

 Traditionally managed server-side programming used to develop enterprise apps. But now this pattern is changing in the enterprise application development industry.  It’s a change away from logic on the server side, and towards logic on the client side. To address these complex business logic Javascript should evolve from just a language to make DOM manipulations to powerful client side MVC/MVVM framework. AngularJS framework makes this shift at ease.





There are also few other frameworks on the same course but AngularJS is a clear leader owing to these facts:

1)       Dependency injection:

This is huge and my personal favorite. Using this, custom modules can be injected just like adding assemblies on the server side code. This makes life little easier design MVC/MVVM based projects with separation of concern, modularity etc. An Analogy to server side code is represented below




2)      HTML templating:

Over the past few years, Single Page App’s (SPA’s) are gaining of a lot of traction from front end developers and end users. HTML templating feature in Angular makes it possible to easily switch the HTML in SPA’s.

 3)      Two way binding:

Fellow Silverlight developers can understand the complexity of two-way binding using propertychange events back in the old days. But AngularJS databinding makes this right OOB

 4)      Community support:

Google continues to develop and maintain the library. Large community of developers has embraced the framework so ample support is available on Stackoverflow and AngularJS official site.

5)      Advance error handling and logging features

Why AngularJS on Provider hosted App:

 Instead of using server side code on Provider hosted app, client side code is used for a sole reason to utilize AngularJS framework. Some of the advantages include

  •  Single Page App (SPA)
  • Clean URL for easy navigation
  • Responsive design
  • No server side code
  • Scalable for further enhancements

Future enhancements may include:

1)       Adding Chrome controls to give SharePoint look and feel

2)      Authentication for WebAPI

3)      Functions to delete/update O365 and WebApi Data. etc


Design of this app is based on Hot Towel app from John Papa and the pluralsight course from Andrew Connell.

It requires a bit of learning to understand the AngularJS. Go through these resources for deep understanding




SPAngular APP:

1)       Create a new provider host app project in VS2013

2)      New Project -> App for SharePoint -> Provider Hosted App -> ASP.NET Web Forms Application -> Use Windows Azure Access Control Service ->finish


3)      Now click the web project -> Manage NuGet Packages


4)      Search “hot towel” and install HotTowel.Angular.



5)      Main benefit of using this project template is all the heavy lifting of implementing MVC project structure, logging, exception handling, angularJS, configuration comes OOB. This makes this bootstrap project easily extensible for custom functionalities.


6)      By default App project creates Query String tokens to store URL’s of Appweb , hostweb etc for reference in the future.


7)      AngularJS navigation is based on the URL manipulations. Its little hard to implement the navigation with these long URL’s. So the idea is to use a applauncherpage to store the Querystring values to cookies for future use and redirect to the main page with clean URL.

8)      Create applauncher.html and applauncher.js. Create an empty controller and all the JS references from index.html.

<!DOCTYPEhtml><!--// ** Step 1: Add AppLauncher:  **//-->



<title>App Launcher</title>


<bodydata-ng-controller="applauncher as vm">


<!--// ** Step 2: Add Angular libs:  **//-->

<!-- Vendor Scripts -->















<!-- Bootstrapping -->






<!-- common Modules -->





<!-- common.bootstrap Modules -->



<!-- app -->






<!--// ** Step 5: Create Add references **// -->

<!-- app Services -->








9)      In the applauncher.js call spappcontext angular service.

// ** Step 3: Add AppLauncher JS:  **//


'use strict';

var controllerId ='applauncher';

var app = angular.module('app');

app.controller(controllerId,['common','spappcontext', applauncher]);


function applauncher(common, spappcontext){

var getLogFn = common.logger.getLogFn;

var log = getLogFn(controllerId);


function activate(){

common.activateController([], controllerId)

.then(function(){ log('Activated App Launcher View');});





10)   Create SPappcontext.js and create createSPAppContext()and loadSPAppContext() functions to read the query string and store it to cookies. This also redirects to \index.html, a Single page app.


'use strict';

var serviceId ='spappcontext';

var app = angular.module('app');

app.service(serviceId,['common','$window','$location', spappcontext]);

function spappcontext(common, $window, $location){

var getLogFn = common.logger.getLogFn;

var log = getLogFn(serviceId);

var service =this;

var spweb ={





service.hostWeb = spweb;


function init(){

var test = jQuery.getQueryStringValue('SPHostUrl');










function loadSPAppContext(){

log('loading spcontext cookie');

service.hostWeb.providerUrl = $.cookie("ProviderUrl");

service.hostWeb.SPAppWebUrl = $.cookie("SPAppWebUrl");

service.hostWeb.SPHostUrl = $.cookie("SPHostUrl");


function createSPAppContext(){

log('writing spcontext cookie');

var ProviderUrl = $window.location.protocol +"//"+ $window.location.host;

$.cookie("ProviderUrl", ProviderUrl,{ path:'/'});

var appWebUrl = decodeURIComponent(jQuery.getQueryStringValue('SPAppWebUrl'));

$.cookie("SPAppWebUrl", appWebUrl,{ path:'/'});

var url = decodeURIComponent(jQuery.getQueryStringValue('SPHostUrl'));

$.cookie('SPHostUrl', url,{ path:'/'});

$window.location.href = ProviderUrl +"/index.html";




11)    Now add host web SP JS libraries to index.html to for make JSOM calls against host web.

<!--// ** Step 7: Add SharePoint libs for JSOM calls **// -->





Now add the following code to web.config remove the static file issue on described here http://rainerat.spirit.de/2012/09/03/SharePoint-2013-App-HTTP-Error-405.0/

<!--// ** Step: 8: To Resolve IIS Static file issue**//-->




<addname="AspNetStaticFileHandler" path="*" verb="*" type="System.Web.StaticFileHandler" />

<addname="StaticHTML" path="*.html" verb="GET,HEAD,POST,DEBUG,TRACE" modules="StaticFileModule" resourceType="File" requireAccess="Read" />




12)   Now use JSOM to call host web and REST calls to WebAPI. $q.defer() objects are used to  pass promise to the calling function. This enables clients to complete the DOM structure without waiting for results.( Host web contains a demo contact list with title “DemoCustomer”

// ** Step 6: Create Datacontext Service **//


'use strict';


var serviceId ='datacontext';

angular.module('app').factory(serviceId,['$rootScope','$resource','spappcontext','common', datacontext]);


function datacontext($rootScope,$resource, spappcontext,common){

var $q = common.$q;



var service ={

getPeople: getPeople,

getMessageCount: getMessageCount,

getUserName: getUserName,

getCustomers: getCustomers,

getSPContacts: getSPContacts



return service;


function getCustomers(){


var dfd = $q.defer();

var webApi = $resource('http://customerwebapi.cloudapp.net/api/Customer/:Id',{ Id:"@Id"},{ update:{ method:'PUT'}});

//   var webApi = $resource('http://localhost/AppWeb/api/Customer/:Id', { Id: "@Id" }, { update: { method: 'PUT' } });


var customers = data;







return dfd.promise;



function getUserName(){


var dfd = $q.defer();


// Standard function to get hostweb

var ctx =new SP.ClientContext(spappcontext.hostWeb.SPAppWebUrl);

var factory =new SP.ProxyWebRequestExecutorFactory(spappcontext.hostWeb.SPAppWebUrl);


var hostWebctx =new SP.AppContextSite(ctx, spappcontext.hostWeb.SPHostUrl);


var appWeb = ctx.get_web();

var hostWeb = hostWebctx.get_web();

var currentAppWebUser = appWeb.get_currentUser();

var currentHostWebUser = hostWeb.get_currentUser();








var userName = currentAppWebUser.get_title();


},function(sender, args){

console.log(args.get_message()+" "+ args.get_stackTrace());




return dfd.promise;



function getSPContacts()


var dfd = $q.defer();

// Standard function to get hostweb

var ctx =new SP.ClientContext(spappcontext.hostWeb.SPAppWebUrl);

var factory =new SP.ProxyWebRequestExecutorFactory(spappcontext.hostWeb.SPAppWebUrl);


var hostWebctx =new SP.AppContextSite(ctx, spappcontext.hostWeb.SPHostUrl);


var appWeb = ctx.get_web();

var hostWeb = hostWebctx.get_web();


var ContactList = hostWeb.get_lists().getByTitle('DemoCustomer');

var contactListItems = ContactList.getItems(SP.CamlQuery.createAllItemsQuery());




var enumerator = contactListItems.getEnumerator();

var SPContacts =[];


var currentItem = enumerator.get_current();

SPContacts.push({"FirstName": currentItem.get_item('FirstName'),"LastName": currentItem.get_item('Title')});


var SPContactsObj = SPContacts;



},function(sender, args){

console.log(args.get_message()+" "+ args.get_stackTrace());



return dfd.promise;




13)   Now modify dashboard.js to call data service functions defined above and add spinner while waiting for results.


'use strict';

var controllerId ='dashboard';

angular.module('app').controller(controllerId,['common','datacontext', dashboard]);


function dashboard(common, datacontext){

var getLogFn = common.logger.getLogFn;

var log = getLogFn(controllerId);


var vm =this;

vm.news ={

title:'Hot Towel Angular',

description:'Hot Towel Angular is a SPA template for Angular developers.'


vm.messageCount =0;

vm.people =[];

vm.SPContacts =[];

vm.Customers =[];

vm.title ='Dashboard';

vm.busyMessage ='Please wait ...';

vm.isBusy =true;

vm.spinnerOptions ={













function activate(){

var promises =[getMessageCount(), getPeople(), getSPContacts(), getCustomers()];

common.activateController(promises, controllerId)

.then(function(){ log('Activated Dashboard View');});



function getCustomers(){


return datacontext.getCustomers().then(function(data){


return vm.Customers = data;




function getMessageCount(){

return datacontext.getMessageCount().then(function(data){

return vm.messageCount = data;




function getPeople(){

return datacontext.getPeople().then(function(data){

return vm.people = data;





function getSPContacts(){


return datacontext.getSPContacts().then(function(data){

return vm.SPContacts = data;





function toggleSpinner(on){ vm.isBusy = on;}



14)   Now add remote endpoint http://customerwebapi.cloudapp.net to the appmanifest.xml


15)   Now navigate to /_layouts/15/appregnew.aspx to generate client Id and client secret. Note down these values.


16)   Now right click the web project and select publish to select a new publishing profile


17)   Seed the values of the ClientID and Client Secret noted earlier.


18)   Now select the created profile and deploy to Azure Website.


19)   Add a site name and click create


20)   Keep the default settings and click publish.


21)    Now package the app and upload the app to the Office 365 site.


22)   Now clicking the app will navigate to the provider hosted app with displays data from both Office 365 and WebAPI.


This project is hosted in codeplex for download: https://spangular.codeplex.com/