简体   繁体   中英

Add Outlook 365 Calendar Events Without Logging In Multiple Times C#

This is a continuation of a previous question: How To Add Calendar Events to Outlook 365 Using C# MSGraph Thanks to user Seiya Su for their help so far.

I'm trying to use Microsoft.Graph inside a Visual Studio C# Windows Form App to add in some additional functionality to Outlook 365. This is my first application being built with Microsoft.Graph, and I have had a hard time finding documentation for its C# integration, so please forgive my lack of knowledge.

Mainly, I want to be able to add several preset Calendar Events who's details are built in the Windows Form, in bulk from a single button press, the issue I'm running into is that whenever I call my SetAppointment() or graphTesting() method I have to log in for every action done. When I'm trying to add 60+ Events to the calendar, having to log in again for every time we want to add a single event is unacceptable. Does anyone have any idea how to accomplish this? I'm okay with the user having to log in, as long as they only have to do it at the start of program execution.

using Microsoft.Graph;
using Microsoft.Identity.Client;
using System.Configuration;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Collections.Generic;

namespace WindowsFormsApp
{
    class MSGraph
    {
        PublicClientApplication clientApp;
        GraphServiceClient graphClient;

        public async void Start()
        {
            await GetDataAsync();
            return;
        }

        // Starts the login process
        async Task GetDataAsync()
        {
            clientApp = new PublicClientApplication(ConfigurationManager.AppSettings["ClientId"].ToString());

            graphClient = new GraphServiceClient(
                    "https://graph.microsoft.com/v1.0",
                    new DelegateAuthenticationProvider(
                        async (requestMessage) =>
                        {
                            requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", await GetTokenAsync(clientApp));
                        }));

            userEmail = currentUser.ToString();
            return;
    }


    // Fetches Access Token
    async Task<string> GetTokenAsync(PublicClientApplication clientApp)
    {
        //need to pass scope of activity to get token
        string[] Scopes = { "User.ReadWrite.All", "Calendars.ReadWrite", "Calendars.ReadWrite.Shared" };
        token = null;

        AuthenticationResult authResult = await clientApp.AcquireTokenAsync(Scopes).ConfigureAwait(false);
        token = authResult.AccessToken;

        return token;
    }

    // Testing out MSGraph
    public async void graphTesting()
            { 
        var myEvent = new Microsoft.Graph.Event();
        myEvent.Subject = "Test";
        myEvent.Body = new ItemBody() { ContentType = BodyType.Text, Content = "This is test." };
        myEvent.Start = new DateTimeTimeZone() { DateTime = "2018-10-3T12:00:00", TimeZone = "Pacific Standard Time" };
        myEvent.End = new DateTimeTimeZone() { DateTime = "2018-10-3T13:00:00", TimeZone = "Pacific Standard Time" };
        myEvent.Location = new Location() { DisplayName = "conf room 1" };



        var myEvent2 = new Microsoft.Graph.Event();
        myEvent2.Subject = "Test";
        myEvent2.Body = new ItemBody() { ContentType = BodyType.Text, Content = "This is test." };
        myEvent2.Start = new DateTimeTimeZone() { DateTime = "2018-10-4T12:00:00", TimeZone = "Pacific Standard Time" };
        myEvent2.End = new DateTimeTimeZone() { DateTime = "2018-10-4T13:00:00", TimeZone = "Pacific Standard Time" };
        myEvent2.Location = new Location() { DisplayName = "conf room 1" };    


        // Create the event.
        var user = graphClient.Users["myEmail"].Calendar.Events.Request();
        await user.AddAsync(myEvent);
        await user.AddAsync(myEvent2);


    }



    // Adds Events to the Calendar
    public async void SetAppointment(string Subject, string Body, string Start, string End, string Location, List<string> attendees) 
    {
        var myEvent = new Microsoft.Graph.Event();
        myEvent.Subject = Subject;
        myEvent.Body = new ItemBody() { ContentType = BodyType.Text, Content = Body };
        myEvent.Start = new DateTimeTimeZone() { DateTime = Start, TimeZone = "" };
        myEvent.End = new DateTimeTimeZone() { DateTime = End, TimeZone = "" };
        myEvent.Location = new Location() { DisplayName = Location };

        var appointment = await graphClient.Me.Calendar.Events.Request().AddAsync(myEvent);          

    }

}

}

Where do you register your app: azure app or MSAL app ? In most case, we can use AcquireTokenSilentAsync method from Microsoft.Identity.Client but not the AcquireTokenAsync from Microsoft.Identity.Client.ActiveDirectory to get the Token.

A issue in your code is the cause, you don't have token cache . So you request new token for every request(login in again), get start from Graph Official docs to learn how to cache token, due to you use WinForm, so you can reference the UWP demo(I have create the WinForm project and add my code below). You can implement the TokenCache logic by foloowing MVC get started code .

For testing, you can just use the follow code from mine: Create a class and name it to AuthenticationHelper :

   public class AuthenticationHelper
    {
        // The Client ID is used by the application to uniquely identify itself to the v2.0 authentication endpoint.
        static string clientId = ConfigurationManager.AppSettings["AppId"].ToString();
        public static string[] Scopes = { "Calendars.ReadWrite", "User.Read", "Mail.Send", "Files.ReadWrite" };        

        public static PublicClientApplication IdentityClientApp = new PublicClientApplication(clientId);

        public static string TokenForUser = null;
        public static DateTimeOffset Expiration;

        private static GraphServiceClient graphClient = null;      

        // Get an access token for the given context and resourceId. An attempt is first made to 
        // acquire the token silently. If that fails, then we try to acquire the token by prompting the user.
        public static GraphServiceClient GetAuthenticatedClient()
        {
            if (graphClient == null)
            {
                // Create Microsoft Graph client.
                try
                {
                    graphClient = new GraphServiceClient(
                        "https://graph.microsoft.com/v1.0",
                        new DelegateAuthenticationProvider(
                            async (requestMessage) =>
                            {
                                var token = await GetTokenForUserAsync();
                                requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", token);
                                // This header has been added to identify our sample in the Microsoft Graph service.  If extracting this code for your project please remove.
                                //requestMessage.Headers.Add("SampleID", "uwp-csharp-connect-sample");

                            }));
                    return graphClient;
                }

                catch (Exception ex)
                {
                    Debug.WriteLine("Could not create a graph client: " + ex.Message);
                }
            }

            return graphClient;
        }


        /// <summary>
        /// Get Token for User.
        /// </summary>
        /// <returns>Token for user.</returns>
        public static async Task<string> GetTokenForUserAsync()
        {
            AuthenticationResult authResult;
            try
            {
                //need to pass scope of activity to get token
                if (TokenForUser == null)
                {
                    authResult = await IdentityClientApp.AcquireTokenSilentAsync(Scopes, IdentityClientApp.Users.First());
                    TokenForUser = authResult.AccessToken;
                }
                return TokenForUser;
            }

            catch (Exception ex)
            {
                if (TokenForUser == null || Expiration <= DateTimeOffset.UtcNow.AddMinutes(5))
                {
                    authResult = await IdentityClientApp.AcquireTokenAsync(Scopes);

                    TokenForUser = authResult.AccessToken;
                    Expiration = authResult.ExpiresOn;
                }
            }

            return TokenForUser;
        }
        /// <summary>
        /// Signs the user out of the service.
        /// </summary>
        public static void SignOut()
        {
            foreach (var user in IdentityClientApp.Users)
            {
                IdentityClientApp.Remove(user);
            }
            graphClient = null;
            TokenForUser = null;

        }

    }

In your form.cs class:

public partial class Form1 : Form
    { 
        public Form1()
        {
            InitializeComponent(); 
        }

        /// <summary>
        /// Register event button.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            graphTesting();
        } 

        // Testing out MSGraph
        public async void graphTesting()
        { 
            // Initialize the GraphServiceClient.
            // GraphServiceClient graphClient = Microsoft_Graph_SDK_ASPNET_Connect.Helpers.SDKHelper.GetAuthenticatedClient();
            var graphClient = AuthenticationHelper.GetAuthenticatedClient();

            var myEvent = new Microsoft.Graph.Event();
            myEvent.Subject = "Test";
            myEvent.Body = new ItemBody() { ContentType = BodyType.Text, Content = "This is test." };
            myEvent.Start = new DateTimeTimeZone() { DateTime = "2018-10-3T12:00:00", TimeZone = "Pacific Standard Time" };
            myEvent.End = new DateTimeTimeZone() { DateTime = "2018-10-3T13:00:00", TimeZone = "Pacific Standard Time" };
            myEvent.Location = new Location() { DisplayName = "conf room 1" };

            var myEvent2 = new Microsoft.Graph.Event();
            myEvent2.Subject = "Test";
            myEvent2.Body = new ItemBody() { ContentType = BodyType.Text, Content = "This is test." };
            myEvent2.Start = new DateTimeTimeZone() { DateTime = "2018-10-4T12:00:00", TimeZone = "Pacific Standard Time" };
            myEvent2.End = new DateTimeTimeZone() { DateTime = "2018-10-4T13:00:00", TimeZone = "Pacific Standard Time" };
            myEvent2.Location = new Location() { DisplayName = "conf room 1" };


            // Create the event.
            //var user = graphClient.Users["test@test.onmicrosoft.com"].Calendar.Events.Request();
            await graphClient.Users["test@test.onmicrosoft.com"].Calendar.Events.Request().AddAsync(myEvent);
            await graphClient.Users["test@test.onmicrosoft.com"].Calendar.Events.Request().AddAsync(myEvent2);
            await graphClient.Users["test@test.onmicrosoft.com"].Calendar.Events.Request().AddAsync(myEvent);
            await graphClient.Users["test@test.onmicrosoft.com"].Calendar.Events.Request().AddAsync(myEvent2);

        }



        /// <summary>
        /// Sign in button.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void button2_Click(object sender, EventArgs e)
        { 
            if (await SignInCurrentUserAsync())
            {

            }           
        }

        public async Task<bool> SignInCurrentUserAsync()
        {
            try
            {
                var graphClient = AuthenticationHelper.GetAuthenticatedClient();

                if (graphClient != null)
                {
                    var user = await graphClient.Me.Request().GetAsync();
                    string userId = user.Id;

                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Microsoft.Identity.Client.MsalException)
            {
                return false;
            }


        }

    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM