Contents tagged with JSOM

  • SharePoint 2013: How to refresh the Request Digest value in JavaScript

    Tags: SharePoint 2013, JSOM, Security

    Introduction

    SharePoint 2013 (and previous versions) uses a client side “token” to validate posts back to SharePoint to prevent attacks where the user might be tricked into posting data back to the server. This token is known by many names; form digest or message digest or request digest. The token is unique to a user and a site and is only valid for a (configurable) limited time.

    When building Apps or customizations on top of SharePoint, especially using patterns such as Single Page Applications (SPA) or using frameworks such as knockout.js it is very common that you see errors due to that the token is invalidated, which is due to that you have not reloaded the page and the token has timed out. The purpose of this article is to show you how you can refresh this form digest using JavaScript.

    How to use the Request Digest token

    When working with CSOM or REST you need to add the Request Digest token to your request. Well, with CSOM (JSOM) it is done for you under the hood, but when you handcraft your REST queries you need to manually add them. It usually looks something like this:

    $.ajax({
        url: _spPageContextInfo.siteAbsoluteUrl + "/_api/web/,,,",
        method: "POST",
        headers: { 
            "Accept": "application/json; odata=verbose", 
            "X-RequestDigest": $('#__REQUESTDIGEST').val() 
        },
        success: function (data) {},
        error: function (data, errorCode, errorMessage) {}
    });

    On line #6 we add the “X-RequestDigest” header, with the value of the hidden input field “__REQUESTDIGEST” – which is the form digest value. I will not dig deeper into this since it’s part of basically every SharePoint POST/REST sample on the interwebs.

    But what happens if you’ve built a page (SPA application) where you don’t reload the page and the users work on the page for longer times than the token timeout (default 30 minutes). Then they will get exceptions like these:

    HTTP/1.1 403 FORBIDDEN
    {"error":{"code":"-2130575252, Microsoft.SharePoint.SPException","message":{
    "lang":"en-US",
    "value":"The security validation for this page is invalid and might be corrupted. 
    Please use your web browser's Back button to try your operation again."}}}

    How to refresh the token

    So how do we get a new and updated token? There are multiple ways to refresh the token, or retrieve a new and updated one. The two most common ways are to either use ye olde web services and call into the /_vti_bin/sites.asmx and use the GetUpdatedFormDigest method. To use this you have to create a SOAP message and then parse the response and retrieve the updated token. You can then either pass that new token for your subsequent requests, or even better update the hidden __REQUESTDIGEST field. The second one is to use the new REST POST endpoint /_api/contextinfo and then parse that response which can be either XML or JSON. This is how to do it the JSON way:

    $.ajax({
        url: _spPageContextInfo.webAbsoluteUrl + "/_api/contextinfo",
        method: "POST",
        headers: { "Accept": "application/json; odata=verbose"},
        success: function (data) {
            $('#__REQUESTDIGEST').val(data.d.GetContextWebInformation.FormDigestValue)
        },
        error: function (data, errorCode, errorMessage) {
            alert(errorMessage)
        }
    });

    It’s also worth noticing that for every REST query SharePoint actually generates a new Form Digest which is sent back as a response header (X-RequestDigest), so you could always read that response header and update the form digest.

    Also, if you’re not using JavaScript but instead building an app using other frameworks, platforms, languages etc – you can always use the two aforementioned methods to update the token. Well, you actually need to do it since you don’t have any hidden input field :)

    How to do it the best and native way

    The drawbacks with the methods above is that you have to either request a new form digest all the time to make sure that it is up to date, or catch the exception and retry your query. And as we all know this will lead to bad performance and/or cluttered JavaScript code (like we don’t have enough of that already!).

    Fortunately there is a native method for refreshing the token built-in to the SharePoint JavaScript libraries. It’s a function called UpdateFormDigest(). It’s defined in INIT.js. The method takes two parameters, first of all the URL to the current site (remember the token is only valid for one site) and secondly it takes an update interval parameter. The update interval value is also already given to us, using a global constant called _spFormDigestRefreshInterval. And this is how you should use the function:

    UpdateFormDigest(_spPageContextInfo.webServerRelativeUrl, _spFormDigestRefreshInterval)
    As you can see, it’s very simple, only use built-in stuff and there’s no magic to it. Under the hood this method uses the /_vti_bin/sites.asmx method and it does it synchronously. This means that all you have to do is copy and paste this line into your own code just before your REST calls. The other smart thing about this method is that is uses the update interval and only updates the form digest when needed – so no extra calls.

    Summary

    There you have it – no more security validation issues with your SPA applications in SharePoint 2013. All you have to do is copy and paste the line above and stay on the safe side.

  • SharePoint 2013 Managed Metadata field and CSOM issues in 2010-mode sites

    Tags: SharePoint 2013, SharePoint 2010, CSOM, JSOM

    Introduction

    SharePoint 2013 introduces a new model on how Site Collections are upgraded using the new Deferred Site Collection Upgrade. To keep it simple it means that SharePoint 2013 can run a Site Collection in either 2010 mode or 2013 mode, and SharePoint 2013 contains a lot of the SharePoint 2010 artifacts (JS files, Features, Site Definitions) to handle this. When you’re doing a content database attach to upgrade from 2010 to 2013, only the database schema is upgraded and not the actual sites (by default). The actual Site Collection upgrade is done by the Site Collection administrator when they feel that they are ready to do that and have verified the functionality of SharePoint 2013 (or you force them to upgrade anyways). But, the Site Collection admin might have to upgrade sooner than expected for some sites.

    Upgrade troubles

    This post is all about what has happened to us when our Office 365 SharePoint Online (SPO) tenant had been upgraded (and right now the Site Collection upgrade is disabled for us so we can’t do anything about it). The limitations of customizations in the 2010 version of SPO was very limited (to be kind) and we embraced JavaScript (which people have despised for a decade and now suddenly think is manna from heaven). We also leveraged Managed Metadata in a lot of lists, libraries and sites. We’ve built Web Parts using JavaScript CSOM to render information and also .NET CSOM stuff running in Windows Azure doing background work. Once our tenant was upgraded to 2013 all of the customizations using Managed Metadata stopped to work…

    JSOM sample with Managed Metadata

    I will show you one example of what works in SharePoint 2010 and what does not work in SharePoint 2013 when you’re site is running in 2010 compatibility mode.

    Assume we have a simple list with two columns; Title and Color, where Color is a Managed Metadata Field. To render this list using JSOM we could use code like this in a Web Part or Content Editor or whatever.

    var products;
    function loadProducts() {
    	document.getElementById('area').innerHTML = 'Loading...';
    	var context = new SP.ClientContext.get_current();
    	var web = context.get_web();
    	var list = web.get_lists().getByTitle('TestList');
    	products = list.getItems('');
    	context.load(products, 'Include (Title, Color)');
    	
    	context.executeQueryAsync(function() {
    		var collection = products.getEnumerator();
    		var html = '<table>'
    		while(collection.moveNext()) {
    			var product = collection.get_current();
    			html +='<tr><td>'
    			html += product.get_item('Title');
    			html += '</td><td>'
    			html += product.get_item('Color').split('|')[0];
    			html += '</td></tr>'			
    		}
    		html += '</table>'
    		document.getElementById('area').innerHTML = html;
    	}, function() {
    		document.getElementById('area').innerHTML = 'An error occurred';
    	});
    }
    ExecuteOrDelayUntilScriptLoaded(loadProducts, 'sp.js');

    As you can see a very simple approach. We’re reading all the items from the list and rendering them as a table, and this html table is finally inserted into a div (with id = area in the example above). This should look something like this when rendered:

    JSOM Rendering in SharePoint 2010

    The key here is that Managed Metadata in 2010 JSOM is returned as a string object (2010 .NET CSOM does that as well). This string object is a concatenation of the Term, the pipe character (|) and the term id. So in the code sample above I just split on the pipe character and take the first part. There was no other decent way to do this in SharePoint 2010 and I’ve seen a lot of similar approaches.

    Same code running in SharePoint 2013 on a SharePoint 2010 mode site

    If we now take this site collection and move it to SharePoint 2013 or recreate the solution on a 2010 mode site in SharePoint 2013. Then we run the same script, then this is what we’ll see, something goes wrong…

    Failed JSOM Rendering

    You might also see a JavaScript error, depending on your web browser configuration. Of course proper error handling could show something even more meaningful!

    JSOM Runtime exception

    Something is not working here anymore!

    What really happens is that the CSOM client service do not return a string object for Managed Metadata but instead a properly typed TaxonomyFieldValue. But that type (SP.Taxonomy.TaxonomyFieldValue) does not exist in the 2010 JSOM. Remember I said that SharePoint 2013 uses the old 2010 JavaScripts when running in 2010 compatibility mode. Unfortunately there is no workaround, unless we roll our own SP.Taxonomy.TaxonomyFieldValue class (but that’s for another JS whizkid to fix, just a quick tip to save you the trouble – you cannot just add the 2013 SP.Taxonomy,js to your solution).

    So why is this so then?

    If we take a closer look at what is transferred over the wire we can see that when running on SharePoint 2010 the managed metadata is transferred as strings:

    Fiddler trace on SharePoint 2010

    But on SharePoint 2013 it is typed as a TaxonomyFieldValue object:

    Fiddler trace on SharePoint 2013

    It’s a bit of a shame, since the server is actually aware of that we’re running the 2010 (14) mode client components! (SchemaVersion is what we sent from the CSOM and LibraryVersion is the library used on the server side)

    Fiddler trace on SharePoint 2013

    I do really hope that the SharePoint team think about this for future releases – respect the actual schema used/sent by the Client Object Model!

    Of course, this JavaScript solution will not work as-is when upgrading the Site Collection to 2013 mode. That is expected and that’s what the Evaluation sites are for.

    What about .NET CSOM?

    We have a similar issue in .NET CSOM, even though we don’t get a SharePoint CSOM runtime exception. Instead of returning a string object you will get back a Dictionary with Objects as values – but if you’re code is expecting a string you still get the exception. So in 99% of the cases it will fail here as well.

    Nothing exciting here, move along...

    Summary

    Deferred Site Collection update might be a good idea and you might think that your customizations will work pretty well even after an upgrade to SharePoint 2013, just as long as you don’t update your actual Site Collections to 2013. But you’ve just seen that this is not the case.

    Happy easter!

About Wictor...

Wictor Wilén is the Nordic Digital Workplace Lead working at Avanade. Wictor has achieved the Microsoft Certified Architect (MCA) - SharePoint 2010, Microsoft Certified Solutions Master (MCSM) - SharePoint  and Microsoft Certified Master (MCM) - SharePoint 2010 certifications. He has also been awarded Microsoft Most Valuable Professional (MVP) for seven consecutive years.

And a word from our sponsors...