Tuesday, June 29, 2010

SharePoint 2010: Attach files to List/Library using Managed Client Object Model

 

Client Objet Model (OM) is a great new addition in SharePoint 2010. I have discussed before how to manipulate lists and list items using Managed Object Model. Today I’ll discuss on how to attach file to list item or add file to library using Managed Client Object Model.

Upload File in Library

The following code snippet shows how to upload file in document library:

public void UploadFileInLibrary(string siteUrl, string webName, string libraryName, string subfolderPath, string fileName)
{
    using (ClientContext clientContext = new ClientContext(siteUrl))
    {

        string uploadLocation = Path.GetFileName(fileName);
        if (!string.IsNullOrEmpty(subfolderPath))
        {
            uploadLocation = string.Format("{0}/{1}", subfolderPath, uploadLocation);
        }
        uploadLocation = string.Format("/{0}/{1}/{2}", webName, libraryName, uploadLocation);
        var list = clientContext.Web.Lists.GetByTitle(libraryName);
        var fileCreationInformation = new FileCreationInformation();
        fileCreationInformation.Content = System.IO.File.ReadAllBytes(fileName);
        fileCreationInformation.Overwrite = true;
        fileCreationInformation.Url = uploadLocation;
        list.RootFolder.Files.Add(fileCreationInformation);
        clientContext.ExecuteQuery();
    }
}

In the above code snippet, I have constructed the full path to the update location by concatenating the subfolderpath with library location. The site url is the spsite location whereas web name is name of the web site. To upload a file I have use FileCreationInformation object which is part of Client Object Model. To use the above method you can call the method as shown below. The instance is the class instance which has the method. Here the subfolderpath is the folder location inside the library where the document will be uploaded.

Instance.UploadFileInLibrary("http://mysite","mywebname", LibraryName,"folder1/folder2", @"c:\myfiles\LibraryItem.xlsx");

 

Download File From Library

The following code snippets shows how to download file from library:

public void DownloadFileFromLibrary(string siteUrl, string webName, string libraryName, string subfolderPath, string fileName, string downloadPath)
{
    using (ClientContext clientContext = new ClientContext(siteUrl))
    {
        string filePath = string.Empty;
        if (!string.IsNullOrEmpty(subfolderPath))
        {
            filePath = string.Format("/{0}/{1}/{2}/{3}", webName, libraryName, subfolderPath, fileName);
        }
        else
        {
            filePath = string.Format("/{0}/{1}/{2}", webName, subfolderPath, fileName);
        }

        var fileInformation = File.OpenBinaryDirect(clientContext, filePath);
        var stream = fileInformation.Stream;
        IList<byte> content = new List<byte>();
        int b;
        while ((b = fileInformation.Stream.ReadByte()) != -1)
        {
            content.Add((byte)b);
        }
        var downloadFileName = Path.Combine(downloadPath, fileName);
        System.IO.File.WriteAllBytes(downloadFileName, content.ToArray());
        fileInformation.Stream.Close();
    }
}

As above code shows, we can use Microsoft.SharePoint.Client.File.OpenBinaryDirect method to download file directly from SharePoint. However, SharePoint open the file as binary stream so you need read the full stream before processing the file. The subfolderpath is same as described in ‘Upload File in Library’ section.

 

Delete File From Library

The following code snippet shows how to delete file from library:

public void DeleteFileFormLibrary(string siteUrl, string webName, string listName, string subfolder, string attachmentFileName)
{
    using (ClientContext clientContext = new ClientContext(siteUrl))
    {
        string attachmentPath = string.Empty;
        if (string.IsNullOrEmpty(subfolder))
        {
            attachmentPath = string.Format("/{0}/{1}/{2}", webName, listName, Path.GetFileName(attachmentFileName));
        }
        else
        {
            attachmentPath = string.Format("/{0}/{1}/{2}/{3}", webName, listName, subfolder, Path.GetFileName(attachmentFileName));
        }
        var file = clientContext.Web.GetFileByServerRelativeUrl(attachmentPath);
        file.DeleteObject();
        clientContext.ExecuteQuery();
    }
}

As the above code , the DeleteObject method is invoked on file object to delete the file.

 

Attach File to ListItem

The following code snippet shows how to attach file to list item. The attachments in list are places in a folder whose location is like “http://siteurl/lists/[listname]/Attachments/[ListItemID]/[filename]”. So I have constructed the attchment location first and use Microsoft.SharePoint.Client.File.SaveBinaryDirect method to upload the file. Here in the method, Item id is the list item id that I want to attach the file to.

public void AttachFileToListItem(string siteUrl, string webName, string listName, int itemId, string fileName, bool overwrite)
{
    using (ClientContext clientContext = new ClientContext(siteUrl))
    {
        FileStream fileStream = new FileStream(fileName, FileMode.Open);
        string attachmentPath = string.Format("/{0}/Lists/{1}/Attachments/{2}/{3}", webName, listName, itemId, Path.GetFileName(fileName));
        File.SaveBinaryDirect(clientContext, attachmentPath, fileStream, overwrite);
    }
}

 

Download File from ListItem

The following code snippet shows how to download file that is attached with list item.

public void DownloadAttachedFileFromListItem(string siteUrl, string webName, int itemId, string attachmentName, string listName, string downloadLocation)
{
    using (ClientContext clientContext = new ClientContext(siteUrl))
    {
        string attachmentPath = string.Format("/{0}/lists/{1}/Attachments/{2}/{3}", webName, listName, itemId, Path.GetFileName(attachmentName));
        var fileInformation = File.OpenBinaryDirect(clientContext, attachmentPath);
        IList<byte> content = new List<byte>();
        int b;
        while ((b = fileInformation.Stream.ReadByte()) != -1)
        {
            content.Add((byte)b);
        }
        var downloadFileName = Path.Combine(downloadLocation, attachmentName);
        System.IO.File.WriteAllBytes(downloadFileName, content.ToArray());
        fileInformation.Stream.Close();
    }
}

As said before, the attachment location is “http://siteurl/lists/[listname]/Attachments/[itemid]/[filename]”. So I have used Microsoft.SharePoint.Client.File.OpenBinraryDirect to download the file.

 

Delete Attached File From ListItem

The following code shows how to delete a file that is attached with list item.

public void DeleteAttachedFileFromListItem(string siteUrl, string webName, int itemId, string attachmentFileName, string listName)
{
    using (ClientContext clientContext = new ClientContext(siteUrl))
    {
        //http://siteurl/lists/[listname]/attachments/[itemid]/[filename]
        string attachmentPath = string.Format("/{0}/lists/{1}/Attachments/{2}/{3}", webName, listName, itemId, Path.GetFileName(attachmentFileName));
        var file = clientContext.Web.GetFileByServerRelativeUrl(attachmentPath);
        file.DeleteObject();
        clientContext.ExecuteQuery();
    }
}

 

Conclusion

The code snippet above just provide you the gist. One point to notice that the File class used in the code not from System.IO. This is from Microsoft.SharePoint.Client and the full name is “Microsoft.SharePoint.Client.File”.

32 comments:

  1. Hi, the code to attach file to list item, only works if my item in the list have already some file attach, If the item doesn't have any file attached the code fail. Any idea??
    Oh, i'm sorry for my bad English

    ReplyDelete
  2. I hope you have enabled the attachment in the list. If you enable attachment in the list then the code should work.

    ReplyDelete
  3. I just want to say thanks, this code solved some of my daily challenges.

    ReplyDelete
  4. Hi

    I hope that you can help me. I have only been in IT since March and am trying to upload multiple documents to Sharepoint 2010 site. what is the webName that you refer to and is the LibraryName just a string like "Shared Documents"?

    ReplyDelete
  5. webname is a sharepoint concept. since SharePoint is a portal management system also, u may have many web sites. The webname is the name of the web site u had put during site creation. In case of site collection the webname is empty string ("").
    About library name, yes the value is like "Shared Documents"

    ReplyDelete
  6. Thanks for this... I'm trying to attach a file via SaveBinaryDirect. The creds the site runs under does not have access to the SP site therefore I set the Credentials property on the ClientContext object however when I call SaveBinaryDirect I get (401): Unauthorized Error. I know the creds are correct because I create the list item and if I don't set the Credentials property I get a (401) error just creating the list item. Any ideas? Thanks!

    ReplyDelete
  7. I was able to get this working farther... I needed to adjust the url. However I now get a 409 error same as David eluded to above. Attachments are enabled for the list under List Settings -> Advanced Settings -> Attachments = Enabled. Is there some other setting that needs to be done. Also, if I first add an attachment for an item through SharePoint I can then add more items through code for those items.

    ReplyDelete
  8. Hi Greg,

    Yes I have noticed the problem. The folder http://siteurl/lists/[listname]/attachments/[itemid]/[filename]
    doesn't create for an item automatically. However, once you add an attachment, the folder is created and later one my code works. I'll modify the code and update later. But for now what I can suggest to check if the folder exists or not and if doesn't exist then create the folder and then try to upload the file. You can get information on how to create folder in another post of my blog.

    ReplyDelete
  9. Thanks... I did try creating a folder but then I get cannot create folder error... :-s

    clientContext.ExecuteQuery()
    clientContext.Load(list.RootFolder.Folders)
    clientContext.ExecuteQuery()
    clientContext.Load(list.RootFolder.Folders(0)) ' 1 -> Attachment folder
    clientContext.Load(list.RootFolder.Folders(0).Folders)
    clientContext.ExecuteQuery()
    Dim folder As Microsoft.SharePoint.Client.Folder = list.RootFolder.Folders(0).Folders.Add("40")
    clientContext.ExecuteQuery()

    For now I'm using the Lists.asmx service to add attachments to new list items unless you have any other ideas :)

    ReplyDelete
  10. How do I hide documents from specified users on a SharePoint site?

    ReplyDelete
  11. @Fallon, You can set permission for a site, list/libraries or an individual item. To modify permission for an item, you need to set permission for the document, where you can set the permission for an user (remove, add etc).

    ReplyDelete
  12. In SharePoint Server 2010 and Office 2010, what add-in can help you sort and analyze millions of rows of data?

    ReplyDelete
  13. @Fico, I've not used such types of addin before. As I know excel uses virtualization for managing a large number of records.

    ReplyDelete
  14. hi
    I can't attach file to sharepoint list used client object model and Lists.asmx.
    Help please
    sorry of my bad english

    ReplyDelete
  15. Does anyone have any knowledge of Microsoft Sharepoint designer 2007? ?

    ReplyDelete
  16. Hi there, can I have your help please?

    I am trying UploadFileInLibrary() example above in the Site like "\\mypc1\sites\DocLib\". I created Document Library named "eDocLib" which has 01-12 month folders and 1-31 subfolders in 01 folder. When debug till line "clientContext.ExecuteQuery();", it prompts error ServerException was unhandled "Value does not fall within the expected range". Which part I missed or did wrong?

    Thanks in advance!

    ReplyDelete
  17. @zhinigami, Is the site url "\\mypc1\sites\DocLib\"? I think this is not valid url. Please make sure you have passed valid url.

    ReplyDelete
  18. How do I hide documents from specified users on a SharePoint site?

    ReplyDelete
  19. Thanks, Sohel, your post help me a lot, but right now I just want to ask whether you have good suggestion for us to create a folder with code, thanks again.

    ReplyDelete
  20. @Tao, here's the link to my another post where you'll find details: http://ranaictiu-technicalblog.blogspot.com/2010/03/sharepoint-2010-manage.html

    ReplyDelete
  21. "Index (zero based) must be greater than or equal to zero and less than the size of the argument list." - Getting this error in downloading file

    ReplyDelete
  22. Hi Sohel,

    As I am trying to upload file thorugh managed client object model and I am done with small size of document upload with the help of FileCreationInformation class.. My code is fail down when size is larger( In my case PDF 7 MB) and my site limit of uploading document is 50MB..is it relate with timeout I really dont want to increase it for the performance issue or could I use WebService for that if there is no option available in FileCreationInformation class Could you please me help in that?

    ReplyDelete
    Replies
    1. Hello Sohel
      Can you help me in few things,from above mentioned post I can make out you are successfully uploadng files to sharepoint site, I have a module where Im trying to upload files, first time when I ran that it worked fine and document got uploaded. After that till now I,m getting "{"Value does not fall within the expected range."}"

      This exception is just not helping in digging out what may be the issue. The code compiles without any issue also. Im invoking it from MVC 3.0 application. I can cut paste code if you want,

      Delete
  23. Hi Ase,

    I get this error for adding look up value programaticallly... I observe that if your lookup field schema is not perfect then while adding value into look up you get this type of error..Try to compare ID for Look Up or check Look Up field Schema

    ReplyDelete
    Replies
    1. Okay. I did manage it get it right:) Thanks

      Delete
  24. This comment has been removed by the author.

    ReplyDelete
  25. Thank you so much
    I have added some code to update metadata of the document library..

    Starting from second last line in "Upload File in Library" part

    Microsoft.SharePoint.Client.File uploadFile = list.RootFolder.Files.Add(fileCreationInformation);
    clientContext.ExecuteQuery();

    ListItem item = uploadFile.ListItemAllFields;
    item["Department"] = "Technology";
    item["City"] = "Mumbai";
    item.Update();
    clientContext.ExecuteQuery();

    ReplyDelete
  26. hi Sohel,

    i had a related question: how do i rename attachment files within a list item?

    in my list, each item has exactly 2 PDFs: a.pdf and b.pdf. what i want to achieve is rename these two PDF attachments to [Num]_a.pdf and [Num]_b.pdf where [Num] is a sequential ID field.

    is this possible in SP2010 Foundation, either with a workflow or programmatically?

    thanks!

    mir

    ReplyDelete
  27. Hallo,
    I get an error "Access to the path 'C: \ test.docx.' is denied" when I use the method System.IO.File.WriteAllBytes (DownloadFileName, content.ToArray ());

    ReplyDelete
  28. Very nice code. It unblocked us after having banged my head for hours. Thanks and keep helping :-)

    ReplyDelete
  29. Thanks for Nice Article. I have one issue ,My requirement is i need to use save Dialog to download the Document. I need your help on this,

    ReplyDelete
  30. This comment has been removed by the author.

    ReplyDelete

Note: Only a member of this blog may post a comment.