Exchange Web 服务:使用 FindItemsResult进行批处理

发布于 2024-09-25 06:37:12 字数 2929 浏览 7 评论 0原文

我正在编写一个应用程序来使用 Exchange Web 服务处理电子邮件附件。

我的问题区域的总体结构如下:

public static void Main()
{
    FindItemsResults<Item> findResults = FindItems();

    foreach (Item item in findResults)
    {
        DoSomethingWithItem(item);
    }
}

public static FindItemsResults<Item> FindItems()
{
            FindItemsResults<Item> findResults;

            ItemView view = new ItemView(10);    //batching 10 at a time
            view.OrderBy.Add(ItemSchema.DateTimeReceived, SortDirection.Ascending);
            view.PropertySet = new PropertySet(
                BasePropertySet.IdOnly,
                ItemSchema.Subject,
                ItemSchema.DateTimeReceived);

            findResults = service.FindItems(
                WellKnownFolderName.Inbox,
                new SearchFilter.SearchFilterCollection(
                    LogicalOperator.Or,
                    new SearchFilter.ContainsSubstring(ItemSchema.Subject, Properties.Settings.Default.EmailSubject)),
                view);

            //return set of emails
            return findResults;
}

起初,这看起来不错 - 它很好地处理了我之前的测试示例。但是当我开始使用批量加载进行测试时,我意识到它只处理前 10 个项目,因为我指定了 10 个项目的批量大小 (ItemView view = new ItemView(10)),但是我没有检查更多批次。

我本来可以简单地增加批处理大小,但后来快速谷歌一下,我发现了一个更好的例子:

public static FindItemsResults<Item> FindItems()
{
            FindItemsResults<Item> findResults;

            ItemView view = new ItemView(10, 0, OffsetBasePoint.Beginning); 
            view.OrderBy.Add(ItemSchema.DateTimeReceived, SortDirection.Ascending);
            view.PropertySet = new PropertySet(
                BasePropertySet.IdOnly,
                ItemSchema.Subject,
                ItemSchema.DateTimeReceived);

            do
            {
                findResults = service.FindItems(
                    WellKnownFolderName.Inbox,
                    new SearchFilter.SearchFilterCollection(
                        LogicalOperator.Or,
                        new SearchFilter.ContainsSubstring(ItemSchema.Subject, Properties.Settings.Default.EmailSubject)),
                    view);

                //any more batches?
                if (findResults.NextPageOffset.HasValue)
                {
                    view.Offset = findResults.NextPageOffset.Value;
                }
            }
            while (findResults.MoreAvailable);

            return findResults;
}

这个循环遍历了我想扔给它的尽可能多的电子邮件,但由于我尚不明白的原因, foreach 循环现在只处理 findResults 中的第一项。

即使 findResults 包含多个项目 (findResults.Items.Count > 1),在我的第二个示例中,findResults.MoreAvailable = false。公平地说,我之前已经循环浏览过这些批次,因此我查看最后一批的末尾是有道理的。

但是我如何重置 findResults 以便它能够处理整个批次?我尝试设置 findResults.MoreAvailable 但它是只读的...我错过了什么?

结论:

好的,所以我可以一次处理一批项目,也可以将每批中的每个项目添加到列表中并稍后处理它们,就像我目前所做的那样。

他们之间没有太多的关系;我最初开始使用列表,但我会进一步考虑这个选择。

I'm writing an app to process email attachments, using Exchange Web Services.

The general structure of my problem area is as follows:

public static void Main()
{
    FindItemsResults<Item> findResults = FindItems();

    foreach (Item item in findResults)
    {
        DoSomethingWithItem(item);
    }
}

public static FindItemsResults<Item> FindItems()
{
            FindItemsResults<Item> findResults;

            ItemView view = new ItemView(10);    //batching 10 at a time
            view.OrderBy.Add(ItemSchema.DateTimeReceived, SortDirection.Ascending);
            view.PropertySet = new PropertySet(
                BasePropertySet.IdOnly,
                ItemSchema.Subject,
                ItemSchema.DateTimeReceived);

            findResults = service.FindItems(
                WellKnownFolderName.Inbox,
                new SearchFilter.SearchFilterCollection(
                    LogicalOperator.Or,
                    new SearchFilter.ContainsSubstring(ItemSchema.Subject, Properties.Settings.Default.EmailSubject)),
                view);

            //return set of emails
            return findResults;
}

At first, this looked OK - it processed my earlier test examples perfectly well. But when I start testing with bulk loads, I realised that it was only processing the first 10 items, since I was specifying a batch size of 10 items (ItemView view = new ItemView(10)), but I wasn't checking for further batches.

I could have simply increased the batch size, but a quick google later, I found a better example:

public static FindItemsResults<Item> FindItems()
{
            FindItemsResults<Item> findResults;

            ItemView view = new ItemView(10, 0, OffsetBasePoint.Beginning); 
            view.OrderBy.Add(ItemSchema.DateTimeReceived, SortDirection.Ascending);
            view.PropertySet = new PropertySet(
                BasePropertySet.IdOnly,
                ItemSchema.Subject,
                ItemSchema.DateTimeReceived);

            do
            {
                findResults = service.FindItems(
                    WellKnownFolderName.Inbox,
                    new SearchFilter.SearchFilterCollection(
                        LogicalOperator.Or,
                        new SearchFilter.ContainsSubstring(ItemSchema.Subject, Properties.Settings.Default.EmailSubject)),
                    view);

                //any more batches?
                if (findResults.NextPageOffset.HasValue)
                {
                    view.Offset = findResults.NextPageOffset.Value;
                }
            }
            while (findResults.MoreAvailable);

            return findResults;
}

This loops through as many emails as I care to throw at it, but for reasons I can't yet understand, the foreach loop now only processes the first item in findResults.

Even though findResults contains more than one item (findResults.Items.Count > 1), with my second example, findResults.MoreAvailable = false. Fair enough, I've looped through the batches earlier, so it makes sense that I'm looking at the end of the last batch.

But how do I reset findResults so that it will process the whole lot? I tried setting findResults.MoreAvailable but it is readonly... What am I missing?

CONCLUSION:

OK, so I can either process the items one batch at a time, or I can add each item in each batch to a List and process them later, as I currently do.

There is not a lot between them; I've initially started using a List, but I'll consider the choice further.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

野稚 2024-10-02 06:37:12

在我看来,您的主要问题是您尝试定义一个返回 FindItemsResults 的函数。如果您使用结果配对,您将没有这种类型的对象。而不是在检索每个新页面时,FindItemsResults 将被覆盖。以下示例显示收件箱中所有项目的主题:

ItemView view = new ItemView(10, 0, OffsetBasePoint.Beginning);
view.OrderBy.Add(ItemSchema.DateTimeReceived, SortDirection.Descending);
view.PropertySet = new PropertySet(
    BasePropertySet.IdOnly,
    ItemSchema.Subject,
    ItemSchema.DateTimeReceived);

// save the folder where we will make searching to do this one time
Folder myInbox = Folder.Bind(service, WellKnownFolderName.Inbox);

FindItemsResults<Item> findResults;

do
{
    findResults = myInbox.FindItems(
        new SearchFilter.ContainsSubstring(ItemSchema.Subject,
                Properties.Settings.Default.EmailSubject)),
        view);

    foreach (Item item in findResults)
    {
        // Do something with the item.
        Console.WriteLine();
        if (item is EmailMessage)
        {
            EmailMessage em = item as EmailMessage;
            Console.WriteLine("Subject: \"{0}\"", em.Subject);
        }
        else if (item is MeetingRequest)
        {
            MeetingRequest mr = item as MeetingRequest;
            Console.WriteLine("Subject: \"{0}\"", mr.Subject);
        }
        else
        {
            // we can handle other item types
        }
    }

    //any more batches?
    if (findResults.NextPageOffset.HasValue)
    {
        view.Offset = findResults.NextPageOffset.Value;
    }
}
while (findResults.MoreAvailable);

该代码在控制台输出上显示主题。如果您想以其他方式使用EmailMessageMeetingRequest,您应该修改对应的代码。您还可以定义一个委托,它对找到的 EmailMessageMeetingRequest 执行某些操作,并在 Console.WriteLine 的位置调用该委托。如果您确实需要在某个地方相同的所有项目,那么您将必须创建一些集合,例如 List,在其中填写函数并返回,而不是 FindItemsResults > 您目前正在做的事情。

It seems to my that your main problem is that you try define a function which returns FindItemsResults<Item>. If you use paring of results you will have not one object of this type. Instead of that on retrieving of every new page the FindItemsResults<Item> will be overwritten. Following example display subjects of all items from the Inbox:

ItemView view = new ItemView(10, 0, OffsetBasePoint.Beginning);
view.OrderBy.Add(ItemSchema.DateTimeReceived, SortDirection.Descending);
view.PropertySet = new PropertySet(
    BasePropertySet.IdOnly,
    ItemSchema.Subject,
    ItemSchema.DateTimeReceived);

// save the folder where we will make searching to do this one time
Folder myInbox = Folder.Bind(service, WellKnownFolderName.Inbox);

FindItemsResults<Item> findResults;

do
{
    findResults = myInbox.FindItems(
        new SearchFilter.ContainsSubstring(ItemSchema.Subject,
                Properties.Settings.Default.EmailSubject)),
        view);

    foreach (Item item in findResults)
    {
        // Do something with the item.
        Console.WriteLine();
        if (item is EmailMessage)
        {
            EmailMessage em = item as EmailMessage;
            Console.WriteLine("Subject: \"{0}\"", em.Subject);
        }
        else if (item is MeetingRequest)
        {
            MeetingRequest mr = item as MeetingRequest;
            Console.WriteLine("Subject: \"{0}\"", mr.Subject);
        }
        else
        {
            // we can handle other item types
        }
    }

    //any more batches?
    if (findResults.NextPageOffset.HasValue)
    {
        view.Offset = findResults.NextPageOffset.Value;
    }
}
while (findResults.MoreAvailable);

The code display the subjects on the console output. If you want to use EmailMessage or MeetingRequest in another way you should modify the code correspondent. You can also define a delegate which do something with the found EmailMessage or MeetingRequest and call the delegate on the place of Console.WriteLine. If you do need to same all items somewhere, then you will have to create some collection like List<Item>, fill there in the function and return instead of FindItemsResults<Item> which you currently do.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文