如何使用Visual Studio在桌面程序中調用Microsoft Graph

到了春暖花開的四月了,又要開始努力成長了。雖然口罩還沒摘下,我們堅信疫情會過去,一切都會好起來的。
許久不寫,介紹一篇“磨刀”文。

本篇講述如何使用Visual Studio在桌面程序中調用Microsoft Graph,調用方式爲簡單易學的SDK方式,以C#爲例。

首先你需要在Microsoft Identity平臺註冊一個應用程序,這個之前說過幾遍就不再贅述了,忘了的點這裏

在Visual Studio中新建一個控制檯應用,然後執行如下命令安裝所需的NuGet包。控制檯程序可以用來寫一些定期跑的任務或者是無人值守進程這種東西。

Install-Package Microsoft.Graph
Install-Package Microsoft.Graph.Auth -IncludePrerelease
Install-Package Microsoft.Extensions.Configuration.Json

前兩個是調用Graph所需的東西,後面的一個是解析Json用的。

以SDK方式調用Graph的概要流程爲通過我們註冊的應用程序的信息去構建GraphServiceClient對象,然後通過這個client去請求我們要獲取的信息。

首先創建一個Json文件用來存儲應用程序信息,例如appsettings.json,示例內容如下:

{
  "tenantId": "<your tenent id>",
  "applicationId": "<your client id>"
}

本示例需用戶手動輸入憑據信息,所以只需要tenant id和client id就可以了。

創建一個認證提供程序類MsalAuthenticationProvider,用於處理用戶憑據認證等相關工作。

using System.Net.Http;
using System.Net.Http.Headers;
using System.Security;
using System.Threading.Tasks;
using Microsoft.Identity.Client;
using Microsoft.Graph;

namespace MSGraphPractice
{
    public class MsalAuthenticationProvider : IAuthenticationProvider
    {
        private static MsalAuthenticationProvider _singleton;
        private IPublicClientApplication _clientApplication;
        private string[] _scopes;
        private string _username;
        private SecureString _password;
        private string _userId;

        private MsalAuthenticationProvider(IPublicClientApplication clientApplication, string[] scopes, string username, SecureString password)
        {
            _clientApplication = clientApplication;
            _scopes = scopes;
            _username = username;
            _password = password;
            _userId = null;
        }

        public static MsalAuthenticationProvider GetInstance(IPublicClientApplication clientApplication, string[] scopes, string username, SecureString password)
        {
            if (_singleton == null)
            {
                _singleton = new MsalAuthenticationProvider(clientApplication, scopes, username, password);
            }

            return _singleton;
        }

        public async Task AuthenticateRequestAsync(HttpRequestMessage request)
        {
            var accessToken = await GetTokenAsync();

            request.Headers.Authorization = new AuthenticationHeaderValue("bearer", accessToken);
        }

        public async Task<string> GetTokenAsync()
        {
            if (!string.IsNullOrEmpty(_userId))
            {
                try
                {
                    var account = await _clientApplication.GetAccountAsync(_userId);

                    if (account != null)
                    {
                        var silentResult = await _clientApplication.AcquireTokenSilent(_scopes, account).ExecuteAsync();
                        return silentResult.AccessToken;
                    }
                }
                catch (MsalUiRequiredException) { }
            }

            var result = await _clientApplication.AcquireTokenByUsernamePassword(_scopes, _username, _password).ExecuteAsync();
            _userId = result.Account.HomeAccountId.Identifier;
            return result.AccessToken;
        }
    }
}

在Program.cs文件中,加入以下方法。

private static IConfigurationRoot LoadAppSettings()
        {
            try
            {
                var config = new ConfigurationBuilder()
                .SetBasePath(System.IO.Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json", false, true)
                .Build();

                if (string.IsNullOrEmpty(config["applicationId"]) ||
                string.IsNullOrEmpty(config["tenantId"]))
                {
                    return null;
                }
                return config;
            }
            catch (System.IO.FileNotFoundException)
            {
                return null;
            }
        }

        private static IAuthenticationProvider CreateAuthorizationProvider(IConfigurationRoot config, string userName, SecureString userPassword)
        {
            var clientId = config["applicationId"];
            var authority = $"https://login.microsoftonline.com/{config["tenantId"]}/v2.0";

            List<string> scopes = new List<string>();
            scopes.Add("User.Read");
            scopes.Add("Files.Read");

            var cca = PublicClientApplicationBuilder.Create(clientId)
                                                    .WithAuthority(authority)
                                                    .Build();
            return MsalAuthenticationProvider.GetInstance(cca, scopes.ToArray(), userName, userPassword);
        }

        private static GraphServiceClient GetAuthenticatedGraphClient(IConfigurationRoot config, string userName, SecureString userPassword)
        {
            var authenticationProvider = CreateAuthorizationProvider(config, userName, userPassword);
            var graphClient = new GraphServiceClient(authenticationProvider);
            return graphClient;
        }

        private static SecureString ReadPassword()
        {
            Console.WriteLine("Enter your password");
            SecureString password = new SecureString();
            while (true)
            {
                ConsoleKeyInfo c = Console.ReadKey(true);
                if (c.Key == ConsoleKey.Enter)
                {
                    break;
                }
                password.AppendChar(c.KeyChar);
                Console.Write("*");
            }
            Console.WriteLine();
            return password;
        }

        private static string ReadUsername()
        {
            string username;
            Console.WriteLine("Enter your username");
            username = Console.ReadLine();
            return username;
        }

並在Main方法中使用以下代碼進行調用。

var config = LoadAppSettings();
            if (config == null)
            {
                Console.WriteLine("Invalid appsettings.json file.");
                return;
            }
            var userName = ReadUsername();
            var userPassword = ReadPassword();

            var client = GetAuthenticatedGraphClient(config, userName, userPassword);

            //your request code
            var request = client.Me.Request();
            var result = request.GetAsync().Result;
            Console.WriteLine(result.DisplayName);

            Console.ReadKey();

具體要執行什麼就要視具體的需要而定了,但基本方式都是類似這樣的。
上面涵蓋了全部的代碼,照着操作就能用,本來想傳到git上但是一直報錯弄不上去,算了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章