How to get SPAppToken in Office 365 and use it in your Provider-Hosted app?

When you log in to your SharePoint site in Office 365, the site will generate a SPAppToken  and cache it somewhere for you to use in App. So, you need this token to open the ClientContext in your Provider-hosted app. When you add an app to your page, it will go to the appredirect.aspx with some parameters:

redirect_uri: App url with the formatting like this:

1:  https://yourproviderhosted.cloudapp.net/ProjectSite?SPHostUrl=https://youroffice365.sharepoint.com/sites/yoursitecollection&SPHostTitle=Your SharePoint Site Title&SPAppWebUrl=”&SPLanguage=en-US&SPClientTag=1&SPProductNumber=16.0.2016.1224&SenderId=E73DC26C0  

client_id: This is an app principle id with the formatting like this:

1:  i:0i.t|ms.sp.ext|48384dfb-52f9-4f04-9a53-dfad0028cbf2@dad0be63-dbfb-4bb2-ab26-ce292a09cff8  

But the problem here is the App only exist at the site where you add it, if you want to use this app again in sub site, you must add it again. In my scenario, I want to add an app only one time at root site collection, and can use it every where in this site collection, include sub site. How I do this?

Step 1: You need to know an app instance id via app product id. You can see the ProductId at the AppManifest.xml of App project, keep this id to javascript variable.

1. Declare some variables to store your context

1:  var clientContext = {};  
2:  var rootWeb = {};  
3:  var appInstance = {};  
4:  var yourAppProductId = '6d510a27-38f7-4d0f-9e67-dac426cc5a3d';

2. Load the root web in your site collection

1:  function loadRootWeb() {  
2:    clientContext = SP.ClientContext.get_current();  
3:    var site = clientContext.get_site();  
4:    clientContext.load(site);  
5:    rootWeb = site.get_rootWeb();  
6:    clientContext.load(rootWeb);  
7:    clientContext.executeQueryAsync(loadRootWebSuccessed, loadRootWebFailed);  
8:  };  

3. In the function “loadRootWebSuccessed”, get appPrincipalId by your AppProductId

1:  function loadRootWebSuccessed() {  
2:    appInstance = rootWeb.getAppInstancesByProductId('{' + yourAppProductId + '}');  
3:    clientContext.load(appInstance);  
4:    clientContext.executeQueryAsync(loadAppRedirect, errorHandler);  
5:  };  

4. Get appInstanceId and load appredirect.aspx with that instanceId

1:  function loadAppRedirect() {  
2:    var appEnumerator = appInstance.getEnumerator();  
3:    var hasNext = appEnumerator.moveNext();  
4:    if (hasNext) {  
5:      var oApp = appEnumerator.get_current();  
6:      var appInstanceId = oApp.get_id().toString();//     "6c2ca931-e661-4cff-bb71-66be022e1763"     String  
7:      var appPrincipalId = oApp.get_appPrincipalId().toString();//     "i:0i.t|ms.sp.ext|48384dfb-52f9-4f04-9a53-dfad0028cbf2@dad0be63-dbfb-4bb2-ab26-ce292a09cff8"     String  
8:      var hostWebUrl = _spPageContextInfo.siteAbsoluteUrl;  
9:      var iframeAppRedirectId = 'appRedirectFrame';  
10:      var iframeAppRedirectSrc = hostWebUrl + "/_layouts/15/appredirect.aspx?instance_id=" + appInstanceId;  
11:      $('body').append('

‘); 12: $(“#” + iframeAppRedirectId).load(iframeAppRedirectSrc + ” #frmRedirect”, function () { 13: getAppInformation(); 14: }); 15: } 16: }

Step 2: Get all needed information of an app in function getAppInformation, include SPAppToken

1:  function getAppInformation() {  
2:    var inputSPAppToken = $('#frmRedirect').find('input[name="SPAppToken"]')[0];  
3:    var formAction = inputSPAppToken.form.action;  
4:    var spAppToken = inputSPAppToken.value;  
5:    var spLanguage = getQuerystringParamValue(formAction, "SPLanguage");  
6:    var spHostUrl = _spPageContextInfo.webAbsoluteUrl;//getQuerystringParamValue(formAction, "SPHostUrl");  
7:    var spClientTag = getQuerystringParamValue(formAction, "SPClientTag");  
8:    var spProductNumber = getQuerystringParamValue(formAction, "SPProductNumber");  
9:    var appUrl = getAppUrlByAction(formAction);  
10:  }  
1:    function getQuerystringParamValue(url, paramName) {  
2:      paramName = paramName.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");  
3:      var regex = new RegExp("[\\?&]" + paramName + "=([^&#]*)"),  
4:        results = regex.exec(url);  
5:      return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));  
6:    };  
1:    function getAppUrlByAction(url) {  
2:      return getRootUrl(url.split('?')[0]);  
3:    };  

That’s all!

Calling a WCF Service using jQuery in SharePoint

Wictor Wilén have a nice post for this article here. But I want to show you my way to create a WCF service for SharePoint

1. Add SharePoint mapped folder “ISAPI” to your project
2. In “ISAPI”, create new folder with the same name with your project name
3. Add new Web.config file into the new folder with some very basic configuration

1:  <?xml version="1.0" encoding="utf-8"?>  
2:  <configuration>  
3:   <system.serviceModel>  
4:    <behaviors>  
5:     <serviceBehaviors>  
6:     </serviceBehaviors>  
7:    </behaviors>  
8:    <bindings>  
9:    </bindings>  
10:    <services>  
11:    </services>  
12:   </system.serviceModel>  
13:  </configuration>  

4. Add new svc file with the content like this”:

1:  <%@ ServiceHost   
2:    Language="C#"   
3:    Service="My.Services.Client.NewsArticleServices, My.Services, Version=1.0.0.0, Culture=neutral, PublicKeyToken=393b1a9faf7ecfca"   
4:    Factory="Microsoft.SharePoint.Client.Services.MultipleBaseAddressWebServiceHostFactory, Microsoft.SharePoint.Client.ServerRuntime, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>  

5. In service dll, add new class named “NewsArticleServices” with content like this:

1:  using System;  
2:  using System.Collections.Generic;  
3:  using System.Linq;  
4:  using System.Text;  
5:  using System.ServiceModel;  
6:  using System.ServiceModel.Activation;  
7:  using System.ServiceModel.Web;  
8:  using Microsoft.SharePoint;  
9:  using Microsoft.SharePoint.Taxonomy;  
10:  using System.Globalization;  
11:  using System.Web;  
12:  using Microsoft.SharePoint.Utilities;  
13:  using Microsoft.SharePoint.Client.Services;  
14:  using System.Runtime.Serialization;  
15:  namespace My.Services.Client  
16:  {  
17:    [BasicHttpBindingServiceMetadataExchangeEndpointAttribute]  
18:    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]  
19:    [ServiceContract]  
20:    public class NewsArticleServices  
21:    {  
22:      [OperationContract]  
23:      [WebGet(BodyStyle = WebMessageBodyStyle.Wrapped, ResponseFormat = WebMessageFormat.Json)]  
24:      public Model.Client.News GetLatestNewsArticle()  
25:      {  
26:        Logger.LogVerbose(this, LayerNames.Services, "GetLatestNewsArticle", "Enter -->");  
27:        var result = new Model.Client.News();  
28:        try  
29:        {  
30:          var webUrl = SPContext.Current.Web.Url;  
31:          SPSecurity.RunWithElevatedPrivileges(() =>  
32:          {  
33:            using (var elevSite = new SPSite(webUrl))  
34:            {  
35:              using (var web = elevSite.OpenWeb())  
36:              {  
37:                Services.NewsArticleServices service = new Services.NewsArticleServices(web);  
38:                result = service.GetLatestNewsArticle();  
39:              }  
40:            }  
41:          });  
42:        }  
43:        catch (Exception ex)  
44:        {  
45:          Logger.LogError(this, LayerNames.Services, "GetLastedNewsArticle", "Can't get latest news article.", ex);  
46:        }  
47:        finally  
48:        {  
49:          Logger.LogVerbose(this, LayerNames.Services, "GetLatestNewsArticle", "Exit -->");  
50:        }  
51:        return result;  
52:      }  
53:    }  
54:  }  

6. Add javascript file to layouts folder with the function:

1:    function getLatestNewsArticle() {  
2:      $.ajax({  
3:        type: "GET",  
4:        url: L_Menu_BaseUrl + '/_vti_bin/YourProjectName/ClientNewsArticleServices.svc/GetLatestNewsArticle',  
5:        contentType: "application/json; charset=utf-8",  
6:        dataType: "json",  
7:        data: getParams(L_Menu_BaseUrl),  
8:        success: function (data) {  
9:          alert('Successed!');  
10:        },  
11:        error: function (err) {  
12:          alert('Failed');  
13:        }  
14:      });  
15:    }  

That’s all!