Looping through Items in Outlook 2003 and having speed issues?
Looping through contacts or other items using Outlook Object Model and C++ is faster than using C#. The primary reason being the "Interop" layer and the marshalling of data that takes place when we use C# with Outlook Object Model.
In this case I was looping through 10,000 contacts and it took me just 20-25 seconds in C++ and almost 2 minutes in C#. The challenge was to improve the performance. Here is how I did it.
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection; // to use Missing.Value
using System.IO;
using Outlook = Microsoft.Office.Interop.Outlook;
namespace ReadContact
{
public class Program
{
public static void Main(string[] args)
{
//Holds the start time
DateTime start;
//Holds the end time
DateTime end;
// Create the Outlook application.
Outlook.Application oApp = new Outlook.Application();
// Get the NameSpace information.
Outlook.NameSpace oNS = oApp.GetNamespace("MAPI");
// Log on by using a dialog box to choose the profile.
oNS.Logon(Missing.Value, Missing.Value, true, true);
// Get the contacts folder
Outlook.MAPIFolder myContacts = oNS.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderContacts);
// Get the items in the contact folder
Outlook.Items myContactItems = myContacts.Items;
// Record the start time
start = System.DateTime.Now;
// use SetColumns - This greatly improves performance
myContactItems.SetColumns("CompanyName,FirstName,LastName,Email1Address,IMAddress,BusinessTelephoneNumber, HomeTelephoneNumber,MobileTelephoneNumber");
// Use the foreach loop and get each item as an object instead of Microsoft.Office.Interop.Outlook.ContactItem
foreach (object item in myContactItems)
{
//Use reflection to get the desired properties
string FirstName = (string)GetProperty(item, "FirstName");
string LastName = (string)GetProperty(item, "LastName");
string HomeTelephoneNumber = (string)GetProperty(item, "HomeTelephoneNumber");
string IMAddress = (string)GetProperty(item, "IMAddress");
string BusinessTelephoneNumber = (string)GetProperty(item, "BusinessTelephoneNumber");
string MobileTelephoneNumber = (string)GetProperty(item, "MobileTelephoneNumber");
string CompanyName = (string)GetProperty(item, "CompanyName");
string Email1Address = (string)GetProperty(item, "Email1Address");
Console.WriteLine("First Name:" + " " + FirstName);
Console.WriteLine("Last Name:" + " " + LastName);
Console.WriteLine("Home Telephone Number:" + " " + HomeTelephoneNumber);
Console.WriteLine("IM Address:" + " " + IMAddress);
Console.WriteLine("Business Telephone Number:" + " " + BusinessTelephoneNumber);
Console.WriteLine("Mobile Telephone Number:" + " " + MobileTelephoneNumber);
Console.WriteLine("Company Name:" + " " + CompanyName);
Console.WriteLine("Email Address:" + " " + Email1Address);
}
//Record the end time
end = System.DateTime.Now;
//Get the difference
System.TimeSpan result2 = end.Subtract(start);
//Print the time taken
Console.WriteLine(String.Format("With SetColumns this took {0} ticks.", result2.Ticks));
Console.WriteLine(start.ToString());
Console.WriteLine(end.ToString());
// Log off.
oNS.Logoff();
//Clean up
oNS = null;
myContacts = null;
myContactItems = null;
oApp = null;
}
private static object GetProperty(object targetObject,string propertyName)
{
return targetObject.GetType().InvokeMember(propertyName,
System.Reflection.BindingFlags.Public |
System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.GetProperty,
null,
targetObject,
null,
System.Globalization.CultureInfo.CurrentCulture);
}
}
}
Although I was not able to get the exact performance that I got using C++ but results were a lot better - from 2 minutes to 55-60 seconds.
Comments
- Anonymous
August 26, 2008
You can greatly improve performance by caching a MethodInfo object during the reflection part. I believe that it will save the reflection engine the time it takes to "locate" the requested member....