[ Office 365 開發系列 ] Graph Service

任澤華Ryan發表於2016-05-19

前言

本文完全原創,轉載請說明出處,希望對大家有用。

通過[ Office 365 開發系列 ] 開發模式分析[ Office 365 開發系列 ] 身份認證兩篇內容的瞭解,我們可以開始使用Office 365提供的各項介面開發應用了,接下來會對其提供的主要介面一一分析並通過示例程式碼為大家講解介面功能。

閱讀目錄

  1. Graph API介紹
  2. Graph API功能
  3. 示例分析

正文

Graph API介紹

最近Office 365釋出了一項新的功能Delve,此項功能為使用者提供了基於人員資訊及搜尋的發現,有點拗口,其實就是使用Graph API提供的一些列介面,如當前所處的組織、正在處理的文件以及與我相關的事件等等內容,讓使用者更快的發現與自己相關的內容。Office 365提供這樣一個API集合有什麼用呢,我們直接使用郵件、檔案、AAD的介面也一樣可以實現這些內容,事實上我們的確可以這麼做,而Graph API是對這些更下層的API進行了封裝,讓我們不需要再深入瞭解每一項內容如何儲存、如何獲取,只需要關注業務本身的需求。下圖是Graph API官方的結構圖,我借用一下:

從上圖所示的內容,我們可以發現Graph API是Office 365作為統一介面為我們提供服務訪問的(主頁中說:One endpoint to rule them all),我們可以不用瞭解Users資訊是存放在哪裡,Graph會幫你找到,我們可以不用瞭解如何從Outlook中獲取郵件,Graph提供現成介面。這麼一看,果然功能強大,不過值得注意的是,Graph API介面不是全能的,目前來說還是有一些限制,如對SharePoint Online的操作只侷限於個人OneDrive站點。目前最新的版本的1.0,未來Graph API應該會增加更多功能。


Graph API功能

在我們使用者API前,先對API使用方法及提供的內容做一個簡要的介紹。

在上一節[ Office 365 開發系列 ] 身份認證中我們講解了如何獲取資源Token,本節我們具體到使用Graph API,值得注意的是使用Graph API所用的終結點有國外版和中國版(21v運營)的區別,具體區別如下:

終結點

國際版Office 365

21Vianet Office 365

Azure AD終結點

https://login.microsoftonline.com

https://login.chinacloudapi.cn

Graph資源終結點

https://graph.microsoft.com

https://microsoftgraph.chinacloudapi.cn

Graph API是以Rest服務的方式提供,我們可以使用兩種方式呼叫API,一種是使用JS AJAX方式呼叫API介面並將token包含在Authorization頭中,另外一種是通過微軟提供的Graph服務類來獲取和解析資料。具體的呼叫方法我們在下面的Graph API示例分析中來分析,先來了解Graph目前能為我們提供什麼。

目前Graph有兩個版本(1.0/beta),區別在於我們呼叫時注意資源地址,API結構為

 https://graph.microsoft.com/{version}/{resource}?[odata_query_parameters]

對於Graph所提供的資源內容,請參閱官方文件


Graph API應用示例

為了更好的瞭解如何呼叫Graph API,我們以獲取使用者郵件為例,分別以AJAX和呼叫Graph服務類方式實現。

一、 使用Ajax呼叫Graph API

呼叫由一個html+js實現,如下所示:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Graph API Demo</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
</head>
<body role="document">
    <table class="table table-striped table-bordered table-condensed table-hover">
        <thead>
            <tr>
                <th>接收時間</th>
                <th>郵件主題</th>
            </tr>
        </thead>
        <tbody class="data-container">
            <tr>
                <td class="view-data-type"></td>
                <td class="view-data-name"></td>
            </tr>
        </tbody>
    </table>
  
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
    <script src="https://secure.aadcdn.microsoftonline-p.com/lib/1.0.0/js/adal.js"></script>
    <script src="App/Scripts/demo.js"></script>
</body>
</html>
(function () {
    var baseEndpoint = 'https://graph.microsoft.com';
    window.config = {
        tenant:  'bluepoint360.onmicrosoft.com',
        clientId: '08d87e99-f2dd-4b4d-b402-bcf7a5ea43ca',
        postLogoutRedirectUri: window.location.origin,
        cacheLocation: 'localStorage', // enable this for IE, as sessionStorage does not work for localhost.
    };
    var authContext = new AuthenticationContext(config);
    var $dataContainer = $(".data-container");
    authContext.acquireToken(baseEndpoint, function (error, token) {
        if (error || !token) {
            console.log('ADAL error occurred: ' + error);
            return;
        }

        $.ajax({
            type: "GET",
            url: baseEndpoint + "/v1.0/me/messages",
            headers: {
                'Authorization': 'Bearer ' + token,
            }
        }).done(function (response) {
            var $template = $(".data-container");
            var output = '';
            response.value.forEach(function (item) {
                var $entry = $template;
                $entry.find(".view-data-type").html(item.receivedDateTime);
                $entry.find(".view-data-name").html(item.subject);
                output += $entry.html();
            });
            $dataContainer.html(output);
        });
    });
}());
demo.js

OK,只要這兩段程式碼就可以了,首先要執行起來,如果不知道如何註冊應用到AAD,請參考[ Office 365 開發系列 ] 身份認證

上述程式碼的邏輯是通過呼叫graph api中的messages資源,獲取使用者郵件資訊。

二、 使用Graph服務類呼叫

如果我們使用後臺服務的方式為使用者提供服務,則需要使用HttpWebRequest來發起rest請求,如果每個都由自己處理當然是可以,不過微軟已經為我們提供了呼叫封裝,那還是省點時間去做業務邏輯吧。

以MVC為例,我們為使用者提供一個獲取個人郵件的方法,示例程式碼基於Office Dev Center建立:

@model List<Tuple<string,string>>
<table class="table">
    <tr>
        <th>接收時間</th>
        <th>郵件主題</th>
    </tr>
    @foreach (var item in Model)
    {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Item1)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Item2)
            </td>
        </tr>
    }
</table>
顯示頁面
 public class DefaultController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }

        public async Task<ActionResult> RetrieveUserEmails()
        {

            List<Tuple<string, string>> mailResults = new List<Tuple<string, string>>();
            try
            {
                GraphServiceClient exClient = new GraphServiceClient(new GraphAuthentication());
                QueryOption topcount = new QueryOption("$top", "10");
                var _Results = await exClient.Me.Messages.Request(new[] { topcount }).GetAsync();

                var mails = _Results.CurrentPage;
                foreach (var mail in mails)
                {
                    mailResults.Add(new Tuple<string, string>(mail.ReceivedDateTime.ToString(), mail.Subject));
                }
            }
            catch (Exception ex)
            {
                return View(ex.Message);
            }
            return View(mailResults);
        }
    }

    public class GraphAuthentication : IAuthenticationProvider
    {

        public async Task AuthenticateRequestAsync(System.Net.Http.HttpRequestMessage request)
        {
            AuthenticationResult authResult = null;
            var signInUserId = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;
            var userObjectId = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
            var tenantId = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
            AuthenticationContext authContext = new AuthenticationContext(string.Format("{0}/{1}", "https://login.microsoftonline.com", tenantId), new ADALTokenCache(signInUserId));
            try
            {

                authResult = await authContext.AcquireTokenSilentAsync("https://graph.microsoft.com", new ClientCredential("your client ID", "your client secret"), new UserIdentifier(userObjectId, UserIdentifierType.UniqueId));
                request.Headers.Add("Authorization", "Bearer " + authResult.AccessToken);
            }
            catch (AdalException ex)
            {
                if (ex.ErrorCode == AdalError.FailedToAcquireTokenSilently)
                {
                   authContext.TokenCache.Clear();
                }
            }
        }
    }
MVC Controller

這裡要注意,使用GraphServiceClient需要引用Microsoft.Graph程式集。


結束語

以上為Graph API的介紹,請繼續關注後續部落格。

 

相關文章