Is "Messages.PostAsync" broken in WinForms App (Sending Emails / Creating Drafts)

Micheal Pepper 20 Reputation points
2023-09-04T06:27:56.6033333+00:00

While refactoring code from "Microsoft.Graph 4.48" to the latest 5.25 (via NuGet) I was unable to send a message nor alternately create a draft message.

The code stalls at PostAsync().Wait when sending email and stalls at PostAsync().Result when creating a Draft message.

For this example, I created a new "Windows Forms App (.NET Framework)" project. Using NuGet, added the latest "Microsoft Graph" and "Azure Identity".

If I call the "SendTest()" from Program.cs, the call works.

namespace TestSendEmail
{
    internal static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Form1.SendTest();
            Application.Run(new Form1());
        }
    }
}

If I call "SendTest()" in the Form1() code, it hangs waiting for the call to complete.


        public Form1()
        {
            SendTest();
            InitializeComponent();
        }

If I interact with the UI while the "task" is waiting, then the call will work (See Simple Test 3).

public static void SendTest()
{
    var tenantId = "your-tenant-id";
    var clientId = "your-client-id";
    var clientSecret = "your-client-secret";
    var toAddress = "test@test.com.au";
    var fromAddress = "testfrom@test.com.au";



    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

    var scopes = new[] { "https://graph.microsoft.com/.default" };
    var clientSecretCredential = new ClientSecretCredential(
        tenantId, clientId, clientSecret);
    var graphClient = new GraphServiceClient(clientSecretCredential, scopes);


    Microsoft.Graph.Models.Message msg = new Microsoft.Graph.Models.Message
    {
        Subject = "Meet for lunch?",
        Body = new ItemBody
        {
            ContentType = BodyType.Text,
            Content = "The new cafeteria is open.",
        },
        ToRecipients = new List<Recipient>
        {
            new Recipient
            {
                EmailAddress = new EmailAddress
                {
                    Address = toAddress,
                },
            },
        },
    };


    //Simple Test 1
    //This sits forever waiting for the ".Wait()" 
    //var requestBody = new Microsoft.Graph.Users.Item.SendMail.SendMailPostRequestBody
    //{
    //    Message = msg,
    //};
    //graphClient.Users[fromAddress].SendMail.PostAsync(requestBody).Wait();


    //Simple Test 2
    //This sits forever waiting for the ".Result" 
    var draftMessage = graphClient.Users[fromAddress].Messages.PostAsync(msg).Result;
    System.Diagnostics.Debug.WriteLine(draftMessage.Id);

    //Simple Test 3
    //var task = graphClient.Users[fromAddress].Messages.PostAsync(msg);
    //MessageBox.Show("a message here fixes the call");
    //var draftMessage2 = task.Result;
    //System.Diagnostics.Debug.WriteLine(draftMessage2.Id);


    MessageBox.Show("success");
}
.NET
.NET
Microsoft Technologies based on the .NET software framework.
3,786 questions
Microsoft Graph
Microsoft Graph
A Microsoft programmability model that exposes REST APIs and client libraries to access data on Microsoft 365 services.
11,799 questions
{count} votes

Accepted answer
  1. Jiale Xue - MSFT 44,316 Reputation points Microsoft Vendor
    2023-09-06T06:38:41.1533333+00:00

    Hi @Micheal Pepper , Welcome to Microsoft Q&A,

    Directly using task.Result to synchronously wait for asynchronous operations may cause deadlock or block the UI thread.

    For async operations you need to use await correctly.

    For example, use: String id2 = await CreateDraftA();

    Your solution is to use: String id2 = Task.Run(async () => await CreateDraftA()).Result;


    Updated:

    A simple async method shows:

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            
            // Start the asynchronous initialization
            InitializeAsync();
        }
    
        private async void InitializeAsync()
        {
            String id1 = CreateDraftB();
            MessageBox.Show("CreateDraftB - id1: " + id1);
    
            String id2 = await CreateDraftA();
            MessageBox.Show("CreateDraftA - id2: " + id2);
        }
    
        // Rest of your form code...
    
        // Your other methods here...
    }
    

    Best Regards,

    Jiale


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment". 

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.