Search code examples
c#.net-coremicrosoft-graph-apionedrive

Authorizing OneDrive user in C# causes program to crash mysteriously


I am writing a console app with .Net Core version 3.1. The purpose is to allow a user to access Microsoft OneDrive accounts and fiddle with them as desired. Getting past the authorizing stage is proving difficult. Here is a code snippet demonstrating what I have going:

//using statements
namespace HelloOneDrive
{
    public class Program
    {
        static void Main(string[] args)
        {
            Task handleThing = (new Thing()).Handle();
        }
    }

    public class Thing
    {
        public async Task Handle()
        {
            ClientCredentialProvider credentials;
            string tenantId = //value
            string clientId = //value
            string clientSecret = //value
            AuthenticationResult authResult;
            string[] scopes = { "https://graph.microsoft.com/.default" };
            CancellationToken cancellationToken = new CancellationToken();
            GraphServiceClient client = null;

            try
            {
                credentials = new ClientCredentialProvider(ConfidentialClientApplicationBuilder
                    .Create(clientId)
                    .WithTenantId(tenantId)
                    .WithClientSecret(clientSecret)
                    .Build());
            }
            catch (Exception ex)
            {
                //[logic for handling an exception, that never gets thrown]
            }

            try
            {
                authResult = await credentials
                .ClientApplication
                .AcquireTokenForClient(scopes)
                .ExecuteAsync(cancellationToken);
            }
            catch (Exception ex)
            {
                //[logic for handling an exception, that never gets thrown]
                //The program fails silently and suddenly, rather than hit
                //this catch block.
                Console.WriteLine("hello");
            }

            if (authResult != null)
            {
                client = new GraphServiceClient(
                    new DelegateAuthenticationProvider(
                        requestMessage =>
                        {
                            requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authResult.AccessToken);
                            return Task.FromResult(0);
                        }));
            }

            if (client != null)
            {
                ...

The debugger will get to the second try-catch block, try to define authResult, and then suddenly end. No exception is caught; the program just ends.

In case it is useful, the NuGet packages I am using are:

  • Microsoft.Graph v3.21.0
  • Microsoft.Graph.Auth v1.0.0-preview.6
  • Microsoft.Graph.Core v1.23.0 (v2.0.0-preview.4)
  • Microsoft.Identity.Client v4.24.0

Help?


Solution

  • You are calling an async method from a non-async Main and not waiting for the result. Thus, your Handle() method is executed synchronously until it reaches the first async call. (authResult = await credentials...) Then the synchronous execution flow is handed back to the Main method, which has nothing else to do, so it exits. And if the Main method comes to an end, of course the whole process ends because the runtime does not wait for running Tasks to complete unless you explicitely tell it to do so.

    You could for instance Wait() for the task in the Main method

    static void Main(string[] args)
    {
      Task handleThing = (new Thing()).Handle();
      handleThing.Wait();
    }
    

    or you could make your Main async as well, and then await your Handle() Task

    static async Task Main(string[] args)
    {
      await (new Thing()).Handle();
    }