RSS Feed Feed your read!

Scot Hillier is an independent consultant and Microsoft SharePoint Most Valuable Professional focused on creating solutions for Information Workers with SharePoint, Office, and related .NET technologies. A frequent speaker at TechEd and SharePoint Connections, he is also the author many books on Microsoft technologies including 5 for SharePoint 2010. Scot splits his time between consulting on SharePoint projects and training for Critical Path Training. Scot is a former U. S. Navy submarine officer and graduate of the Virginia Military Institute. Scot can be reached at scot@shillier.com

Archives

January 2010 (17)
February 2010 (1)
March 2010 (1)
April 2010 (2)
May 2010 (1)
June 2010 (1)
August 2010 (4)
September 2010 (6)
October 2010 (3)
November 2010 (2)
February 2011 (1)
March 2011 (4)
April 2011 (3)
May 2011 (1)
August 2011 (1)
March 2012 (1)
April 2012 (1)
July 2012 (3)
August 2012 (1)
September 2012 (1)
October 2012 (2)
November 2012 (3)
January 2013 (2)
February 2013 (3)
March 2013 (3)
April 2013 (3)
May 2013 (1)
September 2013 (2)
November 2013 (5)
January 2014 (2)
February 2014 (2)
March 2014 (1)
April 2014 (1)
May 2014 (1)
July 2014 (1)

Links

IT Unity
SharePoint Team Blog
Andrew Connell's Blog

Tag Cloud

Apps, Books, Business Data Connectivity, Claims, Conferences, JavaScript, jQuery, MOSS 2007 Archived Post, PowerShell, REST and CSOM, Search, SharePoint 2010, SharePoint 2013, Web Content Management,

Uploading Files in SharePoint 2013 using CSOM and REST 

Tags: REST and CSOM, SharePoint 2013

Recently, I have been working through the process of trying to accomplish as many basic SharePoint tasks with both CSOM and REST as possible. My goal is to build a deeper understanding of what operations work in both approaches as well as strengths and limitations. In the case of document uploading, the CSOM approach is only good for files up to 1.5MB whereas REST is good up to 2GB. This makes understanding the REST approach critical, but I was struggling to get it working using the jQuery ajax method because the documentation is not great. In this post, I’ll save you the heartache I went through and just show you how to do it in both approaches.

Selecting Files

The first thing to set up is the control used for selecting files from the web page. This is a pretty simple use of input controls:

<input id="inputFile" type="file" />

<input id="uploadDocumentButton" type="Button" value="Upload Document"/>

The inputFile control allows for the browsing and selecting of files. The uploadDocumentButton control initiates the upload process. The inputFile control has a Files collection that you can use to access the file for uploading. The following code shows how to get the filename and file for uploading.

$("#uploadDocumentButton").click(function () {

 

    if (document.getElementById("inputFile").files.length === 0) {

        alert("Select a file!");

        return;

    }

 

    var parts = document.getElementById("inputFile").value.split("\\");

    var filename = parts[parts.length - 1];

    var file = document.getElementById("inputFile").files[0];

}

Reading Files

Once the file is selected, you have to read the bytes into your JavaScript code. This is accomplished using the FileReader object. This object accepts the file information for loading asynchronously. The onload and onerror events fire when the file is loaded successfully or fails. I wrote a helper function using promises to read the file into an ArrayBuffer, which will be used later during the upload.

var getFileBuffer = function (file) {

    var deferred = $.Deferred();

    var reader = new FileReader();

    reader.onload = function (e) {

        deferred.resolve(e.target.result);

    }

    reader.onerror = function (e) {

        deferred.reject(e.target.error);

    }

    reader.readAsArrayBuffer(file);

    return deferred.promise();

};

Uploading with CSOM

Uploading the file with CSOM requires converting the ArrayBuffer to a Base64-encoded array, which is then put into a SP.FileCreationInformation object. The following code shows a complete library for uploading with CSOM.

"use strict";

 

var WingtipToys = window.WingtipToys || {};

WingtipToys.Jsom = WingtipToys.Jsom || {};

 

WingtipToys.Jsom.Libs = function () {

 

    var deferreds = new Array(),

 

    upload = function (serverRelativeUrl, filename, file) {

        deferreds[deferreds.length] = $.Deferred();

 

        getFileBuffer(file).then(

            function (buffer) {

                var bytes = new Uint8Array(buffer);

                var content = new SP.Base64EncodedByteArray(); //base64 encoding

                for (var b = 0; b < bytes.length; b++) {

                    content.append(bytes[b]);

                }

                var ctx = new SP.ClientContext.get_current();

                var createInfo = new SP.FileCreationInformation();

                createInfo.set_content(content); //setting the content of the new file

                createInfo.set_overwrite(true);

                createInfo.set_url(filename);

                this.files = ctx.get_web().getFolderByServerRelativeUrl(serverRelativeUrl).get_files();

                ctx.load(this.files);

                this.files.add(createInfo);

                ctx.executeQueryAsync(

                    Function.createDelegate(this,

                        function () { deferreds[deferreds.length - 1].resolve(this.files); }),

                    Function.createDelegate(this,

                        function (sender, args) { deferreds[deferreds.length - 1].reject(sender, args); }));

 

            },

            function (err) {

                deferreds[deferreds.length - 1].reject(err);

            }

         );

 

        return deferreds[deferreds.length - 1].promise();

 

    },

 

    getFileBuffer = function (file) {

        //See previous code

    };

 

    return {

        upload: upload,

    };

 

}();

Once the library is written, uploading the file becomes pretty simple. For this example, I am assuming a document library named “JSOM Documents” exists. Notice how the server-relative URL is provided to the upload method.

WingtipToys.Jsom.Libs.upload("/apps/LibraryOperations/JSOM%20Documents", filename, file)

.then(

    function (files) {

        alert("Uploaded successfully");

    },

    function (sender, args) {

        alert(args.get_message());

    }

);

Uploading with REST

The REST approach can use the contents of the ArrayBuffer directly. The key to making this approach work with jQuery ajax is to set the processData flag to false. By default, jQuery ajax will process all non-string data into a query string, which corrupts the binary file data during the upload. By setting it to false, the data is faithfully uploaded. The following code shows a complete library for uploading with REST.

"use strict";

 

var WingtipToys = window.WingtipToys || {};

WingtipToys.Rest = WingtipToys.Rest || {};

 

WingtipToys.Rest.Libs = function () {

 

    var upload = function (serverRelativeUrl, filename, file) {

 

        var deferred = $.Deferred();

 

        getFileBuffer(file).then(

 

            function (arrayBuffer) {

 

                $.ajax({

                    url: _spPageContextInfo.webServerRelativeUrl +

                        "/_api/web/GetFolderByServerRelativeUrl('" + serverRelativeUrl + "')/Files" +

                        "/Add(url='" + filename + "', overwrite=true)",

                    type: "POST",

                    data: arrayBuffer,

                    processData: false,

                    headers: {

                        "accept": "application/json;odata=verbose",

                        "X-RequestDigest": $("#__REQUESTDIGEST").val(),

                        "content-length": arrayBuffer.byteLength

                    },

                    success: function (data) {

                        deferred.resolve(data);

                    },

                    error: function (err) {

                        deferred.reject(err);

                    }

                });

            },

            function (err) {

                deferred.reject(err);

            }

         );

 

        return deferred.promise();

    },

 

    getFileBuffer = function (file) {

        //See previous code

    };

 

    return {

        upload: upload

    };

 

}();

Again, once you have the library, uploading the file is easy. Here is the REST version of the upload method.

WingtipToys.Rest.Libs.upload("/apps/LibraryOperations/REST%20Documents", filename, file)

.then(

    function (data) {

        alert("Uploaded successfully");

    },

    function (err) {

        alert(JSON.stringify(err));

    }

);

Conclusions

As with most things in programming, it’s pretty simple when someone shows you how. Sparse documentation on MSDN, however, gave me a couple of days of agony. (I'll probably get a laugh when a reader points me at a full code sample somehere on MSDN that I missed.)

The big takeaway from this effort is that now you can easily use the REST interface for file uploading, which is good for files up to 2GB. Because CSOM is limited to 1.5MB, it seems like there is really little point to using anything but REST.

 
Posted by Scot Hillier on 26-Mar-13
0 Comments  |  Trackback Url  |  Link to this post | Bookmark this post with:        
 

Links to this post

Comments