0

Is there any way to call the SharePoint Web Services in host web from JavaScript in a SharePoint hosted app web on O365?

Have tried RequestExecutor however stuck with 415 - unsupported media type issues.

WebProxy.invoke is returning an authorization error & no way to push credentials.

  • I suggest you post your code for a more detailed answer – Rob Windsor Oct 17 '16 at 21:35
1

Got this working using a Custom Page Proxy, RequestExecutor, on an app that has full control of the site collection on a separate domain.

See the following KB articles & code sample for basics of the technique: https://msdn.microsoft.com/en-us/library/office/fp161183.aspx https://code.msdn.microsoft.com/sharepoint-2013-get-data-10039ff1

We're using a page (iframe) hosted on remote domain to authorize and proxy the cross domain calls. So we need:

1) Custom Proxy Page (iframe) - See the above articles for the proxy page, it's merely a static aspx page sitting on the SP Site Collection.
- I named mine rawsproxy.aspx. - To make the example work on SP you need to add the following ASPX headers:

<%@ Page Language="C#" Inherits="Microsoft.SharePoint.WebPartPages.WebPartPage, Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
  • Moreover add the following control to ensure the proxy page can be loaded in an iframe: <WebPartPages:AllowFraming ID="AllowFraming" runat="server" __WebPartId="{0B59B320-402B-4BC0-A66B-F91F3A8A364A}" />

  • Finally remove any http references to scripts so it can run in https (replace "http://" with "//" or "https://")

2) JavaScript adapter in SharePoint Hosted App

// $q is Q promise library at: https://github.com/kriskowal/q
// declare soap & site 
var SOAP = {
       header      : "<soap:Envelope xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'><soap:Body>",
       footer      : "</soap:Body></soap:Envelope>",
   namespace   : "http://schemas.microsoft.com/sharepoint/soap/"
},
siteURL = "https://tenant.sharepoint.com";

// call the service using $q promises
postService({
    siteURL : siteURL,
    url: siteURL + "/_vti_bin/webs.asmx",
    methodName: "UpdateContentTypeXmlDocument",
    args: {
        contentTypeId: "0x002",
        newDocument: "<mtw:customXml xmlns:mtw=\"http://makingthings.work/2016/schema\">Some custom data here...</mtw:customXml>"
    }
}).then(function(result) {
// process result here
}).catch(function(err) {
// some ugly error trapping here
});

// the post service call, executes the cross domain query
function postService(p) {

  if (!p.methodName)    throw new Error("No method name in web service call: " + p.url);
  if (!p.siteURL)       throw new Error("No site url in web service call!");
  if (!p.url)       throw new Error("No url in web service call!");
  if (!p.soapAction)    p.soapAction = SOAP.namespace + p.methodName;

  var xml = p.bodyXml || buildWebServiceBody(p),
      payload = SOAP.header + xml + SOAP.footer,
      def = $q.defer(),
      post = {
          url: p.url,
              method: "POST",
              headers: {
                  SOAPAction: p.soapAction,
                      "Content-Type": "text/xml;charset='utf-8'"
              },
              body: payload,
              success: function (data) {
                  def.resolve(data);
              }, 
              error: function (err) {
                  def.reject(err);
              }
      },
      ex = new SP.RequestExecutor(p.siteURL);

  // modify the iframe source to point to rawsproxy and append the site url
  ex.iFrameSourceUrl = "rawsproxy.aspx?SPHostUrl=" + encodeURIComponent(p.siteURL);

  // execute the async call using callbacks to resolve promises
  ex.executeAsync(post);

  // return the promise
  return def.promise;

}

// removed character escaping for simplicity
function buildWebServiceBody(p){

    if(p.bodyXml) return p.bodyXml;
    var body = ("<" + p.methodName + " xmlns=\"" + (p.namespace || SOAP.namespace) + "\">");
    if(p.args){
        $.each(p.args, function(key, value) {
            body += "<" + key + ">" + value + "</" + key + ">";
        });
    }
    body += ("</" + p.methodName + ">");
    return body;
}
0

Yes, you can call the CSOM or REST web services from JavaScript in a SharePoint-Hosted App. This is true whether you're targeting the App Web or the Host Web.

You don't need to use the WebProxy to call SharePoint web services. That's used when you're calling external web services. You also don't need to attach credentials, the credentials of the currently logged-in user will always be used.

You need to use SP.AppContextSite to make calls to the Host Web. Here are some simple code examples:

// Call to the App Web from CSOM
function appWebCsom() {
    var context = SP.ClientContext.get_current();
    var web = context.get_web();
    context.load(web);
    context.executeQueryAsync(success, fail);

    function success() {
        var message = jQuery("#message");
        message.text(web.get_title());
    }

    function fail(sender, args) {
        alert("Call failed. Error: " +
            args.get_message());
    }
}

// Call to the Host Web from CSOM
function hostWebCsom() {
    var hostUrl = GetUrlKeyValue("SPHostUrl");

    var context = SP.ClientContext.get_current();
    var hostContext = new SP.AppContextSite(context, hostUrl);
    var web = hostContext.get_web();
    context.load(web);
    context.executeQueryAsync(success, fail);

    function success() {
        var message = jQuery("#message");
        message.text(web.get_title());
    }

    function fail(sender, args) {
        alert("Call failed. Error: " + args.get_message());
    }
}

// Call to the App Web from the REST API
function appWebRest() {
    var call = jQuery.ajax({
        url: _spPageContextInfo.webAbsoluteUrl + "/_api/Web/",
        type: "GET",
        dataType: "json",
        headers: {
            Accept: "application/json;odata=verbose"
        }
    });
    call.done(function (data, textStatus, jqXHR) {
        var message = jQuery("#message");
        message.text(data.d.Title);
    });
    call.fail(failHandler);
}

// Call to the Host Web from the REST API
function hostWebRest() {
    var hostUrl = GetUrlKeyValue("SPHostUrl");

    var call = jQuery.ajax({
        url: _spPageContextInfo.webAbsoluteUrl + "/_api/SP.AppContextSite(@target)/Web/?@target='" + hostUrl + "'",
        type: "GET",
        dataType: "json",
        headers: {
            Accept: "application/json;odata=verbose"
        }
    });
    call.done(function (data, textStatus, jqXHR) {
        var message = jQuery("#message");
        message.text(data.d.Title);
    });
    call.fail(failHandler);
}

function failHandler(jqXHR, textStatus, errorThrown) {
    var response = "";
    try {
        var parsed = JSON.parse(jqXHR.responseText);
        response = parsed.error.message.value;
    } catch (e) {
        response = jqXHR.responseText;
    }
    alert("Call failed. Error: " + response);
}
  • Thanks Rob - I am actually trying to call the SharePoint XML Web Service webs.asmx ... the feature I'm looking for is the UpdateContentTypeXmlDocument method which isn't supported in JSOM or REST.... msdn.microsoft.com/en-us/library/dd927334(v=office.12).aspx – thastark Oct 17 '16 at 22:34
  • Unfortunately that isn't supported. You can't use SP.AppContextSite with the ASMX web services so there is no way to switch context from the App Web to the Host Web. – Rob Windsor Oct 18 '16 at 1:41
  • May not be supported but got it working using a Custom Proxy Page and RequestExecutor.... Will post solution shortly... – thastark Oct 18 '16 at 18:09
  • Also for anyone curious, WebProxy does NOT federate authentication or authorization including O365 X-Domain calls (no tokens passed nada)... Otherwise it'd be a convenient way to to access these services in a less hacky way than going the Custom Proxy Page route.... – thastark Oct 18 '16 at 19:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.