简体   繁体   中英

Downloading Attachments over EWS API in C# is painfully slow - how to speed up?

I'm using the EWS Managed API in C# to download a bunch of messages from my company's exchange server. Loading the messages themselves takes a long time considering that service.FindItems() only fetches limited information about the messages, but it's not a huge deal. The serious problem I'm facing is how long it takes to load attachments.

The program is supposed to display an email and its image attachment side-by-side. When loading a new email, it can take well over a minute for the attachment to load. I initially fetched the attachments for each message when the message was loaded, but I thought it would be better to try to load them all at once into a List<EmailMessage> so the program wouldn't have to fetch the attachments when loading individual messages.

Here's the code I used to do that:

        fetchView.PropertySet = new PropertySet(BasePropertySet.FirstClassProperties);

        fetchView.Traversal = FolderTraversal.Deep;

        //create itemView for actual message query since we finally found the damn folder
        ItemView iView = new ItemView(int.MaxValue);

        FolderId sharedInboxFolder = new FolderId(WellKnownFolderName.Root, sharedMailbox);
        FolderId targetFolder = new FolderId(WellKnownFolderName.Root, sharedMailbox);



        FindFoldersResults inboxFolders = service.FindFolders(sharedInboxFolder, fetchView);
        bool folderFound = false;

        //look through the folders in the inbox to find the user-specified one by name
        foreach(Folder f in inboxFolders)
        {
            if (f.DisplayName == Properties.Settings.Default.InboxFolder)
            {
                targetFolder = f.Id;
                folderFound = true;

            }
        }


        // Set itemview properties for FindItems() operation
        fullProperties.Add(ItemSchema.Body);
        fullProperties.Add(ItemSchema.Attachments);
        fullProperties.Add(ItemSchema.DateTimeReceived);
        fullProperties.Add(ItemSchema.Subject);


        if (!folderFound)
        {
            MessageBox.Show("Folder not found!");
        } else {

            SearchFilter greaterthanfilter = new SearchFilter.IsGreaterThanOrEqualTo(ItemSchema.DateTimeReceived, searchDate);
            SearchFilter lessthanfilter = new SearchFilter.IsLessThan(ItemSchema.DateTimeReceived, searchDate.AddDays(1));
            SearchFilter dayFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.And, greaterthanfilter, lessthanfilter);

            FindItemsResults<Item> fetchedMessages = service.FindItems(targetFolder, dayFilter, iView);

            foreach (Item i in fetchedMessages.Items)
            {
                EmailMessage msg = EmailMessage.Bind(service, i.Id, fullProperties);
                emails.Add(msg);
            }
        }
    }

I then save all the attachments to disk with

for (int i = 0; i < message.Attachments.Count; i++)
            {
                if (message.Attachments[i] is FileAttachment)
                {
                    FileAttachment att = message.Attachments[i] as FileAttachment;
                    att.Load();
                    using (FileStream attStream = new FileStream(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\Program\images\" + i.ToString(), FileMode.Create, FileAccess.ReadWrite))
                    { 
                        att.Load(attStream);
                        attStream.Close();
                        attStream.Dispose();
                    }
                }
                else
                {
                    MessageBox.Show("Not FileAttachment!");
                }

            }

Then, to load an image and it's attachment, I do

imgViewer.Source = new BitmapImage(new Uri(/some/path/to/image/))

I suspect the hangup is during the save attachments phase. I found this post that indicated TraceFlags should be disabled, so I did service.TraceFlags = TraceFlags.None but that didn't seem to help at all. I'm contemplating just downloading all the attachments up front, or figuring out some kind of caching mechanism where I download the attachments of message[n+1...x] in the background while the user works on message[n], but this has limited usefulness, because the program should also let the user select an image and load it relatively instantly (ie much less than a minute).

Any suggestions are much appreciated.

Your loading the attachments twice for no apparent reason. Remove the att.Load(); from your if (message.Attachments[i] is FileAttachment) statement.

Maybe have a look at implementing paging and in turn consider reducing your ItemView pageSize to batches of 1000 or less, instead of MaxValue

Also make sure you are only returning what you need in your PropertySet . BasePropertySet.FirstClassProperties Consider changing this to just return what you need.

Side Note: A good way to identify slow performing code is to use the .Net Stopwatch class.

Stopwatch sw = new Stopwatch();
sw.Start();
// code
sw.Stop();
StopWatchLog stopWatchLog = new StopWatchLog();
stopWatchLog.CreateXMLTextFile("MethodName()" + " took" + sw.Elapsed.Seconds + " seconds.");

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM