SharePoint 2013 Provider Hosted Apps with Javascript – JSOM and Cross Domain Calls

Category : Apps, SharePoint 2013, SharePoint Provider Hosted Apps Tips and Tricks Series, sharepoint

SharePoint 2013 Apps – so many options, so many options. SharePoint Hosted, Provider Hosted, Auto Hosted. Ok, for the purposes of this post we picked Provider Hosted. Why? It meets the criteria of our requirements (specifically being able to use other code bases and hosting off the SharePoint farm).

But, wait, there’s more choices when I pick provider hosted. Do I use Client Side Object Model (CSOM) or JSOM (JavaScript Object Model)? Well, the answer depends on your architecture. If you are writing .Net code, then CSOM makes sense. If you are writing any other code base or a pure JavaScript app, then JSOM makes sense. Well, we want to use JavaScript. No postbacks, nice looking animations/loading symbols – basically, a first class App.

Whew! We made up our minds on options. Ok, now what? Lot’s more options. Provider Hosted Apps are really a blank slate. We are responsible for loading the SharePoint javascript files, Chrome, etc… So, to make life easier, I decided to create a SharePointController.js file that loads up the SharePoint context for the App and Host. Now I have one file to drop into any of my Provider Hosted solutions to load the SharePoint context correctly.

Note: This post is about using the Javascript Object Model and utilizing the SharePoint Context. It is not about the Client Object Model. If you want to use that then there is already a TokenHelper.cs created for you when you create the solution. But, once again, that’s not our requirement. I am just trying to be really clear about the situation we are describing in this post. I feel that most posts about the SharePoint App model don’t do a good job at describing their situation. So, once again for clarity, we are using: SharePoint Provider Hosted and the Javascript Object Model

Let me walk you through a whole scenario of how to use this.

Walkthrough

  1. Create a new Visual Studio SharePoint 2013 Provider Hosted App – if you don’t know how to do that yet, this blog might be a little too far along for you at this point.
  2. Open up the AppManifes.xml (in the App project of your solution) and give your App read-rights to the Host Web. This is important because we are reading from the host web for the purposes of this demo. In real life you might have to give different types of permissions based on what you are doing. Always remember – give the minimal amount of permissions necessary for your requirements.
  3. Go to the Default.aspx.cs file in your Web Project and comment out the code in the Page_Load. That code is the TokenHelper that gets the context for CSOM. But, we aren’t doing CSOM, so we can comment it all out for now.
  4. Drop the SharePointController.js file in the Scripts folder of your Web project of your solution.
  5. Create another JavaScript file in your Scripts folder. Call it App.js. This will be your main JavaScript file. Add the following code:

    
    function SharePointLoaded() {
        //This is just an example of a JSOM call we can make now that the appContextSite is loaded
        this.web = appContextSite.get_web();
        context.load(this.web);
    
        context.executeQueryAsync(
            Function.createDelegate(this, successHandler),
            Function.createDelegate(this, errorHandler)
        );
    }
    
    function successHandler() {
        alert("Succesffully created cross-domain call. Host website name is: " + web.get_title());
    }
    
    function errorHandler(data, errorCode, errorMessage) {
        alert("Could not complete cross-domain call");
    }
    
    var spController = new SharePointController();
    spController.go();
    

Basically, all we did was instantiate our SharePoint Controller class. That class calls a function called SharePointLoaded when finished. At this point SharePoint is completely loaded up and we access to our appContextSite (which is really the host web) and the context (which is really the app web).

So, in the example above we are reading (remember we gave read access earlier) to the host web to get the title. Not the most robust example. But, it proves the point. We just use a Provider Hosted App to make a cross-domain call back into SharePoint successfully. Now our options are completely opened. I can write, host, do whatever I want with my Website and talk to SharePoint. Pretty cool stuff!

But wait! We aren’t done yet. Still one more thing left to do. Go to your Default.aspx page and register the Script files we just added.


<head runat="server">
    <title></title>

    <script type="text/javascript" src="//ajax.aspnetcdn.com/ajax/4.0/1/MicrosoftAjax.js"></script>
    <script type="text/javascript" src="//ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.3.min.js"></script>
    <script type="text/javascript" src="../Scripts/SharePointController.js"></script>
    <script type="text/javascript" src="../Scripts/App.js"></script>

</head>
<body>
    <form id="form1" runat="server">
    <div>
        <!-- Chrome control placeholder -->
        <div id="chrome_ctrl_placeholder"></div>  

        Test
    </div>
    </form>
</body>
</html>

Couple very important point about the html above:

  • We first register Ajax and jQuery. These are very important frameworks for the SharePoint JavaScript to work
  • Next we register the SharePointController.js before the App.js
  • Lastly we put the Chrome control placeholder in the right place.

What is that Chrome Control Placeholder?

Well, the chrome control is the logo and title associated with your app. This is a common placeholder that gets added automatically with SharePoint hosted apps. But, you have to add it with Provider Hosted apps. The SharePointController.js takes care of all the hard JavaScript to do this. All you have to do is is make sure the placehoder is there.

Are we done yet?

Yes and No. Everything is technically done. But, go ahead, try to debug your solution. It’s not going to work. Why not? Well, Microsoft, in it’s infinite wisdom decided it wouldn’t provide the AppWebUrl (which is necessary to create the cross domain request) unless a SharePoint element is added to the App project. A SharePoint element can be anything from a List, Workflow, Module, Element, etc… I guess Microsoft “assumed” we developers never need to access the SharePoint AppWebUrl unless one of those exist. But, this assumptions is so wrong I can’t even describe it. There are so many other reasons to want this information. I don’t want to go into the technical details, but this is a big oversight on their part. So, you have two choices:

  1. Go ahead an add a List, Workflow or anything else you might need for your requirements to the “App” project in your solution.
  2. Hack it up – Go to the “App” project in the solution, right click, Add – New Item, and choose Empty Element. We aren’t going to do anything with this element. But, by adding it SharePoint will pass the AppWebUrl to the SharePointController in the query strings.

Advanced Explanation -for those who want to know what I did in the SharePoint Controller

First, get the code from here to walk through with me: SharePointController.js

  1. We first get the hostweburl and the appweburl from the querystrings. The host web is your SharePoint site’s url. The app web is your apps url. Remember earlier when we had to add a SharePoint element to our project. This is why. That appweburl is empty unless there is a SharePoint element getting deployed.
  2. Next we load up our SharePoint JavaScript files. Notice how I load them inside a “getScript”. This is a technique in jQuery that says don’t load the next JavaScript file until the previous one finishes. This is “really” important because some of the inner JavaScript files rely on the previous ones.
  3. When SP.UI.Controls.js loads up it calls renderChrome. That is the JavaScript function that fills in the SharePoint chrome we talked about earlier
  4. When SP.RequestExecutor.js loads up it calls registerContextAndProxy – this is the real Cross Domain magic. SharePoint provides a lightly documented SP.ProxyWebRequestExecutorFactor. That is the key to this solution.

Post a comment