Search code examples
c#sharepointsharepoint-2010

Downloading all Attachments to a SharePoint Item automatically


I have a Console app that will eventually run as a Console app. I need to loop through an external SharePoint site, find all new Items and see if there are any attachments, if so I'll need to download those attachments.

I am able to query the List and I am able to iterate through the attachments to populate a File collection.

FolderToSaveTo resolves as "\\APPDEV03\NEMStoPSIMS\" and passes the if (System.IO.Directory.Exists(destPath)) statement, but on the next line using (Stream destFile = System.IO.File.OpenWrite(destPath)), it throws "The filename, directory name, or volume label syntax is incorrect."

I am able to navigate to \\APPDEV03\NEMStoPSIMS\ and I am able to save a file manually.

<add key="FolderToSaveTo" value="\\APPDEV03\NEMStoPSIMS\" />
SharePointConnector.FolderToSaveTo = ConfigurationManager.AppSettings["FolderToSaveTo"];

try
{
    ClientContext context = new ClientContext(sp_site_address);

    context.AuthenticationMode = ClientAuthenticationMode.FormsAuthentication;
    context.FormsAuthenticationLoginInfo = 
        new FormsAuthenticationLoginInfo(username, pwd);

    List list = context.Web.Lists.GetByTitle(requests_list_name);

    CamlQuery query = new CamlQuery();
    query.ViewXml = "<View><RowLimit>100</RowLimit></View>";

    ListItemCollection items = list.GetItems(query);

    context.Load(list);
    context.Load(items);

    context.ExecuteQuery();

    foreach (ListItem oListItem in items)
    {
        FileCollection Files = GetAttachments(context, list, oListItem);

        foreach (Microsoft.SharePoint.Client.File f in Files)
        {
            Download(f.ServerRelativeUrl, FolderToSaveTo, context);
        }

        lstRequests.Add(Agreement);
    }
}
catch (Exception ex)
{
    throw ex;
}
public static FileCollection GetAttachments(ClientContext ctx, List list, 
                                            ListItem item)
{
    ctx.Load(list, l => l.RootFolder.ServerRelativeUrl);
    ctx.Load(ctx.Site, s => s.Url);
    ctx.ExecuteQuery();

    Folder attFolder = ctx.Web.GetFolderByServerRelativeUrl(
        list.RootFolder.ServerRelativeUrl + "/Attachments/" + item.Id);
    FileCollection files = attFolder.Files;

    ctx.Load(files, fs => fs.Include(f => f.ServerRelativeUrl, 
                                     f => f.Name, 
                                     f => f.ServerRelativeUrl)
    );
    ctx.ExecuteQuery();

    return files;
}

public static void Download(string serverFilePath, string destPath, 
                            ClientContext context)
{
    using (FileInformation ffl = 
            Microsoft.SharePoint.Client.File.OpenBinaryDirect(context, serverFilePath))
    {
        if (System.IO.Directory.Exists(destPath))
        {
            using (Stream destFile = System.IO.File.OpenWrite(destPath))
            {
                byte[] buffer = new byte[8 * 1024];
                int len;
                while ((len = ffl.Stream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    destFile.Write(buffer, 0, len);
                }
            }
        }
    }
}

Solution

  • I tested this code without the Forms Auth. I passed the filename as a variable to your download function and completely rewrote the stream to file portion and made a few minor adjustments to your SharePoint calls. Works great now.

      static void Main(string[] args)
      {
          using (ClientContext context = new ClientContext(sp_site_address))
          {
                context.AuthenticationMode = ClientAuthenticationMode.FormsAuthentication;
                context.FormsAuthenticationLoginInfo = new FormsAuthenticationLoginInfo(username, pwd);
    
                List list = context.Web.Lists.GetByTitle(requests_list_name);
                CamlQuery query = new CamlQuery();
                query.ViewXml = "<View><RowLimit>100</RowLimit></View>";
                ListItemCollection items = list.GetItems(query);
                context.Load(items);
                context.ExecuteQuery();
    
                foreach (ListItem oListItem in items)
                {
                    FileCollection files = GetAttachments(context, list, oListItem);
                    foreach (Microsoft.SharePoint.Client.File f in files)
                    {
                        Download(f.ServerRelativeUrl, FolderToSaveTo, context, f.Name);
                    }
                    lstRequests.Add(Agreement);
                }
            }
        }
    
        public static FileCollection GetAttachments(ClientContext ctx, List list, ListItem item)
        {
            ctx.Load(list, l => l.RootFolder.ServerRelativeUrl);
            ctx.Load(ctx.Site, s => s.Url);
            ctx.ExecuteQuery();
    
            Folder attFolder = ctx.Web.GetFolderByServerRelativeUrl(list.RootFolder.ServerRelativeUrl + "/Attachments/" + item.Id);
            FileCollection files = attFolder.Files;
    
            ctx.Load(files, fs => fs.Include(f => f.ServerRelativeUrl, f => f.Name, f => f.ServerRelativeUrl));
            ctx.ExecuteQuery();
    
            return files;
    
        }
    
        public static void Download(string serverFilePath, string destPath, ClientContext context, string filename)
        {
            using (FileInformation ffl = Microsoft.SharePoint.Client.File.OpenBinaryDirect(context, serverFilePath))
            {
                if (System.IO.Directory.Exists(destPath))
                {
                    using (FileStream fileStream = System.IO.File.Create(destPath + "\\" + filename))
                    {
                        using (MemoryStream stream = new MemoryStream())
                        {
                            ffl.Stream.CopyTo(stream);
                            stream.WriteTo(fileStream);
                        }
                    }
                }
            }
        }