Tagged: Office 365

Getting “Unexpected response data from server” error using SharePoint JSOM?

I was clearing the dust off an old demo for my session on cloud-hosted apps at SharePointFest DC next month when I ran into a problem. As I walked through the demo (which I had given three times before at SPS Events in Boston, Baltimore, and DC), I was getting an error when testing my ability to query for list data in my cloud-hosted app’s app web in my Office 365 developer tenant using JSOM:jsrequestfailedKnowing this script had worked for months in the past, I turned to the Internet. Sure enough, others appeared to be experiencing the same problem. One app developer even worked around the problem by abandoning the use of JSOM altogether in favor of the REST APIs.

What’s the problem here?

In a cloud-hosted app, the app’s business logic is deployed to a remote web (separate from its app web, which resides in SharePoint). This remote web is likely on a different domain (and is definitely on a different domain if you are using SharePoint Online). Querying for data that resides in the app web from a script running in your remote web requires the use of cross-domain JavaScript calls, which are generally blocked for security reasons. To work around this requires the use of the JavaScript Cross-Domain Library (sp.requestexecutor.js).

My demo script looked like this:

var clientContext = new SP.ClientContext(appweburl);
var appWeb = clientContext.get_web();

appWebList = appWeb.get_lists().getByTitle(listname);
var camlQuery = new SP.CamlQuery();
camlQuery.set_viewXml("<View><RowLimit>50</RowLimit></View>");
appWebListItems = appWebList.getItems(camlQuery);
clientContext.load(appWebList);
clientContext.load(appWebListItems);
clientContext.executeQueryAsync(onAppWebGetListDataSuccess, onJSOMError);

Once I initialized the ProxyWebRequestExecutorFactory object and set it as the factory of my ClientContext object, everything worked as expected. (NOTE: The script in my demo that queried for data in the host web was already making proper use of the cross-domain library.)

Here is the proper script to initialize the ClientContext and associate the appropriate ProxyWebRequestExecutorFactory with it:

var clientContext = new SP.ClientContext(appweburl);
var factory = new SP.ProxyWebRequestExecutorFactory(appweburl);
clientContext.set_webRequestExecutorFactory(factory);
var appWeb = clientContext.get_web();

// Remaining code is the same as above

Conclusion

I’m not sure exactly what changed that would cause this problem to start occurring. Common sense dictates that the ProxyWebRequestExecutorFactory should be needed for all cross-domain calls, whether they be to the host web or the app web. I’m less concerned about that than why the old code ever worked (that did not make use of it). Nonetheless, if you find yourself in a situation where a script that definitely worked in the past now fails with an “Unexpected response data from server” error when using the JSOM, ensure you are making proper use of the cross-domain library as well.

Accessing SharePoint Data from Provider-Hosted Apps: Use the Right Context

I have spent the better part of the last two years working with the new app development model for SharePoint 2013. Recently I have focused on building apps that access, manipulate, and interact with data stored in SharePoint Online with Office 365. If you have done any development using the client-side object model (CSOM) for SharePoint, you understand the importance of instantiating the proper ClientContext object to access data in a particular SharePoint site. The ClientContext constructor takes as an argument the URL of a SharePoint site and allows you to access data stored in the Lists collection of the Web associated with it. In this post, I will discuss the various context objects you should use in your provider-hosted app depending on where the data your app needs to access resides and if the user’s permissions need to be considered. If you have been developing apps for SharePoint for awhile now (and even if you haven’t), I strongly encourage you to use Visual Studio 2013 and the Office Developer Tools for Visual Studio 2013 – March 2014 Update.

Host webs and app webs

When dealing with apps for SharePoint, you will become familiar with host webs and app webs:

  • Host web – the SharePoint site to which an app is installed
  • App web – the special isolated site (a unique app web is provisioned for each installation of the app) where the app for SharePoint’s internal components and content, such as lists, content types, workflows, and pages, are deployed

Note that a provider-hosted app is not required to have an app web, and in fact may not need one depending on your business requirements.

Your app will always have Full Control permissions to its app web. However, your app will need to request (and be granted) permissions by the user installing your app in order to access data in the host web. This is handled through the app manifest.

If your app needs to access data in the SharePoint site where it is being installed, you will be working with a host web context of some sort. As you will see, there are actually two different host web context objects, depending on the app authorization policy you choose.

Life made easy, thanks to SharePointContext.cs

When you create a new provider-hosted app in Visual Studio 2013, you have the option to create a new ASP.NET Web Forms or MVC application to serve as your app’s remote web application. If you are using the Office Developer Tools for Visual Studio 2013 – March 2014 Update, you also have the option to convert an existing ASP.NET web application to an app for SharePoint project (really cool!) In either case, you will notice that SharePointContext.cs is added to the remote web application project. This file contains class definitions for SharePointAcsContext and SharePointHighTrustContext, which allow you to create host web and app web context objects based on whether your trust broker is ACS (which it is with Office 365) or if you are on premises. I won’t delve into too much more detail in this post, but Kirk Evans has an outstanding writeup about these classes.

Accessing data in the app web

To access data in the SharePoint app web from your app, use the following pattern:

CSOM (C#)

var spContext = SharePointContextProvider.Current.GetSharePointContext(Context);

using (var clientContext = spContext.CreateUserClientContextForSPAppWeb())
{
    Web web = clientContext.Web;
    clientContext.Load(web);
    clientContext.ExecuteQuery();

    ListCollection lists = web.Lists;
    clientContext.Load<ListCollection>(lists);
    clientContext.ExecuteQuery();
}

REST (C#)

var spContext = SharePointContextProvider.Current.GetSharePointContext(Context);
HttpWebRequest listRequest = (HttpWebRequest)HttpWebRequest.Create(spContext.SPAppWebUrl + "/_api/web/lists");
listRequest.Method = "GET";
listRequest.Accept = "application/atom+xml";
listRequest.ContentType = "application/atom+xml;type=entry";
listRequest.Headers.Add("Authorization", "Bearer " + spContext.UserAccessTokenForSPAppWeb);

JSOM

var appweburl = decodeURIComponent(getQueryStringParameter("SPAppWebUrl"));
var clientContext = new SP.ClientContext(appweburl);
var appWeb = clientContext.get_web();
var appWebListColl = appWeb.get_lists();
clientContext.load(appWebListColl);
clientContext.executeQueryAsync(onAppWebGetListSuccess, onError);

Accessing data in the host web

To access data in the SharePoint host web (the SharePoint site where your app is installed) from your app, use the following pattern:

CSOM (C#)

var spContext = SharePointContextProvider.Current.GetSharePointContext(Context);

using (var clientContext = spContext.CreateUserClientContextForSPHost())
{
    Web web = clientContext.Web;
    clientContext.Load(web);
    clientContext.ExecuteQuery();

    ListCollection lists = web.Lists;
    clientContext.Load<ListCollection>(lists);
    clientContext.ExecuteQuery();
}

REST (C#)

var spContext = SharePointContextProvider.Current.GetSharePointContext(Context);
HttpWebRequest listRequest = (HttpWebRequest)HttpWebRequest.Create(spContext.SPAppWebUrl + "/_api/web/lists");
listRequest.Method = "GET";
listRequest.Accept = "application/atom+xml";
listRequest.ContentType = "application/atom+xml;type=entry";
listRequest.Headers.Add("Authorization", "Bearer " + spContext.UserAccessTokenForSPHost);

JSOM

var appweburl = decodeURIComponent(getQueryStringParameter("SPAppWebUrl"));
var hostweburl = decodeURIComponent(getQueryStringParameter("SPHostUrl"));
var clientContext = new SP.ClientContext(appweburl);
var factory = new SP.ProxyWebRequestExecutorFactory(appweburl);
clientContext.set_webRequestExecutorFactory(factory);
var appContextSite = new SP.AppContextSite(clientContext, hostweburl);
var hostWeb = appContextSite.get_web();
hostWebListColl = hostWeb.get_lists();
clientContext.load(hostWebListColl);
clientContext.executeQueryAsync(onHostWebGetListSuccess, onJSOMError);

Note that using JSOM, we still need to construct a ClientContext for the app web before we generate an AppContextSite for the host web, made possible through the SP.ProxyWebRequestExecutorFactory.

A note about the app-only authorization policy

By default, authorization checks in the host web succeed only if both the current user and the app have sufficient permissions to perform the action in question, such as reading from or writing to a list. We are reminded that the user’s permissions are taken into account based on the names of the context and access token objects we use in these scenarios: for instance, CreateUserClientContextForSPHost and UserAccessTokenForSPHost. However, your app has the ability to do something akin to running with elevated privileges using the app-only policy for authorization. Also controlled through the app manifest, the app-only policy is useful when an app doesn’t need or want to consider the permissions of the current user. In Visual Studio 2013, you can specify that your app would like to have the ability to use the app-only policy by checking this box in the AppManifest.xml editor, on the Permissions tab:

apponly

That being said, just because your app is granted this permission does not mean that you can use the same host web context or access token as before to automatically leverage it. To access data from the SharePoint host web (taking only your app’s permissions into account and ignoring the current user’s permissions) from your app, use the following pattern:

CSOM (C#)

var spContext = SharePointContextProvider.Current.GetSharePointContext(Context);

using (var clientContext = spContext.CreateAppOnlyClientContextForSPHost())
{
    Web web = clientContext.Web;
    clientContext.Load(web);
    clientContext.ExecuteQuery();

    ListCollection lists = web.Lists;
    clientContext.Load<ListCollection>(lists);
    clientContext.ExecuteQuery();
}

REST (C#)

var spContext = SharePointContextProvider.Current.GetSharePointContext(Context);
HttpWebRequest listRequest = (HttpWebRequest)HttpWebRequest.Create(spContext.SPAppWebUrl + "/_api/web/lists");
listRequest.Method = "GET";
listRequest.Accept = "application/atom+xml";
listRequest.ContentType = "application/atom+xml;type=entry";
listRequest.Headers.Add("Authorization", "Bearer " + spContext.AppOnlyAccessTokenForSPHost);

Remember that in order to use the app-only policy, your app must request and be granted this permission by the site owner who installs your app. Also note that there is no JSOM example using the app-only policy because apps that do not make OAuth authenticated calls (such as apps that are only JavaScript running in the app web) cannot use the app-only policy.

As you can see, the code you write in each of the above scenarios (accessing data in the app web, host web, or using the app-only authorization policy) is identical except for the method or property you use from the SharePointContext class to get the appropriate context or access token. Understanding these subtle differences is vitally important when making sure your app has the ability to access and manipulate the SharePoint data it needs.

SPS Events DC (Chevy Chase) Recap

A huge thank you to everyone who came out to SPS Events DC at the Microsoft office in Chevy Chase, MD today! I was honored to represent Fulcrum at my fourth SPS Event so far in 2014 and speak to a crowd of developers and IT professionals about cloud-hosted apps for SharePoint 2013.

With the recent news from the Office 365 Team about the Autohosted Apps Preview Program (spoiler alert: it ends June 30th), I have refined this talk to focus almost exclusively on Provider-hosted apps for SharePoint 2013. If your organization has made any investments in Autohosted apps (and each of the last two times I have given this talk, at least one person in the audience has), there is a step-by-step guide for transitioning your Autohosted apps to Provider-hosted apps here.

There was tremendous audience participation during my session today, which I always appreciate. We had lots of good discussions about “the art of the possible” with Provider-hosted apps, including when to use CSOM, JSOM, and/or REST in our apps. We also discussed OAuth and the cross-domain library, which allow us to securely access and manipulate data stored in SharePoint from external web applications, whether they live on-premises or in the cloud.

I love speaking at SPS Events DC, which happen each year in Reston and Chevy Chase. The team of organizers and volunteers who put this event together are second to none, and it’s always fun to catch up with so many of my friends and colleagues in the DC SharePoint community.

My slide deck from today’s session is below. The code I used in my sample Provider-hosted app may be downloaded here. Feel free to reach out to me in the comments or on Twitter if you have any questions!

SharePoint Event brings Fulcrum to Boston

Photo courtesy @SPBrennan

As you read in my previous post, Fulcrum frequently travels across Virginia and the DC metro area to speak about the capabilities of the SharePoint platform to software developers, IT professionals, and end users at SharePoint user groups and one-day conferences known as SPS (SharePoint Saturday) Events. These events are held in cities around the world and are completely free to the public. The speakers and attendees at these events volunteer their time and sacrifice a Saturday to help others learn more about SharePoint and all the possibilities it offers. On April 12th, I headed north to Beantown to present at the SPS Boston Event at the Microsoft office in Cambridge, Massachusetts.

Fulcrum develops and maintains many custom solutions built on the SharePoint platform for our Army INSCOM and Department of Education customers, among others. Many of these solutions are built using a paradigm known as “farm solutions,” where custom code utilizes resources on the same servers that run SharePoint. This can potentially have an adverse impact on the performance of the SharePoint environment. To address this, SharePoint 2013 introduces a brand new app development model that allows custom code to be deployed anywhere, including the cloud or even a Java application server! I presented a session entitled “Build Secure Cloud-Hosted Apps for SharePoint 2013.” In this session, I demonstrated different ways that apps hosted in the cloud can securely work with data stored in SharePoint and discussed how the new app model has the potential to revolutionize SharePoint development, making SharePoint farms run more reliably and efficiently while helping our customers to realize significant cost savings.

If you are interested in learning more about SharePoint 2013 and the new app development model, I encourage you to reach out to me—or any other member of the SharePoint community—anytime. Members of the SharePoint community pride themselves on being accessible and are eager to share their knowledge, guidance, and advice with other SharePoint users around the world. To find the next SPS Event near you, visit http://spsevents.org.

Fulcrum Presents at Regional SharePoint Events

Many of our government customers leverage different versions of SharePoint to collaborate, automate business processes, and share data. Fulcrum has developed numerous custom solutions built on the SharePoint platform. In addition to being a robust and feature-rich platform, SharePoint is widely known for its enthusiastic community of developers, administrators, and end users who freely volunteer their time and energy to share their knowledge at one-day conferences known as SPS (SharePoint Saturday) Events, as well as local and regional SharePoint user groups around the world. These events are completely free to the public, who also volunteer their time to learn more about SharePoint and all the possibilities it offers. I have had the privilege of representing the talented SharePoint professionals at Fulcrum, presenting at several such events over the past few months.

Last November 7th, I presented an introductory session on the new app development model for SharePoint 2013 at the Federal SharePoint User Group and Women in SharePoint DC. This paradigm shift for custom development promises greater reliability and up-time in on-premises SharePoint environments like the ones our customers rely on for critical mission operations. On January 11th, I had the privilege of presenting at SPS Events – Virginia Beach. This was the third year I have spoken at this event. My session was entitled Put it on a Map! Using the new Location and Map Features in SharePoint 2013. As the name implies, I spoke about the many enhancements the latest version of SharePoint offers with respect to “geolocation metadata”—essentially plotting data associated with a particular location on a map. This gives us the potential to bring engaging mapping solutions to our clients and their customers more readily and reliably than ever before. These capabilities are of particular interest to our defense and military customers, where enabling our Armed Forces to quickly and efficiently find information based on a geographic location can save lives. I also presented the Put it on a Map! session at the Reston SharePoint User Group on March 10th.

I will be representing Fulcrum at SPS Events – Boston on April 12th and at several other SPS Events and user groups in the months ahead, presenting more advanced sessions about building secure cloud-hosted apps for SharePoint 2013.

If you are currently using SharePoint, or are just interested in learning more about it, I encourage you to reach out to me—or any other member of the SharePoint community—anytime. Members of the SharePoint community pride themselves on being accessible and are eager to share their knowledge, guidance, and advice with other SharePoint users around the world. If you are interested in learning more about Fulcrum’s capabilities, I encourage you to visit our website at http://www.fulcrumco.com.