对于循环运行缓慢

I have a Web Method that is querying Outlook to grab all the distribution lists from the Global Address List.

This is grabbing over 4,000 distribution lists, which is exactly what I want it to do, but when it goes into the loop to pass the 4,000 lists into my List it takes over 3 minutes for it to finish the for loop. Can anyone see anything that is out of the ordinary and have an answer of why this may be happening?

Here is my code:

        public class DistributionListDetails
        {
            public int DistributionListId { get; set; }
            public string DistributionListEmail { get; set; }
        }

        List<DistributionListDetails> distributionLists = new List<DistributionListDetails>();
        int val = 0;

        //create Outlook application. 
        Outlook.Application oApp = new Outlook.Application();

        //get Mapi NameSpace and Logon. 
        Outlook.NameSpace oNS = oApp.GetNamespace("mapi");

        //get Global Address List. 
        Outlook.AddressLists oDLs = oNS.AddressLists;
        Outlook.AddressList oGal = oDLs["Global Address List"];

        //get a specific distribution list. 
        string sDL = "TestDL";
        Outlook.AddressEntries oEntries = oGal.AddressEntries;
        Outlook.AddressEntry oDL = oEntries[sDL];

        if (oDL.Manager != null)
        distributionLists.Add(new DistributionListDetails
            {
                DistributionListId = val,
                DistributionListEmail = oDL.Manager.ToString()
            });

        //get all of the members of the distribution list. 
        oEntries = oDL.Members;
        Outlook.AddressEntry oEntry = default(Outlook.AddressEntry);

        int i = 0;
        for (i = 1; i <= oGal.AddressEntries.Count && i <= 10; i++)
        {
            oEntry = oGal.AddressEntries[i];
            distributionLists.Add(new DistributionListDetails
            {
                DistributionListId = val,
                DistributionListEmail = oEntry.Name
            });
        }

NOTE: I am binding the returned list from the loop to a dropdown via AJAX.

Assuming that the query to AD isn't the bottleneck, try this LINQ on for size. It replaces your last loop.

distributionLists.AddRange(oGal.AddressEntries
  .Cast<Outlook.AddressEntry>()
  .Select(
    x => new DistributionListDetails 
    { 
        DistributionListId = val, 
        DiestributionListEmail = x.Name
    }));

Edit: Force cast the AddressEntries into an IQueryable so select will work.

I guess you are running this method to grab distribution lists every time someone calls this method. Instead of doing that, it's better to cachce the distribution lists and access them from cache when needed.

  1. Create a repository class for the distribution lists
  2. When a user calls this method for the first time, load the repository from outlook using your method. Then Store it in MemoryCache. You have to select a suitable policy for caching. For an example if, you need to refresh your cached distribution list hourly basis, you have to use absolute expiration and set it to 1hr. If not, you can use sliding expiration which extends the life time of the cached object as users access the lists.
  3. Your repository should first check if the cached object is available, if yes, use it. Else load it again using the above method.

If you were using C++ or Delphi, you could use AddressEntires.RawTable (returns IMAPITable MAPI object) and use IMAPITable::SetColumns/QueryRows or HrQueryAllRows.

If using Redemption is an option, you could use it MAPITable object. Off the top of my head:

 Redemption.MAPITable table = new Redemption.MAPITable(); 
 table.Item = oGal.AddressEntries;
 ADODB.Recordset recordset = table.ExecSQL("SELECT name from Table");
 while (!recordset.EOF)
 { 
      string name = recordset.Fields(0).Value;
      recordset.MoveNext();
  }