1

I am trying to build a WPF application that queries our Exchange 2010 SP2 using the Exchange Web Services API.

However, I'm finding that if I use the Exchange API from a WPF application, the calls to the API are really, really slow. In fact they are two orders of magnitude slower than running the exact same code from a command-line application (some calls to the API takes 15 seconds when done from a WPF app and only 0.15 seconds when done from a command-line app).

I'm using Visual Studio 2015 with Exchange Web Services Managed API 2.2.

This is the code for WPF. In particular, what runs extremely slow is the call to folder.FindFolders in GetPathFolder:

using System;
using System.Windows;
using Microsoft.Exchange.WebServices.Data;

namespace esw_testwpf
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            var service = new ExchangeService(ExchangeVersion.Exchange2010_SP2);
            service.UseDefaultCredentials = true;
            service.TraceEnabled = true;
            service.TraceFlags = TraceFlags.All;
            service.AutodiscoverUrl("myemail@company.com", RedirectionUrlValidationCallback);

            Folder baseFolder = FindFolderIdByPath(service, @"\Path\To\A\Known\PublicFolder", WellKnownFolderName.PublicFoldersRoot);
        }

        private static bool RedirectionUrlValidationCallback(string redirectionUrl)
        {
            // The default for the validation callback is to reject the URL.
            bool result = false;

            Uri redirectionUri = new Uri(redirectionUrl);

            // Validate the contents of the redirection URL. In this simple validation
            // callback, the redirection URL is considered valid if it is using HTTPS
            // to encrypt the authentication credentials. 
            if (redirectionUri.Scheme == "https")
            {
                result = true;
            }
            return result;
        }

        public static Folder FindFolderIdByPath(ExchangeService service, string path, WellKnownFolderName root)
        {
            // Specify the root folder to be searched.
            Folder rootFolder = Folder.Bind(service, root);

            return GetPathFolder(rootFolder.FindFolders(new FolderView(100)), path, "");
        }

        public static Folder GetPathFolder(FindFoldersResults results, string lookupPath, string currentPath)
        {
            foreach (Folder folder in results)
            {
                string path = currentPath + @"\" + folder.DisplayName;
                if (lookupPath.Equals(path))
                {
                    return folder;
                }

                if (lookupPath.StartsWith(path))
                {
                    return GetPathFolder(folder.FindFolders(new FolderView(100)), lookupPath, path);
                }
                else
                {
                    continue;
                }
            }
            return null;
        }
    }
}

And this exactly the same code for command-line, which consistently runs very fast.

using System;
using Microsoft.Exchange.WebServices.Data;

namespace ewstestcmd
{
    class Program
    {
        static void Main(string[] args)
        {
            var service = new ExchangeService(ExchangeVersion.Exchange2010_SP2);
            service.UseDefaultCredentials = true;
            service.TraceEnabled = true;
            service.TraceFlags = TraceFlags.All;
            service.AutodiscoverUrl("myemail@company.com", RedirectionUrlValidationCallback);

            Folder baseFolder = FindFolderIdByPath(service, @"\Path\To\A\Known\PublicFolder", WellKnownFolderName.PublicFoldersRoot);
        }

        private static bool RedirectionUrlValidationCallback(string redirectionUrl)
        {
            // The default for the validation callback is to reject the URL.
            bool result = false;

            Uri redirectionUri = new Uri(redirectionUrl);

            // Validate the contents of the redirection URL. In this simple validation
            // callback, the redirection URL is considered valid if it is using HTTPS
            // to encrypt the authentication credentials. 
            if (redirectionUri.Scheme == "https")
            {
                result = true;
            }
            return result;
        }

        public static Folder FindFolderIdByPath(ExchangeService service, string path, WellKnownFolderName root)
        {
            // Specify the root folder to be searched.
            Folder rootFolder = Folder.Bind(service, root);

            return GetPathFolder(rootFolder.FindFolders(new FolderView(100)), path, "");
        }

        public static Folder GetPathFolder(FindFoldersResults results, string lookupPath, string currentPath)
        {
            foreach (Folder folder in results)
            {
                string path = currentPath + @"\" + folder.DisplayName;
                if (lookupPath.Equals(path))
                {
                    return folder;
                }

                if (lookupPath.StartsWith(path))
                {
                    return GetPathFolder(folder.FindFolders(new FolderView(100)), lookupPath, path);
                }
                else
                {
                    continue;
                }
            }
            return null;
        }
    }
}

Why do I get such a different behavior in Exchange API response time if the code is essentially the same?

I first thought it was some kind of server-side throttling, but it does not make sense to me that the WPF variant is always very slow and the command-line variant is always very fast.

Pep
  • 1,957
  • 2
  • 24
  • 40
  • Have you tried release builds of both and running it without a debugger attached? Is it still slower? – J.H. May 10 '16 at 18:56
  • Yes, the release build takes about the same time. The WPF version from start to end takes 26-27 seconds while the command line version takes about one second. – Pep May 10 '16 at 19:44
  • However, it seems that if I change `service.TraceEnabled = true;` to `service.TraceEnabled = false;` all the extra delay disappears. For some reason EWS tracing impacts heavily WPF. – Pep May 10 '16 at 19:46

1 Answers1

2

When I changed:

service.TraceEnabled = true;

to

service.TraceEnabled = false;

all extra delay in WPF disappeared. So it seems that, for some reason, enabling tracing for EWS in a WPF takes a huge performance hit.

Pep
  • 1,957
  • 2
  • 24
  • 40