How to: Query a remote service using the web proxy in SharePoint 2013

apps for SharePoint

Learn how to access data in a remote domain from a page that is hosted in SharePoint 2013 by using the web proxy.

Last modified: July 01, 2013

Applies to: apps for SharePoint | Office 365 | SharePoint Foundation 2013 | SharePoint Server 2013

When you are building apps for SharePoint, you usually have to incorporate data from various sources. For security reasons, there are blocking mechanisms that prevent cross-domain communication. When you use the web proxy, the webpages in your app can access data in your remote domain and the SharePoint domain.

As a developer, you can use the web proxy exposed in client APIs, such as the JavaScript and .NET client object models. When you use the web proxy, you issue the initial request to SharePoint. In turn, SharePoint requests the data to the specified endpoint and forwards the response back to your page. Use the web proxy when you want the communication to occur at the server level. For more information, see Data access options for apps in SharePoint 2013.

To follow the steps in this example, you need the following:

  • Microsoft Visual Studio 2012

  • Office Developer Tools for Visual Studio 2012

  • A SharePoint 2013 development environment (app isolation required for on-premises scenarios)

For guidance on how to set up a development environment that fits your needs, see Start building apps for Office and SharePoint.

Core concepts to know before using the web proxy

The following table lists some useful articles that can help you understand the concepts involved in a cross-domain scenario in apps for SharePoint.

Table 1. Core concepts for the web proxy

Article title

Description

Apps for SharePoint overview

Learn about the new app model in SharePoint 2013 that enables you to create apps, which are small, easy-to-use solutions for end users.

Data access options for apps in SharePoint 2013

Learn about data access options in apps for SharePoint. This article provides guidance on the high-level alternatives you have to choose from when working with data in your app.

Host webs, app webs, and SharePoint components in SharePoint 2013

Learn about the difference between host webs and app webs. Find out which SharePoint 2013 components can be included in an app for SharePoint, which components are deployed to the host web, which components are deployed to the app web, and how the app web is deployed in an isolated domain.

Client-side Cross-domain Security

Explore cross-domain threats and use cases, security principles for cross-origin requests, and weigh the risks for developers to enhance cross-domain access from web applications that run in the browser.

To read data from a remote service, you must do the following:

  1. Create an app for SharePoint project.

  2. Modify the Default.aspx page to use the web proxy to query the remote service.

  3. Modify the app manifest to allow communication to the remote domain.

Figure 1 shows the browser window with data from the remote service in a SharePoint webpage.

Figure 1. SharePoint webpage with data from the remote service

SharePoint page with data from the remote service

To create the app for SharePoint project

  1. Open Visual Studio 2012 as administrator. (To do this, right-click the Visual Studio 2012 icon in the Start menu, and choose Run as administrator.)

  2. Create a new project using the App for SharePoint 2013 template

    Figure 2 shows the location of the App for SharePoint 2013 template in Visual Studio 2012, under Templates, Visual C#, Office SharePoint, Apps.

    Figure 2. App for SharePoint 2013 Visual Studio template

    App for SharePoint 2013 Visual Studio template
  3. Provide the URL of the SharePoint website that you want to use for debugging.

  4. Select SharePoint-hosted as the hosting option for your app.

To modify the Default.aspx page to use the web proxy by using the JavaScript object model

  1. Double-click the Default.aspx page in the Pages folder.

  2. Copy the following markup and paste it in the PlaceHolderMain content tag of the page. The markup performs the following tasks:

    • Provides a placeholder for the remote data.

    • References the SharePoint JavaScript files.

    • Prepares the request with a WebRequestInfo object.

    • Prepares the request Accept header to specify the response in the JavaScript Object Notation (JSON) format.

    • Issues a call to the remote endpoint.

    • Handles successful completion, rendering the remote data in the SharePoint webpage.

    • Handles any errors, rendering the error message in the SharePoint webpage.

    Categories from the Northwind database exposed as an OData service: 
        
    <!-- Placeholder for the remote content -->
    <span id="categories"></span>
    
    <!-- Add references to the JavaScript libraries. -->
    <script 
        type="text/javascript" 
        src="../_layouts/15/SP.Runtime.js">
    </script>
    <script 
        type="text/javascript" 
        src="../_layouts/15/SP.js">
    </script>
    <script type="text/javascript">
    (function () {
        "use strict";
    
        // Prepare the request to an OData source
        // using the GET verb.
        var context = SP.ClientContext.get_current();
        var request = new SP.WebRequestInfo();
        request.set_url(
            "http://services.odata.org/Northwind/Northwind.svc/Categories"
            );
        request.set_method("GET");
    
        // We need the response formatted as JSON.
        request.set_headers({ "Accept": "application/json;odata=verbose" });
        var response = SP.WebProxy.invoke(context, request);
    
        // Let users know that there is some
        // processing going on.
        document.getElementById("categories").innerHTML =
                    "<P>Loading categories...</P>";
    
        // Set the event handlers and invoke the request.
        context.executeQueryAsync(successHandler, errorHandler);
    
        // Event handler for the success event.
        // Get the totalResults node in the response.
        // Render the value in the placeholder.
        function successHandler() {
    
            // Check for status code == 200
            // Some other status codes, such as 302 redirect
            // do not trigger the errorHandler. 
            if (response.get_statusCode() == 200) {
                var categories;
                var output;
    
                // Load the OData source from the response.
                categories = JSON.parse(response.get_body());
    
                // Extract the CategoryName and Description
                // from each result in the response.
                // Build the output as a list.
                output = "<UL>";
                for (var i = 0; i < categories.d.results.length; i++) {
                    var categoryName;
                    var description;
                    categoryName = categories.d.results[i].CategoryName;
                    description = categories.d.results[i].Description;
                    output += "<LI>" + categoryName + ":&nbsp;" +
                        description + "</LI>";
                }
                output += "</UL>";
    
                document.getElementById("categories").innerHTML = output;
            }
            else {
                var errordesc;
    
                errordesc = "<P>Status code: " +
                    response.get_statusCode() + "<br/>";
                errordesc += response.get_body();
                document.getElementById("categories").innerHTML = errordesc;
            }
        }
    
        // Event handler for the error event.
        // Render the response body in the placeholder.
        // The body includes the error message.
        function errorHandler() {
            document.getElementById("categories").innerHTML =
                response.get_body();
        }
    })();
    </script>
    

(Optional) To modify the Default.aspx page to use the web proxy by using the REST endpoint

  1. Double-click the Default.aspx page in the Pages folder.

  2. Copy the following markup and paste it in the PlaceHolderMain content tag of the page. The markup performs the following tasks:

    • Provides a placeholder for the remote data.

    • References the jQuery library.

    • Prepares the request to the SP.WebRequest.Invoke endpoint.

    • Prepares the body of the request with a SP.WebrequestInfo object. The object includes an Accept header to specify the response in the JavaScript Object Notation (JSON) format.

    • Issues a call to the remote endpoint.

    • Handles successful completion, rendering the remote data in the SharePoint webpage.

    • Handles any errors, rendering the error message in the SharePoint webpage.

    Categories from the Northwind database exposed as an OData service: 
        
    <!-- Placeholder for the remote content -->
    <span id="categories"></span>
    
    <script 
        type="text/javascript" 
        src="//ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.0.min.js">
    </script>
    
    <script type="text/javascript">
    (function () {
        "use strict";
    
        // The Northwind categories endpoint.
        var url =
            "http://services.odata.org/Northwind/Northwind.svc/Categories";
    
        // Let users know that there is some
        // processing going on.
        document.getElementById("categories").innerHTML =
                    "<P>Loading categories...</P>";
    
        // Issue a POST request to the SP.WebProxy.Invoke endpoint.
        // The body has the information to issue a GET request
        // to the Northwind service.
        $.ajax({
            url: "../_api/SP.WebProxy.invoke",
            type: "POST",
            data: JSON.stringify(
                {
                    "requestInfo": {
                        "__metadata": { "type": "SP.WebRequestInfo" },
                        "Url": url,
                        "Method": "GET",
                        "Headers": {
                            "results": [{
                                "__metadata": { "type": "SP.KeyValue" },
                                "Key": "Accept",
                                "Value": "application/json;odata=verbose",
                                "ValueType": "Edm.String"
                            }]
                        }
                    }
                }),
            headers: {
                "Accept": "application/json;odata=verbose",
                "Content-Type": "application/json;odata=verbose",
                "X-RequestDigest": $("#__REQUESTDIGEST").val()
            },
            success: successHandler,
            error: errorHandler
        });
    
        // Event handler for the success event.
        // Get the totalResults node in the response.
        // Render the value in the placeholder.
        function successHandler(data) {
            // Check for status code == 200
            // Some other status codes, such as 302 redirect,
            // do not trigger the errorHandler. 
            if (data.d.Invoke.StatusCode == 200) {
                var categories;
                var output;
    
                // Load the OData source from the response.
                categories = JSON.parse(data.d.Invoke.Body);
    
                // Extract the CategoryName and Description
                // from each result in the response.
                // Build the output as a list
                output = "<UL>";
                for (var i = 0; i < categories.d.results.length; i++) {
                    var categoryName;
                    var description;
                    categoryName = categories.d.results[i].CategoryName;
                    description = categories.d.results[i].Description;
                    output += "<LI>" + categoryName + ":&nbsp;" +
                        description + "</LI>";
                }
                output += "</UL>";
    
                document.getElementById("categories").innerHTML = output;
            }
            else {
                var errordesc;
    
                errordesc = "<P>Status code: " +
                    data.d.Invoke.StatusCode + "<br/>";
                errordesc += response.get_body();
                document.getElementById("categories").innerHTML = errordesc;
            }
        }
    
        // Event handler for the error event.
        // Render the response body in the placeholder.
        // The 2nd argument includes the error message.
        function errorHandler() {
            document.getElementById("categories").innerHTML =
                arguments[2];
        }
    })();
    </script>
    
    

To edit the app manifest file

  1. In Solution Explorer, open the shortcut menu for the AppManifest.xml file, and choose View code.

  2. Copy the following RemoteEndPoints definition as a child of the App node.

    <RemoteEndpoints>
        <RemoteEndpoint Url=" http://services.odata.org" />
    </RemoteEndpoints>
    

    The RemoteEndpoint element is used to specify the remote domain. The web proxy validates that the requests issued to remote domains are declared in the app manifest. You can create up to 20 entries in the RemoteEndpoints element. Only the authority part is considered; http://domain:port and http://domain:port/website are considered the same endpoint. You can issue calls to many different endpoints within the same domain with just one RemoteEndpoint definition.

To build and run the solution

  1. Press the F5 key.

    Note Note

    When you press F5, Visual Studio builds the solution, deploys the app, and opens the permissions page for the app.

  2. Choose the Trust It button.

  3. Click the app icon in the Site Contents page.

    Figure 3 shows the remote data in the SharePoint webpage.

    Figure 3. Remote data in the SharePoint webpage

    SharePoint page with data from the remote service
Table 2. Troubleshooting the solution

Problem

Solution

Visual Studio does not open the browser after you press the F5 key.

Set the app for SharePoint project as the startup project.

The scheme-port combination is not supported.

The call schema-port combination must fall within the following criteria:

Scheme

Port

http

80

https

443

http or https

7000-10000

Important note Important

The outbound ports are subject to host firewall availability. In particular, only http-80 and https-443 are available on SharePoint Online.

Unhandled exception SP is undefined.

Make sure you can access the SP.RequestExecutor.js file in a browser window.

If you are using your local server as your development environment, you must disable IIS loopback check. Run the following command from a Windows PowerShell command prompt.

New-ItemProperty HKLM:\System\CurrentControlSet\Control\Lsa -Name "DisableLoopbackCheck" -value "1" -PropertyType dword
Caution noteCaution

Disabling the IIS loopback check is not recommended in a production environment.

The size of the response from the remote endpoint exceeds the configured limit.

The response’s size of web proxy requests must not be larger than 200 KB.

This article demonstrated how to read data in a remote service from a SharePoint webpage. As a next step, you can learn about other data access options that are available in apps for SharePoint. To learn more, see the following:

Community Additions

ADD
Show:
© 2014 Microsoft