获取共享的 Outlook 日历事件 C#

坚持

我知道如何在当前用户的 Outlook 日历中检索事件,例如,以下代码可用于删除与特定模式匹配的项目:

private void RemoveAppointments()
        {
            Outlook.Application outlook = new Outlook.Application();
            Outlook.MAPIFolder calendarFolder = outlook.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderCalendar);
            Outlook.Items outlookCalendarItems = calendarFolder.Items;
            for (int i = outlookCalendarItems.Count; i > 0; i--)
            {
                if (outlookCalendarItems[i].Subject.Contains("On Call: Regions:") && outlookCalendarItems[i].Start.Year == _year)
                {
                    outlookCalendarItems[i].Delete();
                }
            }
        }

但是,我现在需要能够从 Outlook 团队中的所有用户读取日历事件(假设共享权限已正确设置)。理想情况下,我需要能够对每个用户进行迭代,但是如果我只是获取所有事件的集合,然后可以按用户查询就足够了。

我可以从哪里开始的任何想法?


注意:这是团队在 Outlook 的“日历”窗格中的表示方式。敏感细节已编辑。

日历部分栏

坚持

Thanks to @Dmitry for his answer which helped me solve my issue. However, to maximise the utility of this question for future readers I thought I'd expand on it.


Assume that:

using Microsoft.Office.Interop.Outlook;

and that the COM assembly Microsoft Outlook 16.0 Object Library is referenced.


The first step is to create an Outlook.Application object that serves as an interface to Outlook's functions (you can think of it as an internal instance of the full Outlook program):

Application app = new Application();

From this I then pull all of the users from the distribution list in the Global Address List that is associated with the team. This is done by creating a Recipient object from the Session property of the Application instance.

Recipient distList = app.Session.CreateRecipient(yourDistList);

From here we can pull all of the real names and usernames vie the AdressEntry.Members property of our Recipient. To pull these both into an anonymous tuple of (string,string) we can use this LINQ query, if you don't like that you can just iterate like normal:

List<(string,string)> usersData = distList.AddressEntry.Members.Cast<AddressEntry>().Select(entry => (entry.Name,entry.Address)).ToList();

Now, given a specific username, as long as the calendar has been shared with the curernt user you can access it using the GetSharedDefaultFolder() method of the Session:

MAPIFolder sharedCalendar = _app.Session.GetSharedDefaultFolder(teamMember, OlDefaultFolders.olFolderCalendar);

At this point I found it useful to do some filtering to try and avoid the most common COMExceptions however, there are plenty I can't seem to determine the cause of so I just catch (COMException) and bin them off. Not good practice I know but it didn't seem to interfere with me accessing calendars that I had permissions for. Some (very) basic filtering:

if (sharedCalendar.DefaultMessageClass != "IPM.Appointment" || teamMember.DisplayType != 0)
{
    return null; //Calendar not shared.
}

Now we have to build a Filter string utilising the Microsoft Outlook format, this can be done using the following statement (where from and to are both DateTime objects):

string sFilter = $"[End] > '{from:g}' AND [Start] < '{to:g}' AND [Recurring] = 'No'";

We filter out recurring events as otherwise the Start and End dates can be wildly outside the range with no internal occurrences. For my purposes, I didn't need recurring events anyway, however, if you do you will have to deal with this separately.

Finally we can now collect the events we need utilising the Items.Restrict() method of MAPIFolder:

Items results = sharedCalendar.Items.Restrict(sFilter);

This returns an Items interface to all of the items falling within our filter.

最后,我们可以迭代每个项目(我以相反的顺序迭代,因为我从我的旧应用程序中复制了删除事件的代码,但在这种情况下应该无关紧要)。您可能需要强制转换objectAppointmentItem依赖于这是否可以被编译器推断。

List<AppData> appointments = new List<AppData>();
for (int i = results.Count; i > 0; i--)
{
    appointments.Add(new AppData(results[i], username));
}

我将每个事件存储为一个AppData结构体,只保留我需要的数据:

public struct AppData
{
    public string Subject { get; }
    public DateTime From { get; }      
    public DateTime To { get; }       
    public string Location { get; }      
    public string Categories { get; }      
    public string Username { get; }
    public AppData(AppointmentItem appItem, string username)
    {
        Subject = appItem.Subject;
        From = appItem.Start;
        To = appItem.End;
        Location = appItem.Location;
        Categories = appItem.Categories;
        Username = username;
    }
}

所有这些都会产生一个看起来像这样的类:

public class OutlookCommunicator : IDisposable
{
    private readonly Application _app;

    public OutlookCommunicator()
    {
        _app = new Application();
    }

    /// <summary>
    /// Username of the distribution list according to the GAL.
    /// </summary>
    private const string DistList = "redacted";

    /// <summary>
    /// Fetches a list of all usernames and names within the DistList.
    /// </summary>
    /// <returns>List&lt;string&gt; containing all usernames.</returns>
    public List<(string,string)> GetUsers()
    {
            Recipient warEngineering = _app.Session.CreateRecipient(DistList);
            List<(string,string)> usernames = warEngineering.AddressEntry.Members.Cast<AddressEntry>().Select(entry => (entry.Name,entry.Address)).ToList();
            return usernames;

    }



    /// <summary>
    /// Fetches all calendar events for a user falling within the provided range.
    /// </summary>
    /// <param name="from">Start search date.</param>
    /// <param name="to">End search dat.</param>
    /// <param name="username">User's calendar to search.</param>
    /// <returns></returns>
    public List<AppData> GetEventsInRange(DateTime from, DateTime to, string username)
    {
        List<AppData> appointments = new List<AppData>();
        try
        {

            Recipient teamMember = _app.Session.CreateRecipient(username);
            MAPIFolder sharedCalendar = _app.Session.GetSharedDefaultFolder(teamMember, OlDefaultFolders.olFolderCalendar);
            if (sharedCalendar.DefaultMessageClass != "IPM.Appointment" || teamMember.DisplayType != 0)
            {
                return null; //Calendar not shared.
            }

            string sFilter = $"[End] > '{from:g}' AND [Start] < '{to:g}' AND [Recurring] = 'No'";
            Items results = sharedCalendar.Items.Restrict(sFilter);
            for (int i = results.Count; i > 0; i--)
            {
                appointments.Add(new AppData(results[i], username));
            }

            return appointments;
        }
        catch (COMException)
        {
            return null;
        }
    }

    public void Dispose()
    {
        _app?.Quit();
    }

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章