Cloud

Musings on attaching a document to a list item in SharePoint 2010 using the Client OM, Lists.asmx, and ListData.svc

The Client Object Model (OM) in SharePoint 2010 is great for many things, but it seems that it is not great for adding the first attachment to a list item. The problem is that the OM is unable to create the attachments folder for a list item. When no folder exists, attempting to add an attachment will result in an error. The error that I kept receiving was “(409) Conflict”.

To get around this problem, it is necessary to use a service to create the attachments folder for you:

 

1.One strategy is to use Lists.asmx, as shown by Vladimir Buyevich.

2.Another strategy is to use the ListData.svc service available in SharePoint 2010.

In this blog, I want to build on the strategies that I have linked to above and show two approaches I used for working with existing attachments. I will go over checking for and overwriting attachments. For this code, I am assuming that I will always be uploading a file where the name never changes.

 

 

First Approach

The first approach that I used was the combination of the OM and Lists.asmx, with Lists.asmx creating the initial attachment folder if it did not already exist.

To start, I need to retrieve a specific list item using the OM:

using (ClientContext clientContext = new ClientContext(“Your Site”)

{

clientContext.Credentials = new NetworkCredential(“Your Credentials”);

ListItemCollection collection = null;

CamlQuery camlQuery = newCamlQuery();

List list = clientContext.Web.Lists.GetByTitle(“Test”);

 

camlQuery.ViewXml = @”<View><Query><Where><Eq><FieldRef Name=’TestField’/><Value Type=’Text’>” + testValue + “</Value></Eq></Where></Query></View>”;

 

collection = list.GetItems(camlQuery);

clientContext.Load(collection);

clientContext.ExecuteQuery();

 

IEnumerable<ListItem> items = collection;

ListItem item = items.First();

 

Now that I have my list item, I want to check to see if an attachment already exists. To do this, I used the following lines of code:

var file = clientContext.Web.GetFileByServerRelativeUrl(new Uri(“Your Site”).AbsolutePath + “Lists/Test/Attachments/” + item[“ID”].ToString() + “/test.txt”);

 

clientContext.ExecuteQuery();

 

//check to see if the file already exists

if (file.ServerObjectIsNull == null)

{

 

ServerObjectIsNull returns “null” or “false”. I could also use Lists.asmx to check if the attachment exists, but I found that it was marginally faster to use ClientContext.

If the file does not exist, then I will make my call to Lists.asmx and upload a blank file with the same name. My strategy here is to create the attachments folder while knowing that I intend to overwrite this blank file in my next code section.

using (ListsWebService.Lists lists = new ListsWebService.Lists())

{

lists.Credentials = clientContext.Credentials;

lists.Url = “Your Site” + “/_vti_bin/lists.asmx”;

lists.AddAttachment(“Test”, item[“ID”].ToString(), “test.txt”, new byte[1]);

}

 

Knowing that the attachments folder has been created for the list item, I now will upload the actual document using the OM. What I like about using the OM is that I can use FileStream. To use Lists.asmx, you can look here for converting a document to a byte array.

using (System.IO.FileStream strm = new System.IO.FileInfo(“log.txt”).Open(System.IO.FileMode.Open))

{

Microsoft.SharePoint.Client.File.SaveBinaryDirect(clientContext, newUri(“Your Site”).AbsolutePath + “Lists/Test/Attachments/” + item[“ID”].ToString() + “/test.txt”, strm, true);

}

 

 

Second Approach

 

The second approach that I used was a combination of the OM and ListData.svc. The reason that I had to use both is that I was unable to get my ListData.svc client to recognize that a list item had an attachment.

To start out, I need to retrieve my list item using ListData.svc:

ListData.TestDataContext context = new ListData.TestDataContext(new Uri(“Your Site” + “_vti_bin/ListData.svc”));

 

context.Credentials = new NetworkCredential(“Your Credentials”);

 

ListData.ProjectItem item = context.Project.Where(i => i.Test == testValue).FirstOrDefault();

 

Now that I have my list item, I will add a few lines of code to delete the existing attachment. The only way I have found to do this is using the OM.

using (ClientContext clientContext = new ClientContext(“Your Site”))

{

clientContext.Credentials = context.Credentials;

 

var file = clientContext.Web.GetFileByServerRelativeUrl(new Uri(“Your Site).AbsolutePath + “Lists/Test/Attachments/” + item.Id + “/test.txt”);

 

file.DeleteObject();

clientContext.ExecuteQuery();

}

 

Now that I know the item does not have an attachment with the same name, I can continue attaching my file using ListData.svc.

ListData.AttachmentsItem attachment = new ListData.AttachmentsItem { EntitySet = “Test”, ItemId = item.Id, Name = “test.txt” };

 

context.AddToAttachments(attachment);

 

using (FileStream strm = new FileStream(@”test.txt”, FileMode.Open, FileAccess.Read))

{

context.SetSaveStream(attachment, strm, false, “text/plain”, “Test|” + item.Id + “|test.txt”);

context.SaveChanges();

}

 

These are the two approaches that I took to adding attachments using the OM and services. If anyone knows of a way to better manipulate attachments using the ListData.svc, I would appreciate some feedback.

Thoughts on “Musings on attaching a document to a list item in SharePoint 2010 using the Client OM, Lists.asmx, and ListData.svc”

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Brian Honaker

More from this Author

Subscribe to the Weekly Blog Digest:

Sign Up
Follow Us
TwitterLinkedinFacebookYoutubeInstagram