Tuesday, September 25, 2012

SharePoint - Get File Versions Using Client Object Model


In two of my previous posts I discussed how to get, delete and resore file versions programmatically.
I suggested way of getting versions using web service. Now let’s do the same thing with Silverlight client object model. Same thing can be done with JavaScript object model with some syntax changes.
Here I am considering same scenarios which we considered when we used web service. To put this in other way I have written sample methods for the operations which are possible by client object model.
These are some sample methods:
I have placed clientcontext object to App level. So I am using App.clientContext in my code.

Remember to load clientcontext before using these methods.

Get all versions:

private void GetAllFileVersions(string fileUrl)

{  

    FileVersionCollection fileVersionCollection;

    file = App.clientContext.Web.GetFileByServerRelativeUrl(fileUrl);

    fileVersionCollection = file.Versions;

    App.clientContext.Load(file);

    App.clientContext.Load(fileVersionCollection);

    App.clientContext.ExecuteQueryAsync((s, args) =>

    {

        int numberOfVersions = fileVersionCollection.Count;

    },

    (s, args) =>

    {

        //"Error loading versions.

    });

}
 

Usage:

GetAllFileVersions("/sites/prasad/teamsite/MyLibrary/testexcel.xlsx");
 

Description:

This method will load file version collection. You can iterate through each file version and get values for various properties which will give you date of creation, user object of user who created version, url of file for that version and Boolean value that tells if it is a current version of file.

  
Delete Specific Version Using Version ID:

        private void DeleteSpecificFileVersion(string fileUrl, int versionId)

        {

            file = App.clientContext.Web.GetFileByServerRelativeUrl(fileUrl);

            App.clientContext.Load(file);

            file.Versions.DeleteByID(versionId);

            App.clientContext.ExecuteQueryAsync((s, args) =>

            {

                //"Deleted file version successfuly.

            },

            (s, args) =>

            {

                //"Error deleting file version.

            });

        }
 

Usage:

DeleteSpecificFileVersion("/sites/prasad/teamsite/MyLibrary/testexcel.xlsx",512);
 

Description:

This method deletes specific version of file when version Id is provided. Interesting fact here is what is version id?

While iterating through versions of file you can get version id from “ID” property of “FileVersion” class.

Version ids are in multiple of 512.i.e. for first version it is 512, for second version it is 1024, for third version it is 1536 and so on.
 

Delete Specific Version Using Version Label:

        private void DeleteSpecificFileVersion(string fileUrl, string versionLabel)

        {

            file = App.clientContext.Web.GetFileByServerRelativeUrl(fileUrl);

            App.clientContext.Load(file);

            file.Versions.DeleteByLabel(versionLabel);

            App.clientContext.ExecuteQueryAsync((s, args) =>

            {

                //"Deleted file version successfuly.

            },

            (s, args) =>

            {

                //"Error deleting file version.

            });

        }
 

Usage:

DeleteSpecificFileVersion("/sites/prasad/teamsite/MyLibrary/testexcel.xlsx", "2.0");
 

Description:

This method deletes specific version of file when version label is provided. Version label means version number which you see on UI. i.e. “1.0”, “2.0”,”3.0” and so on.

While iterating through versions of file you can get version label from “VersionLabel” property of “FileVersion” class.

 

Delete All File Versions:

        private void DeleteAllFileVersions(string fileUrl)

        {

            file = App.clientContext.Web.GetFileByServerRelativeUrl(fileUrl);

            App.clientContext.Load(file);

            file.Versions.DeleteAll();

            App.clientContext.ExecuteQueryAsync((s, args) =>

            {

                //"Deleted all file versions successfuly.

            },

            (s, args) =>

            {

                //"Error deleting old file versions.

            });

        }
 

Usage:

DeleteAllFileVersions("/sites/prasad/teamsite/MyLibrary/testexcel.xlsx");
 

Description:

This simply deletes all the versions of file but current version.
 

Restore Specific Version:

        private void RestoreSpecificFileVersion(string fileUrl, string versionLabel)

        {

            file = App.clientContext.Web.GetFileByServerRelativeUrl(fileUrl);

            App.clientContext.Load(file);

            file.Versions.RestoreByLabel(versionLabel);

            App.clientContext.ExecuteQueryAsync((s, args) =>

            {

                //"Restored file version successfuly.

            },

            (s, args) =>

            {

                //"Error restoring old file versions.

            });

        }
 

Usage:

RestoreSpecificFileVersion("/sites/prasad/teamsite/MyLibrary/testexcel.xlsx", "3.0");
 

Description:

This method restores specific version of file when version label is provided.
 
To get current version of file use “UIVersion” or “UIVersionLabel” properties of “File” class. These properties will return you version id and version label respectively.

Interesting fact is version ids which SharePoint maintains. As I mentioned earlier, these are in multiples of “512”. URL of file version contains this version id in it. E.g.–

URL of first Version:                      http://[My Site URL]/_vti_history/512/MyLibrary/testexcel.xlsx

URL of second Version:               http://[My Site URL]/_vti_history/1024/MyLibrary/testexcel.xlsx

URL of third Version:                    http://[My Site URL]/_vti_history/1536/MyLibrary/testexcel.xlsx

Getting this path is nothing fancy. If you look at the version history of any file you can get this.
Just mouse over the link for each version and observe URL, you will get URL in above mention format.
Most important thing, current version of file will not include version id in its URL.
I learned many things from above exercise. Did you?

Wednesday, September 19, 2012

SharePoint Client Object Model: Using lambda expression for ExecutequeryAsync

When using "ExecuteQueyAsync" method of client object model we genarally write two different callback methods for success and failure. Instead of that we can use "Lambda Expression" and avoid two separate methods. This will also avoid class level variables and we  can access parameters of calling method in callback too.
Here is one simple example of usage of lambda expression.

private void UpdateItem(int itemId, string fieldName, object fieldValue)

{
ListItem item = clientContext.Web.Lists.GetByTitle("MyList").GetItemById(itemId);

item[fieldName] = fieldValue;

item.Update();

clientContext.ExecuteQueryAsync((sender, args) =>

{
//On update success

MessageBox.Show("Item with id "+ itemId.ToString()+" updated successfuly");

},

(s, args) =>

{
//on update failure

MessageBox.Show("Error occurred updating item: " + itemId.ToString());

});

}
Hope this helps to those who are unaware of using lambda expression.

SharePoint: How to move files from one document library to other using RPC in Silverlight application. Presrve created and modified information.

In my last post I talked about Uploading large files to SharePoint using RPC call. In this post I am going to tell how to move or copy file from one document library to other.
For basics of RPC, please follow links given in my last post.
So, here is my code which uses RPC method to copy file.

private string rpcCallString = string.Empty;

private byte[] newFileData;

public void MoveFile(string CurrentWebUrl, string serviceName, string newFilePath, string oldFilePath)

{
string requestUrl = CurrentWebUrl + "_vti_bin/_vti_aut/author.dll";

 string method = GetEncodedString("move document:14.0.0.5123");

serviceName = GetEncodedString("/" + serviceName);

 string putOption = "edit";

oldFilePath = GetEncodedString(oldFilePath);

newFilePath = GetEncodedString(newFilePath);

rpcCallString =
"method={0}&service_name={1}&oldUrl={2}&newUrl={3}&rename_option=findbacklinks&put_option={4}&docopy=false";

rpcCallString = String.Format(rpcCallString, method, serviceName, oldFilePath, newFilePath, putOption).Replace("_", "%5f");

 HttpWebRequest wReq = WebRequest.Create(requestUrl) as HttpWebRequest;

wReq.Method = "POST";

wReq.Headers["Content"] = "application/x-vermeer-urlencoded";

wReq.Headers["X-Vermeer-Content-Type"] = "application/x-vermeer-urlencoded";

wReq.BeginGetRequestStream(new AsyncCallback(gotFileMoveRequestStream), wReq);

}

private void gotFileMoveRequestStream(IAsyncResult asynchronousResult)

{HttpWebRequest webRequest = (HttpWebRequest)asynchronousResult.AsyncState;

 Stream requestStream = webRequest.EndGetRequestStream(asynchronousResult);

 byte[] fileData = Encoding.UTF8.GetBytes(rpcCallString);

requestStream.Write(fileData, 0, fileData.Length);

requestStream.Close();

webRequest.BeginGetResponse(
new AsyncCallback(gotFileMoveResponse), webRequest);

}

private void gotFileMoveResponse(IAsyncResult asynchronousResult)

{
HttpWebRequest webRequest = (HttpWebRequest)asynchronousResult.AsyncState;

 HttpWebResponse webResponse = (HttpWebResponse)webRequest.EndGetResponse(asynchronousResult);

 Stream responseStream = webResponse.GetResponseStream();

 StreamReader reader = new StreamReader(webResponse.GetResponseStream());

 string responseString = string.Empty;

responseString = reader.ReadToEnd();byte[] fileBuffer = Encoding.UTF8.GetBytes(responseString);

responseStream.Close();

reader.Close();

webResponse.Close();
if (responseString.IndexOf("\n<p>message=successfully") < 0)

{throw new Exception(responseString);
 
}           
}

and here is the utility method.

public string GetEncodedString(string SourceString)

{
if (!string.IsNullOrEmpty(SourceString))

{
return HttpUtility.UrlEncode(SourceString).Replace(".", "%2e").Replace("_", "%5f");

}
 
else

{
return SourceString;

}

}


Let's discuss parameters now.
method is move document. 14.0.0.5123 is server extension version for SharePoint 2010.
oldUrl and newUrl are the paths of old and new files respectively.
rename_option is set to findbacklinks, which means all the references to the file will also be updated for new location.
Here is the parameter for which many like me are looking for. Parameter which will allow us to preserve created and modified information even if we copy or move file from one location to other. And the parameter used is put_option which when set to "overwrite", overwrites file with same name, when set to "edit" prompts with message saying file with same name exists and IF SET TO "migrationsemantics" PRESERVES CREATED and MODIFIED INFORMATION.
If we set docopy to true it will only copy file to new location but if it is set to false it will move file from old location to new location. Default value for it is false.
Here is example of call to above method.
 


MoveFile("http://myserver/sites/prasad/teamsite/", "sites/prasad/teamsite", "Shared Documents/document1.docx", "MyDocLib/document1.docx");

Remember the way paths are provided. It is very important.
For more information about "
move document" method visit MSDN.
This method will be very useful when you want to migrate data from one site to another.
So are you ready to use this method for your next migration task???

How to upload large files to SharePoint document library using RPC method from Silverlight application

Well this is very common scenario and we come accross during our development when we want to upload large files. If we try to use silverlight client object model it will not allow us to upload large files and result in error.
There are various options suggested by various bloggers and even on MSDN which tell us to increase message size. But to do that we require server access. What if we dont have server access and allowed to write code only on client side?
I was in simillar situation where I wanted to upload large file from my Silverlight application.
And finally I decided to go for RPC methods available for SharePoint.
 RPC is an interprocess communication technique that allows client and server software to communicate. For more details of RPC you can visit "Wikipedia" and "Technet" articles.
As we can use RPC calls to communicate with SharePoint from any platform it is very powerful way of communication.
Here I am posting code for uploading large file to SharePoint document library. Hope this will help to those who are searching for similar solution.

public void UploadFile(string CurrentWebUrl,string serviceName, string filePath, FileStream stream, string userDomainName)

{

newFileData =
null;

newFileData = new byte[stream.Length];

stream.Read(newFileData, 0, Convert.ToInt32(stream.Length));
 string requestUrl = CurrentWebUrl + "/_vti_bin/_vti_aut/author.dll";

string method = GetEncodedString("put document:14.0.0.5123");

serviceName = GetEncodedString("/" + serviceName);
 string putOption = "overwrite";

string metaInfo = "[vti_modifiedby;SW|" + userDomainName + ";vti_author;SW|" + userDomainName + "]]";

string comments = GetEncodedString("File uploaded using RPC call");

string docDetails = string.Format("[document_name={0};meta_info={1}", filePath, metaInfo);

docDetails = GetEncodedString(docDetails);

rpcCallString =
"method={0}&service_name={1}&document={2}&put_option={3}&comment={4}&keep_checked_out=false\n";

rpcCallString = String.Format(rpcCallString, method, serviceName, docDetails, putOption, comments).Replace("_", "%5f");

 HttpWebRequest wReq = WebRequest.Create(requestUrl) as HttpWebRequest;

wReq.Method = "POST";

wReq.Headers["Content"] = "application/x-vermeer-urlencoded";

wReq.Headers["X-Vermeer-Content-Type"] = "application/x-vermeer-urlencoded";

wReq.BeginGetRequestStream(new AsyncCallback(gotRequestStream), wReq);

}



private void gotRequestStream(IAsyncResult asynchronousResult)

{HttpWebRequest webRequest = (HttpWebRequest)asynchronousResult.AsyncState;

Stream requestStream = webRequest.EndGetRequestStream(asynchronousResult);

List<byte> uploadData = new List<byte>();

uploadData.AddRange(Encoding.UTF8.GetBytes(rpcCallString));

uploadData.AddRange(newFileData);
 
byte[] fileData = uploadData.ToArray();

requestStream.Write(fileData, 0, fileData.Length);

requestStream.Close();

webRequest.BeginGetResponse(
new AsyncCallback(gotResponse), webRequest);

}

private void gotResponse(IAsyncResult asynchronousResult)

{HttpWebRequest webRequest = (HttpWebRequest)asynchronousResult.AsyncState;

HttpWebResponse webResponse = (HttpWebResponse)webRequest.EndGetResponse(asynchronousResult);

Stream responseStream = webResponse.GetResponseStream();

StreamReader reader = new StreamReader(webResponse.GetResponseStream());
 
string responseString = string.Empty;

responseString = reader.ReadToEnd();byte[] fileBuffer = Encoding.UTF8.GetBytes(responseString);

responseStream.Close();

reader.Close();

webResponse.Close();
if (responseString.IndexOf("\n<p>message=successfully") < 0)

{throw new Exception(responseString);
}
}

Now let's have a look at the parameters used in this call.
Here we are using method "put document" and "14.0.0.5123" is server extension version.
Service name is server relative URL of your site.
In document parameter we are providing to fileds "document_name" and "meta_info". document name is nothing but the path at which we want to upload file including file name and meta info sets the metadata of the document to be uploaded. You can observe in code that I am setting two fields like "Modified By" and "Author" of the document. vti_modifiedby is column name and userDomainAlias is value to set. "SW" is field type. Syntax for various field types is different. This is very simple example of setting meta info. But I am not able to get any documentation which will give me idea about rest of the field types. I will post updates once I get details about other field types.
Next parameter is put_option where you can provide "overwrite" if you want to overwrite existing file with same name else you can provide "edit".
Next two parameters comment and keep_checked_out are very straight forward and do not require any explaination.
In case of RPC calls it is confusing how to pass parameters, mostly in case of file paths. So here is the example of how will you call this upload method.

UploadFile("http://myserver/sites/prasad/teamsite/", "sites/prasad/teamsite", "Shared Documents/document1.docx", stream, "myserver\\prasad.kulkarni");

I have used one utility method for encoding of string. Here it is for your reference.

public string GetEncodedString(string SourceString)
{if (!string.IsNullOrEmpty(SourceString))

{ return HttpUtility.UrlEncode(SourceString).Replace(".", "%2e").Replace("_", "%5f");
}else

{return SourceString;

}
}

If you have any doubts please post your comments. For more information of method used here see this MSDN page.

I hope you can upload files upto 2 GB which is default SharePoint limit.

Enjoy uploading large files....