簡體   English   中英

將Microsoft.Graph與控制台應用程序一起使用

[英]Using Microsoft.Graph with a Console application

我正在嘗試復制將Outlook.COM與控制台應用程序一起使用的Microsoft示例。 因此,我創建了一個C#控制台應用程序並添加了所需的軟件包:

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Microsoft.Graph" version="1.5.1" targetFramework="net461" />
  <package id="Microsoft.Graph.Core" version="1.6.1" targetFramework="net461" />
  <package id="Microsoft.Identity.Client" version="1.1.0-preview" targetFramework="net461" />
  <package id="Newtonsoft.Json" version="6.0.1" targetFramework="net461" />
  <package id="System.Net.Http" version="4.3.1" targetFramework="net461" />
  <package id="System.Security.Cryptography.Algorithms" version="4.3.0" targetFramework="net461" />
  <package id="System.Security.Cryptography.Encoding" version="4.3.0" targetFramework="net461" />
  <package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net461" />
  <package id="System.Security.Cryptography.X509Certificates" version="4.3.0" targetFramework="net461" />
</packages>

我修改了我的主控制台類:

using System;
using Microsoft.Identity.Client;

namespace OutlookCalIFConsole
{
    class Program
    {
        //Below is the clientId of your app registration. 
        //You have to replace the below with the Application Id for your app registration
        private static string ClientId = "xxxxx";

        public static PublicClientApplication PublicClientApp = new PublicClientApplication(ClientId);

        static void Main(string[] args)
        {
            Outlook oOutlook = new Outlook();

            oOutlook.AquireToken();
            if (oOutlook.ResultsText != "")
                Console.WriteLine(oOutlook.ResultsText);
        }
    }
}

我創建了Outlook類:

using Microsoft.Identity.Client;
using System;
using System.Linq;
using System.Threading.Tasks;

namespace OutlookCalIFConsole
{
    class Outlook
    {

        //Set the API Endpoint to Graph 'me' endpoint
        string _graphAPIEndpoint = "https://graph.microsoft.com/v1.0/me";

        //Set the scope for API call to user.read
        string[] _scopes = new string[] { "user.read" };

        public string ResultsText { get { return strResultsText; } }
        string strResultsText = "";

        public async void AquireToken()
        {
            AuthenticationResult authResult = null;

            try
            {
                if (authResult == null)
                {
                    authResult = await Program.PublicClientApp.AcquireTokenSilentAsync(_scopes, Program.PublicClientApp.Users.FirstOrDefault());
                }
            }
            catch (MsalUiRequiredException ex)
            {
                // A MsalUiRequiredException happened on AcquireTokenSilentAsync. This indicates you need to call AcquireTokenAsync to acquire a token
                System.Diagnostics.Debug.WriteLine($"MsalUiRequiredException: {ex.Message}");

                try
                {
                    authResult = await Program.PublicClientApp.AcquireTokenAsync(_scopes);
                }
                catch (MsalException msalex)
                {
                    strResultsText = $"Error Acquiring Token:{System.Environment.NewLine}{msalex}";
                }
            }
            catch (Exception ex)
            {
                strResultsText = $"Error Acquiring Token Silently:{System.Environment.NewLine}{ex}";
                return;
            }

            if (authResult != null)
            {
                strResultsText = await GetHttpContentWithToken(_graphAPIEndpoint, authResult.AccessToken);
                Console.WriteLine(strResultsText);

                DisplayBasicTokenInfo(authResult);

                SignOut();
                if (strResultsText != "")
                    Console.WriteLine(strResultsText);
            }
        }

        /// <summary>
        /// Perform an HTTP GET request to a URL using an HTTP Authorization header
        /// </summary>
        /// <param name="url">The URL</param>
        /// <param name="token">The token</param>
        /// <returns>String containing the results of the GET operation</returns>
        public async Task<string> GetHttpContentWithToken(string url, string token)
        {
            var httpClient = new System.Net.Http.HttpClient();
            System.Net.Http.HttpResponseMessage response;
            try
            {
                var request = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, url);
                //Add the token in Authorization header
                request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
                response = await httpClient.SendAsync(request);
                var content = await response.Content.ReadAsStringAsync();
                return content;
            }
            catch (Exception ex)
            {
                return ex.ToString();
            }
        }

        private void DisplayBasicTokenInfo(AuthenticationResult authResult)
        {
            string strTokenInfoText = "";
            if (authResult != null)
            {
                strTokenInfoText += $"Name: {authResult.User.Name}" + Environment.NewLine;
                strTokenInfoText += $"Username: {authResult.User.DisplayableId}" + Environment.NewLine;
                strTokenInfoText += $"Token Expires: {authResult.ExpiresOn.ToLocalTime()}" + Environment.NewLine;
                strTokenInfoText += $"Access Token: {authResult.AccessToken}" + Environment.NewLine;
                Console.WriteLine(strTokenInfoText);
            }
        }

        public void SignOut()
        {
            strResultsText = "";
            if (Program.PublicClientApp.Users.Any())
            {
                try
                {
                    Program.PublicClientApp.Remove(Program.PublicClientApp.Users.FirstOrDefault());
                    Console.WriteLine("User has signed-out");
                }
                catch (MsalException ex)
                {
                    strResultsText = $"Error signing-out user: {ex.Message}";
                }
            }
        }
    }
}

以上是基於WPF的示例。 我只是修改了它,因為我認為對於控制台應用程序來說還可以。 但是當我運行它時,我得到一個例外:

拋出的異常:Microsoft.Identity.Client.dll中的“ Microsoft.Identity.Client.MsalUiRequiredException”拋出的異常:mscorlib.dll中的“ Microsoft.Identity.Client.MsalUiRequiredException”拋出的異常:mscorlib中的“ Microsoft.Identity.Client.MsalUiRequiredException” .DLL

我已經閱讀了MsalUiRequiredException ,可以理解的是:

該異常類用於通知開發人員,成功進行身份驗證需要UI交互。

那么,我到底該如何工作呢? 我認為它將顯示一個瀏覽器控件,其中包含與用戶進行交互所需的資源。

我無法弄清楚如何使其能夠工作以進行身份​​驗證。 根據代碼,一切都可以。

更新

我嘗試更改:

static void Main(string[] args)
{
    Outlook oOutlook = new Outlook();

    new Task(oOutlook.AquireToken).Start();

    if (oOutlook.ResultsText != "")
        Console.WriteLine(oOutlook.ResultsText);
}

沒有區別。

問題在於, AquireToken()被標記為async void ,除非它是事件處理程序,否則應避免使用。 由於調用async void方法而無法捕獲異常。

另外,由於您不必等待創建的任務,因此完全有可能在任務完成之前退出您的應用。

解決此問題的一種方法是讓主應用創建一個Task然后等待其完成。 Main不能async因此您需要顯式阻止任務,而不是使用await

static void Main(string[] args)
{
    var program = new Program();
    var task = Task.Run(program.Run);
    task.Wait();
}

...然后將此新方法添加到Program

private async Task Run()
{
    Outlook oOutlook = new Outlook();
    await oOutlook.AquireToken();
    if (oOutlook.ResultsText != "")
        Console.WriteLine(oOutlook.ResultsText);
}

從以下位置更改AquireToken簽名:

public async void AquireToken()

...至:

public async Task AquireToken()  

現在,當您運行控制台應用程序時,您將看到登錄窗口。 在這里,您可以看到它已經在獲取我的緩存帳戶名:

在此處輸入圖片說明

告訴我更多有關異步/等待的信息

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM