If Part 1 of this blog series, I created a simple Provider-hosted app to SharePoint. The “Provider” part of the SharePoint app was Windows Azure. If you’d like to read more on this, check out Part 1 here: http://blogs.msdn.com/b/steve_fox/archive/2013/02/18/building-your-first-provider-hosted-app-for-sharepoint-using-windows-azure-part-1.aspx.

In the second part, I wanted to add some code to flesh out the app to interact with SharePoint. In this blog, we’ll create a read event that uses a context and access token to interact with a SharePoint list. In essence, you’ll deploy a Provider-hosted app to Windows Azure, and then you’ll deploy the .APP to SharePoint.

So, let’s get started.

If you take the principles you learned in Part 1, you’ll do the same thing in this blog. So, let’s go ahead and create a new Provider-hosted app. To do this:

  • Open Visual Studio 2012
  • Click File, New Project
  • Select Office/SharePoint, Apps, and App for SharePoint 2013
  • Provide a name for the project, and click OK.
  • Double-check the name of the project, the URL to your SharePoint site, and select Provider-hosted in the drop down list
  • Click Finish

All of the above should be review for you at this point—assuming you followed along with Part 1. The project comprises two parts: the APP, which contains the AppManifest.xml file (config file for SharePoint), and the Web file, which you’ll deploy to Windows Azure. You can see in the image below the different elements of each part of the project.

image

I mentioned this in the first post, but will review in a little more detail here. When you create a new Provider-hosted app, you’ll see some code-spit by default. Without doing anything, you could hit F5 and your app would run and you’d see the title of your site appear at the top of the web page. The code below is the default code that is created when you create a new project. The two bolded lines use the new TokenHelper class, which contains a set of methods that enable you to manage requests for auth tokens in your app. The first bolded line retrieves a context token from the page request, and the second wraps the CSOM API with an auth token. It’s important to note that you can’t interact with SharePoint unless you have a context token, and you can’t access resources within SharePoint without an access token—and of course you need to set permissions within the AppManifest.xml file. Point being, you really need to be thinking more about the permissions and authorization within your app.

Note: There’s a great MSDN article on app authorization here: http://msdn.microsoft.com/en-us/library/office/apps/fp142384.

    …

        protected void Page_Load(object sender, EventArgs e)
        {
            var contextToken = TokenHelper.GetContextTokenFromRequest(Page.Request);
            var hostWeb = Page.Request["SPHostUrl"];

            using (var clientContext = TokenHelper.GetClientContextWithContextToken(hostWeb, contextToken, Request.Url.Authority))
            {
                clientContext.Load(clientContext.Web, web => web.Title);
                clientContext.ExecuteQuery();
                Response.Write(clientContext.Web.Title);
            }

        }

    …

Let’s go ahead and make some changes to the default code-spit to make this app a tiny bit more interesting.

In the spirit of keeping things simple for illustration, right-click Default.aspx and select View Designer. Drag a GridView object onto the Designer surface.

image

If you click the Source tab, you should see something similar to the bolded code below:

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:GridView ID="grdviewSPData" runat="server"></asp:GridView>
    </div>
    </form>
</body>
</html>

Double-click the Default.aspx.cs file and then replace the default code discussed above with the code below. You can again see the TokenHelper class here being leveraged to set the context for the app and then getting an access token to interact with SharePoint resources. Key to the use of the access token is the fact that it is passed in the ReadListItem method and then used to set auth properties on the request object. You may recognize the code inside the ReadListItem method, which I ‘borrowed’ from one of the SDK samples.

What’s important to note here is that any time you have an event or object that triggers an event, you must have an access token attached to it so it can interact with the SharePoint resources—e.g. read or write to a list. Also, you should note that there are different ways in which you can manage the context token—e.g. through the page request, page or session cache, accessing the headers, or through a response.redirect call:

Response.Redirect(TokenHelper.GetAppContextTokenRequestUrl(sharePointUrl, Server.UrlEncode(Request.Url.ToString())));

There are a good set of tips and tricks for developers around auth, which you can find here: http://msdn.microsoft.com/en-us/library/office/apps/fp179932.

Getting back to the code, the below in essence gets the appropriate context tokens with SharePoint, gets the access tokens, and then uses the access tokens to read a default list within SharePoint.

using Microsoft.SharePoint.Client;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml.Linq;

namespace Test_Provider_Hosted_App_2_20_2013Web.Pages
{
    public partial class Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            var contextToken = TokenHelper.GetContextTokenFromRequest(Page.Request);

            SharePointContextToken spContextToken = TokenHelper.ReadAndValidateContextToken(contextToken, Request.Url.Authority);

            var appWeb = new Uri(Page.Request["SPAppWebUrl"]);

            string myAccessToken = TokenHelper.GetAccessToken(spContextToken, appWeb.Authority).AccessToken;

            ReadListItems(appWeb.ToString(), myAccessToken); 
        }

        private void ReadListItems(string webUrl, string myAccessToken)
        {
            string oDataUrl = "/_api/Web/lists/getbytitle('Composed Looks')/items?$select=Title,AuthorId,Name";

            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(webUrl.ToString() + oDataUrl);
            request.Method = "GET";
            request.Accept = "application/atom+xml";
            request.ContentType = "application/atom+xml;type=entry";
            request.Headers.Add("Authorization", "Bearer " + myAccessToken);
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();

            XDocument oDataXML = XDocument.Load(response.GetResponseStream(), LoadOptions.None);
            XNamespace atom = "
http://www.w3.org/2005/Atom";
            XNamespace d = "http://schemas.microsoft.com/ado/2007/08/dataservices";
            XNamespace m = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata";

            List<XElement> entries = oDataXML.Descendants(atom + "entry")
                                     .Elements(atom + "content")
                                     .Elements(m + "properties")
                                     .ToList();

            var entryFieldValues = from entry in entries
                                   select new
                                   {
                                       Title = entry.Element(d + "Title").Value,
                                       AuthorId = entry.Element(d + "AuthorId").Value,
                                       Name = entry.Element(d + "Name").Value
                                   };

            grdviewSPData.DataSource = entryFieldValues;
            grdviewSPData.DataBind();
        }

    }
}

At this point, you can hit F5 and debug, and your code should execute just fine. As you can see from the below, you’re running the SharePoint app in localhost, so you should have no trust issues with your app.

image

If you copy and paste the URL of your app into Notepad, you’ll see something similar to the below:

https://localhost:44303/Pages/Default.aspx?SPHostUrl=https%3A%2F%2Fmydemosite2013%2Esharepoint%2Ecom%2Fsites%2Fspc&SPLanguage=en%2DUS&SPClientTag=0&SPProductNumber=15%2E0%2E4454%2E1011&SPAppWebUrl=https%3A%2F%2Fspcdemo2013%2Db802311f297b7f%2Esharepoint%2Ecom%2Fsites%2Fspc%2FTest%5FProvider%5FHosted%5FApp%5F2%5F20%5F2013

It’s not just about making sure the auth is managed in your code; remember that you also need to create a ClientID and ClientSecret and add to your project files. Specifically, as you did in Part 1, make sure you create a new ClientID and ClientSecret and then add those to the AppManifest.xml and Web.Config files.

Now, you can go ahead and follow the same pattern as in Part 1 and create a new Azure Web site, to which you will deploy the Web project. To do this:

  • Navigate to your Windows Azure portal
  • Click Web Sites
  • Click New
  • Select Compute, Web Site, Quick Create, provide a URL, and then select the region in which you want to deploy the site
  • Click Create Web Site

image

Make sure you click the Download publish profile link to save your publish profile locally, so you can configure the publish process to Azure in Visual Studio.

If you click Configure, you’ll see that you can also add your ClientID and ClientSecret on the Azure site. Go ahead and add the settings here as well.

image

Back in Visual Studio, right-click the Web project and select Publish. This will prompt you to import your publish profile and provide a wizard for you to publish your Windows Azure app.

image

Once you’ve deployed your Windows Azure app, you can right-click the APP project and select Publish. This does not deploy your files to SharePoint; it only creates the package of files for you to either deploy into an on-premises environment or to upload the APP file to SharePoint. You can do this by navigating to your SharePoint site, clicking new app to deploy, and then browsing, uploading, and trusting the app.

image

Once you’ve deployed the app to SharePoint, you can then click the newly deployed app and you can see that now it is deployed to Azure, integrated with SharePoint and using the appropriate tokens to read a list from the SharePoint site.

image

Again, take note of the long URL that contains the cross-domain reference along with the SharePoint tokens.

https://spappinazure.azurewebsites.net/Pages/Default.aspx?SPHostUrl=https%3A%2F%2Fmyspsite2013%2Esharepoint%2Ecom%2Fsites%2Fspc&SPLanguage=en%2DUS&SPClientTag=0&SPProductNumber=15%2E0%2E4454%2E3006&SPAppWebUrl=https%3A%2F%2Fspcdemo2013%2Db802311f297b82%2Esharepoint%2Ecom%2Fsites%2Fspc%2FTest%5FProvider%5FHosted%5FApp%5F2%5F20%5F2013

A tip for you…

One thing I kept coming across was the “null context token” error. Drove me crazy to say the least. However, I discovered that there are a couple of things that could cause this to happen:

  • The ClientID in your AppManifest.xml and in your Web.Config do not match.
  • Your domain reference to Azure is HTTP instead of HTTPS in the AppManifest.xml file.

The second one tripped me up for quite some time—makes sense right since we need an auth handshake. The code worked fine, but then when deployed it kept spitting up the null token error. I’ve bolded the culprit line below


<App xmlns="
http://schemas.microsoft.com/sharepoint/2012/app/manifest"
     Name="Test_Provider_Hosted_App_2_20_2013"
     ProductID="{d8eda873-90b8-4d34-b75b-0bb56a0718ea}"
     Version="1.0.0.0"
     SharePointMinVersion="15.0.0.0"
>
  <Properties>
    <Title>Test_Provider_Hosted_App_2_20_2013</Title>
    <StartPage>
https://spappinazure.azurewebsites.net/Pages/Default.aspx?{StandardTokens}</StartPage>
  </Properties>

  <AppPrincipal>
    <RemoteWebApplication ClientId="e432a156-56c9-46a4-a296-13ca4618fd86" />
  </AppPrincipal>
  <AppPermissionRequests>
    <AppPermissionRequest Scope="
http://sharepoint/content/sitecollection/web" Right="FullControl" />
    <AppPermissionRequest Scope="
http://sharepoint/content/sitecollection/web/list" Right="FullControl" />
    <AppPermissionRequest Scope="
http://sharepoint/content/sitecollection" Right="FullControl" />
  </AppPermissionRequests>
</App>

The OAuth pattern for SharePoint 2013 is new, and it takes some getting used to. My advice to you would be to build out small apps and get them working in a simple way, and then use a common approach to managing your token requests across your app. It is tricky, and it does take some prep and reading time. Invest some time to practice this, and you’ll find it a pretty powerful tool to begin to connect your Windows Azure apps with your SharePoint Apps.

Enjoy!

Steve