工作遇到新需求:辦公室自動化服務希望讀取使用者行事曆,整合顯示於個人資訊頁。

EWS Managed API 封裝了複雜又囉嗦的 Exchange Web Service SOAP 細節,改以 .NET 程式庫形式提供電子郵件、連絡人、行事曆、公用資料夾的存取管道,是 C# 開發 Exchange 相關程式的首選。(意外發現 EWS Managed API 從 2014 起轉為 Github 開源專案,有原始碼在手,搞不懂走不通都有救,用起來格外讓人放心,微軟真的愈來愈開放)

官方文件有篇詳細介紹文,示範如何使用 EWS Mananged API 查詢行事曆取得個人約會資訊。基本原理是利用 CalendarFolder.Bind() 連上個人行事曆,接著建立一個 CalendarView 指定查詢期間、取回筆數,CalendarView.PropertySet 則傳入要讀取的欄位(主旨、開始/結束時間… 等),接著呼叫 CalendarFolder.FindAppointments() 就取得 Appointment 的集合,很簡單,這部分可直接參考官方範例。好消息是 EWS Managed API 用 NuGet 就可以下載:

不過我的需求多了一些變化,系統會使用統一中間程式查詢不同使用者的行事曆,而我們不可能為此要使用者交出 AD 帳號密碼。因此,透過行事曆共用是較可行做法。

行事曆共用可使用 Outlook 操作, 找到自己的行事曆(一般會有兩份,要選名稱有個人郵件地址位於 Exchange Server 的那一份),右鍵選單開啟內容:

程式使用 EWS Managed API 會以特定 AD 帳號執行(測試時可用開發者自己的帳號,正式營運則會申請專用帳號),要開放行事曆供程式存取,使用者必須授與該帳號讀取權限,授權完成可使用 Outlook 檢查是否看到測試對象的約會做為驗證。但有一點要留意,除了授權讀取空閒/忙碌時間、主旨、地點外,其他區域有個「可看到資料夾」一定要勾選。未勾選時 Oulook 可查看共享行事曆,但 EWS Managed API 不行,我花了不少時間才發現這個眉角。

若要求省事,也可請共用行事曆的使用者直接選取「權限等級:檢閱者」;若使用者很介意約會細節外流,只想透露主旨、地點,甚至只打算開放/空閒忙碌資訊,只勾選自己想開放範圍也成,但記得一定要勾選「可看到資料夾」,不然程式沒戲唱:

程式範例如下。查詢他人行事曆時,有個關鍵是使用 new FolderId(WellKnownFloderName.Calendar, "對方的Email") 取得資料夾代號,若對方未授與「可看到資料夾」權限,程式會在 FindAppointments 時噴出找不到資料夾的錯誤。

private static void QuerySharedCalender()
{
    var ewsUrl = "https://the-exchange-server/ews/Exchange.asmx";
    ExchangeService ews = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
    ews.Credentials = new WebCredentials(userId, pwd, domainName);
    ews.Url = new Uri(ewsUrl);
    FolderId folderToAccess = 
            new FolderId(WellKnownFolderName.Calendar, "someone@company.com");
    //指定日期區間與資料筆數
    var view = new CalendarView(
        new DateTime(2017, 12, 10),
        new DateTime(2017, 12, 17), 
        1024);
    view.PropertySet = new PropertySet(
                AppointmentSchema.Subject, 
                AppointmentSchema.Start, 
                AppointmentSchema.End);
    FindItemsResults<Appointment> apps = ews.FindAppointments(folderToAccess, view);
    foreach (var app in apps)
    {
        Console.WriteLine(
            $"{app.Start:MM-dd HH:mm} - {app.End:MM-dd HH:mm} {app.Subject}");
    }
}

假設行事曆如下:

測試成功!


Comments

Be the first to post a comment

Post a comment


80 - 35 =