Hi,
I had requirement to add new version to document set using SharePoint 2013 CSOM (Client side object Model) & JSOM (Javacript side object Model). CSOM & JSOM doesn't have any such API to add a version to Document Set directly. Also, I have to achieve this functionaliy in Sharepoint hosted App (for Sharepoint Online).
Below is the server side Code that I have to achieve using CSOM & JSOM.
web.AllowUnsafeUpdates = true; listItem.Update(); DocumentSet documentSet = DocumentSet.GetDocumentSet(listItem.Folder); documentSet.VersionCollection.Add(true, currentUser.Name); web.AllowUnsafeUpdates = false;
Solution :-
With absence of any proper APIs in CSOM & JSOM, a possible workaround was that monitor the POST request using Fiddler when clicking the "Capture Version" button in the ribbon on Document Set welcome page, then Create a custom POST request to imitate the Original "Capture Version" action.
Therefore, I have achieved this functionality by creating custom POST request to imitate the Original "Capture Version" Action. On click of "Capture Version" button in the ribbon it creates a Post Request on "/_layouts/15/CreateDocSetVersion.aspx" Page along with ListId & ItemId (i.e. Document Set Item of whom version need to be captured) in Query String Parameter "List={listguidid}&ID=docsetitemid".
Also, It passes "CreateComments={docsetversioncomments}" in the post request body to set document set version comments.
Reference :- https://social.msdn.microsoft.com/Forums/office/en-US/2b3d11d0-05ee-4e53-91bc-66362a0751ef/adding-a-new-version-in-version-collection-of-document-set-using-sharepoint-2013-jsom?forum=sharepointdevelopment
CSOM
Using CSOM API by creating custom POST request to Capture Document Set Version.
var CreateDocSetVersionUrl = SiteURL + "/_layouts/15/CreateDocSetVersion.aspx?List={" + spListID + "}&ID=" + spListItemID; System.Net.CookieContainer cookieContainer = new System.Net.CookieContainer(); // create Web Request using client context HttpWebRequest request = clientContext.WebRequestExecutorFactory.CreateWebRequestExecutor(clientContext, CreateDocSetVersionUrl).WebRequest; if (clientContext.Credentials != null) { // Get Authentication Cookie SecureString passWord = new SecureString(); foreach (char c in UserPassword.ToCharArray()) passWord.AppendChar(c); var credentials = new Microsoft.SharePoint.Client.SharePointOnlineCredentials(UserName, passWord); var authCookieValue = credentials.GetAuthenticationCookie(new Uri(CreateDocSetVersionUrl)); // Create fed auth Cookie System.Net.Cookie fedAuth = new Cookie(); fedAuth.Name = "FedAuth"; fedAuth.Value = authCookieValue.TrimStart(new char[] { 'S', 'P', 'O', 'I', 'D', 'C', 'R', 'L', '=' }); fedAuth.Path = "/"; fedAuth.Secure = true; fedAuth.HttpOnly = true; fedAuth.Domain = new Uri(clientContext.Url).Host; // Hookup authentication cookie to request cookieContainer.Add(fedAuth); request.CookieContainer = cookieContainer; } else { // No specific authentication required request.UseDefaultCredentials = true; } request.ContentLength = 0; WebResponse response = request.GetResponse(); // decode response string strResponse; Stream stream = response.GetResponseStream(); if (!string.IsNullOrEmpty(response.Headers["Content-Encoding"])) { if (response.Headers["Content-Encoding"].ToLower().Contains("gzip")) { stream = new System.IO.Compression.GZipStream(stream, System.IO.Compression.CompressionMode.Decompress); } else if (response.Headers["Content-Encoding"].ToLower().Contains("deflate")) { stream = new System.IO.Compression.DeflateStream(stream, System.IO.Compression.CompressionMode.Decompress); } } // get response string System.IO.StreamReader sr = new System.IO.StreamReader(stream); strResponse = sr.ReadToEnd(); sr.Close(); sr.Dispose(); stream.Close(); // Look for inputs and add them to the dictionary for postback values var inputs = new List<KeyValuePair<string, string>>(); string patInput = @"<input.+?\/??>"; string patName = @"name=\""(.+?)\"""; string patValue = @"value=\""(.+?)\"""; // Instantiate the regular expression object. Regex r = new Regex(patInput, RegexOptions.IgnoreCase); Regex rName = new Regex(patName, RegexOptions.IgnoreCase); Regex rValue = new Regex(patValue, RegexOptions.IgnoreCase); // Match the regular expression pattern against a text string. Match m = r.Match(strResponse); while (m.Success) { string name = string.Empty; string value = string.Empty; if (rName.IsMatch(m.Value)) { name = rName.Match(m.Value).Groups[1].Value; } if (rValue.IsMatch(m.Value)) { value = rValue.Match(m.Value).Groups[1].Value; } if (string.IsNullOrEmpty(name)) { m = m.NextMatch(); continue; } var dict = new KeyValuePair<string, string>(name, value); inputs.Add(dict); m = m.NextMatch(); } response.Close(); response.Dispose(); // Format inputs as postback data string string strPost = ""; string strComments = "Doc set version comments"; bool IsCommentsExist = false; foreach (KeyValuePair<string, string> inputKey in inputs) { if (!string.IsNullOrEmpty(inputKey.Key) && inputKey.Key.EndsWith("CreateComments")) { IsCommentsExist = true; strPost += System.Uri.EscapeDataString(inputKey.Key) + "=" + System.Uri.EscapeDataString(strComments) + "&"; } else if (!string.IsNullOrEmpty(inputKey.Key)) { strPost += System.Uri.EscapeDataString(inputKey.Key) + "=" + System.Uri.EscapeDataString(inputKey.Value) + "&"; } } if (!IsCommentsExist) { // Set Document Set Version Comments strPost += System.Uri.EscapeDataString("CreateComments") + "=" + System.Uri.EscapeDataString(strComments) + "&"; } strPost = strPost.TrimEnd(new char[] { '&' }); byte[] postData = System.Text.Encoding.UTF8.GetBytes(strPost); // Build postback request HttpWebRequest activateRequest = clientContext.WebRequestExecutorFactory.CreateWebRequestExecutor(clientContext, CreateDocSetVersionUrl).WebRequest; activateRequest.Method = "POST"; activateRequest.Accept = "text/html, application/xhtml+xml, */*"; if (clientContext.Credentials != null) { activateRequest.CookieContainer = cookieContainer; } else { // No specific authentication required activateRequest.UseDefaultCredentials = true; } activateRequest.ContentType = "application/x-www-form-urlencoded"; activateRequest.ContentLength = postData.Length; activateRequest.UserAgent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)"; activateRequest.Headers["Cache-Control"] = "no-cache"; activateRequest.Headers["Accept-Encoding"] = "gzip, deflate"; activateRequest.Headers["Accept-Language"] = "en-US"; // Add postback data to the request stream stream = activateRequest.GetRequestStream(); stream.Write(postData, 0, postData.Length); stream.Close(); stream.Dispose(); // Perform the postback response = activateRequest.GetResponse(); response.Close(); response.Dispose();
Reference :- https://github.com/janikvonrotz/PowerShell-PowerUp/blob/master/functions/SharePoint%20Online/Switch-SPOEnableDisableSolution.ps1
JSOM
In JSOM, I have to achieve this on App Web Page of Sharepoint Hosted App. I have created one page "DocSet.aspx" to create custom post request to add document set version. This page takes "SPHostUrl=hosturl&SPAppWebUrl=appweburl&ItemID=itemid&ListID=listid&Comments=docsetversioncomments" following parameter from query string & create custom POST request to add Document set version.
DocSet.aspx
<%-- The following 4 lines are ASP.NET directives needed when using SharePoint components --%> <%@ Page Inherits="Microsoft.SharePoint.WebPartPages.WebPartPage, Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" MasterPageFile="~masterurl/default.master" Language="C#" %> <%@ 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" %> <%-- The markup and script in the following Content element will be placed in the <head> of the page --%> <asp:Content ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server"> <script type="text/javascript" src="../JS/jquery.js" ></script> <script type="text/javascript" src="/_layouts/15/MicrosoftAjax.js"></script> <SharePoint:ScriptLink ID="ScriptLink5" name="sp.js" runat="server" LoadAfterUI="true" Localizable="false" /> <SharePoint:ScriptLink ID="ScriptLink6" name="sp.runtime.js" runat="server" LoadAfterUI="true" Localizable="false" /> <SharePoint:ScriptLink ID="ScriptLink7" name="sp.core.js" runat="server" LoadAfterUI="true" Localizable="false" /> <SharePoint:ScriptLink ID="ScriptLink8" name="SP.RequestExecutor.js" runat="server" LoadAfterUI="true" Localizable="false" /> </asp:Content> <%-- The markup in the following Content element will be placed in the TitleArea of the page --%> <asp:Content ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea" runat="server"> Page Title </asp:Content> <%-- The markup and script in the following Content element will be placed in the <body> of the page --%> <asp:Content ContentPlaceHolderID="PlaceHolderMain" runat="server"> <WebPartPages:AllowFraming runat="server" /> <table class="ms-formtable" border="0" cellspacing="0" width="100%"> <tr> <td> </td> </tr> </table> <span id="errorMessage"></span> <script type="text/javascript"> var errorMessage = ''; function LoggerLog(logMessage) { errorMessage += '<br/>' + logMessage; $('#errorMessage').html(errorMessage); } var hostUrl; var appWebUrl; var context; var spListID; var spListItemID; var Comments; function getParameterByName(name) { name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]"); var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"), results = regex.exec(location.search); return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " ")); } LoadProperties(); String.prototype.endsWith = function(suffix) { return this.indexOf(suffix, this.length - suffix.length) !== -1; }; if (this.length == 0) return this; c = c ? c : ' '; var i = 0; var val = 0; for (; this.charAt(i) == c && i < this.length; i++); return this.substring(i); } String.prototype.trimEnd=function(c) { c = c?c:' '; var i=this.length-1; for(;i>=0 && this.charAt(i)==c;i--); return this.substring(0,i+1); } function LoadProperties() { try { //debugger; hostUrl = getParameterByName('SPHostUrl'); appWebUrl = getParameterByName('SPAppWebUrl'); spListItemID = getParameterByName('ItemID'); spListID = getParameterByName('ListID'); Comments = getParameterByName('Comments'); //debugger; if (spListItemID != '') { context = new SP.ClientContext.get_current(); // Add Document Set Version AddDocSetVersion(); } } catch (ex) { //debugger; console.log(ex.toString()); LoggerLog(ex.toString()); } } function AddDocSetVersion() { console.log("UpdateLeadInfo Method started.."); try { //debugger; var redirectUrl = hostUrl + '/_layouts/15/CreateDocSetVersion.aspx?List={' + spListID + '}&ID=' + spListItemID +'&IsDlg=1'; var value = new SP.ClientRequest(context); var webRequest = value.get_webRequest(); // Set the request verb. webRequest.set_httpVerb("GET"); // Set the request Url. webRequest.set_url(redirectUrl); webRequest.get_headers()['Content-Length'] = 0; // Set the web request completed event handler, for processing return data. webRequest.add_completed(OnWebGetRequestCompleted); // Execute the request. webRequest.invoke(); console.log("AddDocSetVersion Method completed.."); } catch (ex) { //debugger; console.log("Error occured in AddDocSetVersion : " + ex.toString()); LoggerLog("Error occured in AddDocSetVersion : " + ex.toString()); } } function OnWebGetRequestCompleted(executor, eventArgs) { //debugger; if(executor.get_responseAvailable()) { var statusCode=executor.get_statusCode(); // STATUS CODE 204 MEANS ok, BUT NO DATA TO RETUIRN. ie CHANGES THIS TO 1223 AND DROPS ALL THE HEADERES var statusText=executor.get_statusText(); var responseData=executor.get_responseData(); var newHeaders=executor.getAllResponseHeaders(); // Look for inputs and add them to the dictionary for postback values var inputs = []; var patInput = /<input.+?\/??>/ig; var patName = /name=\"(.+?)\"/i; var patValue = /value=\"(.+?)\"/i; while(res = patInput.exec(responseData)) { var name1 = ''; var value1 = ''; var InputTag = res[0]; var resName = patName.exec(InputTag); if(resName !== null) { name1 = resName[1]; } var resValue = patValue.exec(InputTag); if(resValue !== null) { value1 = resValue[1]; } if (name1 == '') { continue; } inputs.push({key:name1,value:value1}); } // Format inputs as postback data string, but ignore the one that ends with iidIOGoBack var strPost = ""; var strComments = Comments; var IsCommentsExist = false; for(i=0;i<inputs.length;i++){ if (inputs[i].key != '' && inputs[i].key.endsWith("CreateComments")) { IsCommentsExist = true; strPost += encodeURIComponent(inputs[i].key) + "=" + encodeURIComponent(strComments) + "&"; } else if (inputs[i].key != '') { strPost += encodeURIComponent(inputs[i].key) + "=" + encodeURIComponent(inputs[i].value) + "&"; } } if (!IsCommentsExist) { // Set Document Set Version Comments strPost += encodeURIComponent("CreateComments") + "=" + encodeURIComponent(strComments) + "&"; } strPost = strPost.trimEnd('&'); var postData = strPost; // Build postback request var redirectUrl = hostUrl + '/_layouts/15/CreateDocSetVersion.aspx?List={' + spListID + '}&ID=' + spListItemID +'&IsDlg=1'; var value = new SP.ClientRequest(context); var webRequest = value.get_webRequest(); // Set the request verb. webRequest.set_httpVerb("POST"); // Set the request Url. webRequest.set_url(redirectUrl); webRequest.set_body(postData); webRequest.get_headers()['Accept'] = "text/html, application/xhtml+xml, */*"; webRequest.get_headers()['Content-Type'] = "application/x-www-form-urlencoded"; webRequest.get_headers()['Content-Length'] = postData.length; webRequest.get_headers()['User-Agent'] = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)"; webRequest.get_headers()['Cache-Control'] = "no-cache"; webRequest.get_headers()['Accept-Encoding'] = "gzip, deflate"; webRequest.get_headers()['Accept-Language'] = "en-US"; // Set the web request completed event handler, for processing return data. webRequest.add_completed(OnWebPostRequestCompleted); // Execute the request. webRequest.invoke(); } } function OnWebPostRequestCompleted(executor, eventArgs) { //debugger; if(executor.get_responseAvailable()) { var statusCode=executor.get_statusCode(); // STATUS CODE 204 MEANS ok, BUT NO DATA TO RETUIRN. ie CHANGES THIS TO 1223 AND DROPS ALL THE HEADERES var statusText=executor.get_statusText(); var responseData=executor.get_responseData(); var newHeaders=executor.getAllResponseHeaders(); } } </script> </asp:Content>
then I have uploaded that page in "StyleLibrary" of Sharepoint online site.
After on App Web page, I have created "SPAppIframe" control to load above created "DocSet.aspx" page along with the query string to add Document Set Version for an document set item.
<SharePoint:SPAppIFrame ID="SPDocSetVersionCreation" Style="display: none !important;" runat="server" Src="" Width="100%" Height="100%"></SharePoint:SPAppIFrame>
Code to load "DocSet.aspx" page on App Web page dynamically using jquery.
<script type="text/javascript">
// Update Document Set Version
var Iframeurl = '';
Iframeurl += '&SPHostUrl=' + HostUrl + '&SPAppWebUrl=' + AppWebUrl + '&ItemID=' + ItemId + '&ListID=' + spListID + '&Comments=' + encodeURIComponent('comments');
var Iframeurl = '';
Iframeurl += '&SPHostUrl=' + HostUrl + '&SPAppWebUrl=' + AppWebUrl + '&ItemID=' + ItemId + '&ListID=' + spListID + '&Comments=' + encodeURIComponent('comments');
$('#SPDocSetVersionCreation').attr('src', Iframeurl);
$('#SPDocSetVersionCreation').load( function () {
$('#SPDocSetVersionCreation').load( function () {
alert('Document set version added suceesfully !');
});
</script>