【问题标题】:Find all subfolders of the Inbox folder using EWS使用 EWS 查找收件箱文件夹的所有子文件夹
【发布时间】:2011-11-27 06:40:09
【问题描述】:

我有以下收件箱文件夹结构:

Inbox
--ABC
----ABC 2
----ABC 3
--XYZ
----XYZ 2
--123
----123 A
----123 B
----123 C

我正在使用 Exchange Web 服务和以下代码来查找收件箱文件夹的子文件夹:

ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010);

service.AutodiscoverUrl("MyName@MyDomain.com");
Mailbox mb = new Mailbox("MyName@MyDomain.com");

FindFoldersResults findResults = service.FindFolders(
    WellKnownFolderName.Inbox,
    new FolderView(int.MaxValue));

foreach (Folder folder in findResults.Folders)
{
    Console.WriteLine(folder.DisplayName);
}

这部分有效,因为它返回 ABC、XYZ 和 123 文件夹;不幸的是,它不会返回每个文件夹中的文件夹(ABC 2、ABC 3、XYZ 2、123 A、123 B、123 C)。

此外,一个文件夹内可能有多个级别的子文件夹。

如何编写此代码以便返回所有子文件夹,无论它们嵌套的深度如何?

【问题讨论】:

    标签: c# recursion exchange-server exchangewebservices


    【解决方案1】:

    只需几次调用,您就可以分页您的请求并从服务器获取整个文件夹层次结构。正如 Jacob 所指出的,关键是 FolderView.Traversal 属性。

    例如,对于包含约 1,300 个文件夹的 Exchange 邮箱,以下代码仅发出 2 个请求。您可以将页面大小设置为您喜欢的任何大小,只要您保持在或低于服务器限制即可。

    仅供参考:Exchange Online (Office365) 在响应中最多包含 1,000 个项目。我没有测试过,所以在查询本地 Exchange Server 时,我无法说出任何类似的限制。

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Security;
    using Exchange = Microsoft.Exchange.WebServices.Data; // from nuget package "Microsoft.Exchange.WebServices"
    
    namespace FolderViewTraversal
    {
        class Program
        {
            public static void Main()
            {
                Exchange.ExchangeService oService;
                Dictionary<string, User> oUsers;
    
                oUsers = new Dictionary<string, User>
                {
                    { "User1", new User("write.to.me1@my.address.com", "Some-Fancy-Password1") },
                    { "User2", new User("write.to.me2@my.address.com", "Some-Fancy-Password2") }
                };
    
                foreach (KeyValuePair<string, User> Credential in oUsers)
                {
                    File.Delete(String.Format(LOG_FILE_PATH, Credential.Key)); 
                }
                foreach (KeyValuePair<string, User> Credential in oUsers)
                {
                    LogFileName = Credential.Key;
    
                    Console.WriteLine("Getting message counts for mailbox [{0}]...", LogFileName);
                    Console.WriteLine();
    
                    oService = Service.ConnectToService(Credential.Value);
    
                    GetAllFolders(oService, String.Format(LOG_FILE_PATH, Credential.Key));
    
                    Console.Clear();
                };
    
                Console.WriteLine();
                Console.Write("Press any key to exit...");
                Console.ReadKey();
            }
    
            private static void GetAllFolders(Exchange.ExchangeService Service, string LogFilePath)
            {
                Exchange.ExtendedPropertyDefinition oIsHidden = default;
                List<Exchange.Folder> oFolders = default;
                Exchange.FindFoldersResults oResults = default;
                bool lHasMore = false;
                Exchange.Folder oChild = default;
                Exchange.FolderView oView = default;
    
                short nPageSize = 0;
                short nOffSet = 0;
    
                List<string> oPaths = default;
                List<string> oPath = default;
    
                oIsHidden = new Exchange.ExtendedPropertyDefinition(0x10f4, Exchange.MapiPropertyType.Boolean);
                nPageSize = 1000;
                oFolders = new List<Exchange.Folder>();
                lHasMore = true;
                nOffSet = 0;
    
                while (lHasMore)
                {
                    oView = new Exchange.FolderView(nPageSize, nOffSet, Exchange.OffsetBasePoint.Beginning)
                    {
                        PropertySet = new Exchange.PropertySet(Exchange.BasePropertySet.IdOnly)
                    };
                    oView.PropertySet.Add(oIsHidden);
                    oView.PropertySet.Add(Exchange.FolderSchema.ParentFolderId);
                    oView.PropertySet.Add(Exchange.FolderSchema.DisplayName);
                    oView.PropertySet.Add(Exchange.FolderSchema.FolderClass);
                    oView.PropertySet.Add(Exchange.FolderSchema.TotalCount);
                    oView.Traversal = Exchange.FolderTraversal.Deep;
    
                    oResults = Service.FindFolders(Exchange.WellKnownFolderName.MsgFolderRoot, oView);
                    oFolders.AddRange(oResults.Folders);
    
                    lHasMore = oResults.MoreAvailable;
    
                    if (lHasMore)
                    {
                        nOffSet += nPageSize;
                    }
                }
    
                oFolders.RemoveAll(Folder => (bool)Folder.ExtendedProperties[0].Value == true);
                oFolders.RemoveAll(Folder => Folder.FolderClass != "IPF.Note");
    
                oPaths = new List<string>();
    
                oFolders.ForEach(Folder =>
                {
                    oChild = Folder;
                    oPath = new List<string>();
    
                    do
                    {
                        oPath.Add(oChild.DisplayName);
                        oChild = oFolders.SingleOrDefault(Parent => Parent.Id.UniqueId == oChild.ParentFolderId.UniqueId);
                    } while (oChild != null);
    
                    oPath.Reverse();
                    oPaths.Add(String.Format("{0}{1}{2}", String.Join(DELIMITER, oPath), '\t', Folder.TotalCount));
                });
    
                oPaths.RemoveAll(Path => Path.StartsWith("Sync Issues"));
    
                File.WriteAllText(LogFilePath, String.Join(Environment.NewLine, oPaths));
            }
    
            private static string LogFileName;
            private const string LOG_FILE_PATH = "D:\\Emails\\Remote{0}.txt";
            private const string DELIMITER = "\\";
        }
    
        internal class Service
        {
            public static Exchange.ExchangeService ConnectToService(User User)
            {
                return Service.ConnectToService(User, null);
            }
    
            public static Exchange.ExchangeService ConnectToService(User User, Exchange.ITraceListener Listener)
            {
                Exchange.ExchangeService oService = default;
    
                oService = new Exchange.ExchangeService(Exchange.ExchangeVersion.Exchange2013_SP1)
                {
                    Credentials = new NetworkCredential(User.EmailAddress, User.Password)
                };
                oService.AutodiscoverUrl(User.EmailAddress, RedirectionUrlValidationCallback);
    
                if (Listener != null)
                {
                    oService.TraceListener = Listener;
                    oService.TraceEnabled = true;
                    oService.TraceFlags = Exchange.TraceFlags.All;
                }
    
                return oService;
            }
    
            private static bool RedirectionUrlValidationCallback(string RedirectionUrl)
            {
                var _with1 = new Uri(RedirectionUrl);
                return _with1.Scheme.ToLower() == "https";
            }
        }
    
        internal class User
        {
            public string EmailAddress { get; }
            public SecureString Password { get; }
    
            public User(string EmailAddress)
            {
                this.EmailAddress = EmailAddress;
                this.Password = new SecureString();
            }
    
            public User(string EmailAddress, string Password)
            {
                this.EmailAddress = EmailAddress;
                this.Password = new SecureString();
    
                foreach(char Chr in Password) { this.Password.AppendChar(Chr); };
    
                this.Password.MakeReadOnly();
            }
    
            public static User GetUser()
            {
                Console.Write("Enter email address: ");
                string sEmailAddress = Console.ReadLine();
                Console.Write("Enter password: ");
    
                User functionReturnValue = new User(sEmailAddress);
    
                while (true)
                {
                    ConsoleKeyInfo oUserInput = Console.ReadKey(true);
                    if (oUserInput.Key == ConsoleKey.Enter)
                    {
                        break; // TODO: might not be correct. Was : Exit While
    
                    }
                    else if (oUserInput.Key == ConsoleKey.Escape)
                    {
                        functionReturnValue.Password.Clear();
    
                    }
                    else if (oUserInput.Key == ConsoleKey.Backspace)
                    {
                        if (functionReturnValue.Password.Length != 0)
                        {
                            functionReturnValue.Password.RemoveAt(functionReturnValue.Password.Length - 1);
                        }
    
                    }
                    else
                    {
                        functionReturnValue.Password.AppendChar(oUserInput.KeyChar);
                        Console.Write("*");
    
                    }
                }
    
                if (functionReturnValue.Password.Length == 0)
                {
                    functionReturnValue = null;
                }
                else
                {
                    functionReturnValue.Password.MakeReadOnly();
                    Console.WriteLine();
                }
                return functionReturnValue;
            }
    
        }
    
        internal class TraceListener : Exchange.ITraceListener
        {
    
            public void Trace(string TraceType, string TraceMessage)
            {
                File.AppendAllText(String.Format("{0}.txt", Path.Combine("D:\\Emails\\TraceOutput", Guid.NewGuid().ToString("D"))), TraceMessage);
            }
        }
    }
    

    【讨论】:

    • @garfbradaz:感谢你这么说。我不同意这值得投反对票——这些天翻译非常简单——但这完全是另一点。所以,如果我编辑并翻译成 C#,会在你看来解决问题吗?
    • @garfbradaz — 如果我翻译成 C# 并发布一个编辑,那会赢回投票吗?
    • @garfbradaz — 你不厌其烦地解释为什么你损害了我的声誉——对此表示赞赏——但你还没有回答我的后续问题。再说一遍:如果我翻译成 C# 并发布一个编辑,那会赢回投票吗?
    • 我当然会 :) 我什至会在你的评论上写一个 +1 ?
    • @AhmadAgbaryah:我已修复此代码并在 .Net Framework 4.8 控制台中对其进行编译。尽管那里有很多与问题无关的代码。
    【解决方案2】:

    您可以告诉 EWS 在搜索文件夹时进行深度遍历。您可以使用FolderView.Traversal 属性来执行此操作。然后您的代码将更改为类似于以下内容:

    FindFoldersResults findResults = service.FindFolders(
        WellKnownFolderName.Inbox,
        new FolderView(int.MaxValue) { Traversal = FolderTraversal.Deep });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-02
      • 1970-01-01
      • 2013-05-18
      • 1970-01-01
      • 2021-12-22
      • 1970-01-01
      相关资源
      最近更新 更多