How can I reduce EWS calls when downloading attachments from an Inbox?

半城伤御伤魂 提交于 2019-12-23 04:13:06

问题


I wrote this method with much help from StackO, but I've been unable to find an a was to improve on this.

Right now, I iterate through each message in an Office 365 inbox, traverse its attachment collection, and save each file to disk if it's an Excel workbook. This is currently working, but results in a ton of calls to Exchange. The inbox size can get pretty large, and this takes a long time to run as a result, with each call clocking in at around 0.5 seconds.

If I've counted right, the number of calls scales as (n / 100) + 2n.

  • n is the number of messages in the inbox (2 calls per message)
  • 100 is the pageSize, as I haven't seen anything larger than this (one call every page)

Note: Typically (99.9999%) there's only one attachment per message, but I added the inner loop for CYA purposes. Might be some memory overhead, but little-to-no scaling factor.

I was wondering if there's a better way, with fewer web service calls. Is there an EWS method that could just download attachments in bulk? I'm pretty new to EWS, so I'm sure I'm lacking understanding here. What I want to do is reduce the pageSize and Load(path) a batch of files to disk, reducing the scale.

Any suggestions for improvement on the code below, with respect to reducing EWS calls, would be greatly appreciated.

public void SaveAttachmentsFromInbox(string[] extensionFilter = null)
    {

        // Default to excel files
        extensionFilter = extensionFilter ?? new[] { ".xls", ".xlsx" };

        // Config for traversing inbox
        int offset = 0;
        int pageSize = 100;
        ItemView view = new ItemView(pageSize, offset, OffsetBasePoint.Beginning);
        view.PropertySet = PropertySet.FirstClassProperties;
        FindItemsResults<Item> findResults;

        // Loop through the inbox
        //   and save all attachments of the designated file types
        bool more = true;
        var fileCount = 0;
        while (more)
        {

            findResults = service.FindItems(WellKnownFolderName.Inbox, view);
            // Load each sheet's data into an Object
            foreach (var item in findResults.Items)
            {
                //get FirstClassProperties
                item.Load(view.PropertySet);

                string vendor = GetVendor(EmailMessage.Bind(service, item.Id));
                messageIds.Add(item.Id.ToString());

                // Save files to disk
                foreach (FileAttachment file in item.Attachments)
                {
                    string fileExtension = file.Name.Substring(file.Name.IndexOf('.'), file.Name.Length - file.Name.IndexOf('.'));

                    if (extensionFilter.Contains(fileExtension))
                    {
                        var fullPath = Path.Combine(path, file.Name);
                        attachmentInfo.Add(fullPath, vendor);

                        // Loads attachment and saves to disk
                        file.Load(fullPath);

                        fileCount++;
                        Console.Write("\rFiles received... {0}    ", fileCount);
                    }
                }
            }



            Console.WriteLine(); // Next line

            more = findResults.MoreAvailable;
            // Page through inbox if more messages remain
            if (more)
            {
                view.Offset += pageSize;
            }
        }
        Console.WriteLine(attachmentInfo.Count + " Excel Attachment Downloads successful.\n");
    }

回答1:


As well as using AQS to cut down the recordset that is returned from the server you should make use of the batchs command to first get the Item properties using LoadPropertiesForItems (replaces the Bind in your code for each items) and then you can batch the Attachment download using GetAttachments (you need to make sure your using version 2.2 of the EWS Managed API) this will mean for example a batch of 100 item your making one FindItems Calls, a batch GetItem call and a Batch GetAttachment Call rather the 1 * 100 * 100 if you use Bind and Load. eg something like

         ItemView ivItemView = new ItemView(100);
        PropertySet flLevel = new PropertySet(BasePropertySet.IdOnly);
        ivItemView.PropertySet = flLevel;
        FindItemsResults<Item> faItems = service.FindItems(WellKnownFolderName.Inbox, "attachment:.xlsx OR attachment:xls", ivItemView);
        PropertySet slLevel = new PropertySet(BasePropertySet.FirstClassProperties);
        if (faItems.Items.Count > 0)
        {
            service.LoadPropertiesForItems(faItems, slLevel);
        }
        List<Attachment> atAttachments = new List<Attachment>();
        foreach (Item itItem in faItems.Items)
        {
            foreach (Attachment atAttachment in itItem.Attachments)
            {
                if (atAttachment is FileAttachment)
                {
                    string fileExtension = atAttachment.Name.Substring(atAttachment.Name.IndexOf('.'), atAttachment.Name.Length - atAttachment.Name.IndexOf('.'));
                    if (extensionFilter.Contains(fileExtension))
                    {
                        atAttachments.Add(atAttachment);

                    }
                }
            }
        }
        service.GetAttachments(atAttachments.ToArray(), BodyType.HTML,null);
        foreach (FileAttachment FileAttach in atAttachments)
        {
            Console.Write(FileAttach.Name);
            System.IO.File.WriteAllBytes("c:\\export\\" + FileAttach.Name, FileAttach.Content);
            //save off
        }



回答2:


If you are targeting Exchange 2010 or later versions, you could use a FindItem with Advanced Query Syntax:

ItemView view = new ItemView(100);
FindItemsResults<Item> results = service.FindItems(folder, "Has attachment:true", view);

foreach (Item item in results.Items)
{
  if (item is EmailMessage)
    {
      // Get the item and FileAttachments in the same way.
    }
}

I have not tried this myself, but it is possible that you could get a even better result with the AQS Has attachment:true AND .xlsx.



来源:https://stackoverflow.com/questions/33898269/how-can-i-reduce-ews-calls-when-downloading-attachments-from-an-inbox

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!