Microsoft & .NETAccessing and Saving List Item Attachments

Accessing and Saving List Item Attachments

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Custom lists in SharePoint offer an option that lets you add attachments to individual list items. Initially, while that feature might not seem very tempting, there are many practical scenarios where attachments (along with custom columns), can help meet some of your business requirements. Often, adding attachments to the list is just one part of the picture; how you present those attachments to users to meet a business need is the more interesting part. This article shows how you can programmatically access list item attachments and save them locally.

First, Figure 1 provides a quick overview of how attachments can add extra power to custom list items.

Attachment Sequence
Figure 1. Attachment Sequence:
The figure shows a general sequence of steps that occur when attachments are used.

The item’s creator usually performs Step 1, typically a content admin, or user(s) selected for that task.

The specific actions taken in Step 2 depend totally on business requirements, and may even be optional in some cases. Typically, checks and validation would enforce IT department or general business policies, etc. The actions various sites may choose to perform in Step 2 (and they way they might implement them) is a fascinating topic that’s beyond the scope of this article. Lastly, in Step 3, attachments become the source material to fulfill business requirements, often in conjunction with some GUI to provide end users with easy access to the content.

For example, one requirement might be show or hide attachments based on the groups to which a user belongs. Another might be to display or deliver different types of attachments in different ways. The possibilities are endless and you will likely have unique needs.

Although the list item attachments are accessible via the SharePoint UI, this method is usually not the ideal way to meet most business challenges; therefore, you’ll want to use some SharePoint Object Model code to retrieve the attachments and gain full control over them. Getting the list attachments is quite easy; then you simply need to get the attached file content.

The following example uses a simple Windows console application to demonstrate the three major tasks shown in Figure 2.

Attachment Tasks
Figure 2. Attachment Tasks:
These are the three critical tasks that you need to perform to retrieve list item attachments.

To perform these tasks, you’ll use four methods:

  • ProcessListItemsForAttachments: This is a wrapper method that calls the other three methods.
  • GetAllListItems: This method creates SPWeb and SPList objects whose SPListItems are then iterated for attachments. The three string parameters required by this method are a site URL, web URL, and list name.
  • GetListItemAttachments: This method retrieves any attachments to a list item. It returns a generic List of SPFile instances.
  • SaveAttachmentToDisk: This method saves the content of the attachment to a disk location.

The sections below explore these methods in more detail.

Author’s Note: Please note that the sample code is for demonstration purposes only, and not meant to run in production environment without further development and testing.

The ProcessListItemAttachments wrapper method displays the list item name, and then iterates over the list of SPFile objects returned from GetListItemAttachments. It then displays some of the properties of SPFile Object (discussed later).

public static void ProcessListItemsForAttachments()
{
   try
   {
      foreach (SPListItem item in GetAllListItems(
         "http://sitecollectionUrl", "webUrl", "ListName"))
      {
         Console.WriteLine(item.Name);
         foreach (SPFile file in GetListItemAttachments(item))
         {
            Console.WriteLine("File Name : " + file.Name + " , URL " +
               item.ParentList.ParentWeb.Site.MakeFullUrl(
               file.ServerRelativeUrl));
            Console.WriteLine("Saving File to Disk");
            SaveAttachmentToDisk(file.OpenBinary(
               SPOpenBinaryOptions.SkipVirusScan), + item.ID + 
               "_" + file.Name);
         }
      }
      Console.ReadLine();
   }
   catch
   {
      //Do some logging here...
      //Otherwise throw the exception
      throw;
   }
}

The GetAllListItems method creates an SPSite object, opens the SPWeb Object and then gets to the list items through the SPList.Items property. It returns an SPListItemCollection. Note that if your list is in the root web of the site collection , you can pass a slash (/) for the webUrl parameter; doing that ensures that the call to OpenWeb()gets you to the root web.

public static SPListItemCollection GetAllListItems(
   string siteUrl, string webUrl, string listName)
{
   try
   {
      SPListItemCollection items = null;
      SPSecurity.RunWithElevatedPrivileges(delegate
      {
         using (SPSite oSite = new SPSite(siteUrl))
         {
            using (SPWeb oWeb = oSite.OpenWeb(webUrl))
            {
                items = oWeb.Lists[listName].Items;
            }
         }
      });
      return items;
   }
   catch
   {
      throw;
   }
}

The GetListItemAttachments method takes an SPListItem and then uses the following statement to get to the folder (of type SPFolder) that contains the attachments in the form of Files, each of type SPFile:

SPFolder folder = listItem.ParentList.RootFolder.SubFolders["Attachments"].
   SubFolders[listItem.ID.ToString()];

Basically, to access a list item attachment, you first need to access the item’s parent list, and then the list’s root folder. That folder contains a subfolder named “Attachments,” which in turn may have a list of subfolders that you can access by the list item’s ID, which makes sense, because each item’s ID is unique within the list.

That’s easier to understand if you use the following URL and modify it to access your own list item attachments. Simply replace the variables with valid entries for your SharePoint environment.

http[s]://sitecollectionURL/[webname]/Lists/     
  ListName/Attachments/ListItemID/AttachmentName

Finally, the method returns a List of SPFile objects (List<SPFile>); each corresponds to an attachment in the list item. The SPFile class exposes many interesting properties and methods. The ones used here are:

  • SPFile.Name: Returns the name of the file , including the extension.
  • SPFile.ServerRelativeUrl: Returns the server-relative URL of the file location on the server. You can use this property with the SPSIte.MakeFullUrl() method to create a complete URL—in fact, this is exactly what the ProcessListItemsForAttachments method shown earlier does.
  • SPFile.OpenBinary(): This method provides access to the file contents as a byte array, which simplifies saving the file locally . An overload to this method takes one of the self-explanatory SPOpenBinaryOptions enum values—either SkipVirusScan or None.
public static List<SPFile> GetListItemAttachments(SPListItem listItem)
{
   try
   {
      List<SPFile> lstSPFile = null;
      SPSecurity.RunWithElevatedPrivileges(delegate
      {
         using (SPSite oSite = new SPSite(
            listItem.ParentList.ParentWeb.Site.ID))
         {
            using (SPWeb oWeb = oSite.OpenWeb(
               listItem.ParentList.ParentWeb.ID))
            {
               SPFolder folder = listItem.ParentList.RootFolder.
                  SubFolders["Attachments".SubFolders[
                  listItem.ID.ToString()];
               if (null != folder)
               {
                  lstSPFile = new List<SPFile>();
                  foreach (SPFile file in folder.Files)
                  {    
                     lstSPFile.Add(file);
                  }
               }
            }
         }
      });
      return lstSPFile;
   }
   catch
   {
      throw;
   }
}

Lastly, the SaveAttachmentToDisk method first creates the file specified by the fileName parameter, and then writes the content to disk, using the bytes parameter.

public static void SaveAttachmentToDisk(byte[] bytes, string fileName)
{
   System.IO.FileStream oFileStream;
   try
   {
      oFileStream = new System.IO.FileStream(
         fileName, System.IO.FileMode.Create);
      oFileStream.Write(bytes, 0, bytes.Length);
      oFileStream.Close();
   }
   finally
   {
      oFileStream = null;
   }
}

As you can see by this article, downloading and persisting custom list attachments is a straightforward process, primarily because the SPFile object provides the OpenBinary() method, which returns the contents as a byte array. With the byte array in hand, you can use all the methods available for that. This example saves the file contents to disk, but you can easily extend or alter it to meet your specific requirements.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories