使用 C#/.NET 在 G 日历中创建事件的最简单方法是什么

What is the simplest way to create event in G calendar using C# / .NET

!我在下面添加的解决方案 ! 问题: 我正在使用 c#/.NET 构建一个 windows 表单,我想添加一个功能来在我的个人 google 日历中添加一个事件。我已经在互联网上研究了几天,但我发现的每一个解决方案似乎都过于复杂。

我只需要:

event title = textbox1.text;
event description = textbox2.text;
event date = datetimepicker.text;
addEvent();

但我不知道怎么写,也找不到任何如此简单的解决方案(大多数解决方案过于复杂)。我可以说我有一些爱好编码经验,足以构建一个简单的项目,但我承认这超出了我的水平,我需要一些指导。

我想我已经设置了日历 API 和 Google SDK。还在 Visual Studio 中安装了 Google Calendars NuGet 包,但如果有办法通过密码和用户名而不是 API & SDK 建立连接,我将不胜感激。

提前致谢!

!解决方案 !

在@Dalmto 的最初帮助下,我设法link他的代码到一个按钮并实际让它触发一个事件,因为以前它没有。

这是我的最终代码,您可以将其简单地用作复制粘贴。只需添加您的凭据。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Calendar.v3;
using Google.Apis.Services;
using Google.Apis.Util.Store;
using System.IO;
using System.Threading;
using Google.Apis.Calendar.v3.Data;


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

        private void button1_Click(object sender, EventArgs e)
        {
            string clientSecretJson = ""; //add your json path here
            string userName = ""; // add your google account here
            string[] scopes = new string[n] {"n1", "n2", "n3" }; // replace n with the number of scopes you need and write them one by one
            CalendarService service = GetCalendarService(clientSecretJson, userName, scopes);

            Event newEvent = new Event()
            {
                Summary = "event title",
                Description = "event description",
                Start = new EventDateTime()
                {
                    DateTime = DateTime.Parse("2022-02-28T09:00:00-07:00"),
                    TimeZone = "America/Los_Angeles",
                },
                End = new EventDateTime()
                {
                    DateTime = DateTime.Parse("2022-02-28T09:00:00-08:00"),
                    TimeZone = "America/Los_Angeles",
                },
            }; //// more options here https://developers.google.com/calendar/api/v3/reference/events/insert#.net

            String calendarId = "primary"; // choose a calendar in your google account - you might have multiple calendars
            EventsResource.InsertRequest request = service.Events.Insert(newEvent, calendarId);
            Event createdEvent = request.Execute();
        }
        public static CalendarService GetCalendarService(string clientSecretJson, string userName, string[] scopes)
        {
            try
            {
                if (string.IsNullOrEmpty(userName))
                    throw new ArgumentNullException("userName");
                if (string.IsNullOrEmpty(clientSecretJson))
                    throw new ArgumentNullException("clientSecretJson");
                if (!File.Exists(clientSecretJson))
                    throw new Exception("clientSecretJson file does not exist.");

                var cred = GetUserCredential(clientSecretJson, userName, scopes);
                return GetService(cred);

            }
            catch (Exception ex)
            {
                throw new Exception("Get Calendar service failed.", ex);
            }
        }

        private static UserCredential GetUserCredential(string clientSecretJson, string userName, string[] scopes)
        {
            try
            {
                if (string.IsNullOrEmpty(userName))
                    throw new ArgumentNullException("userName");
                if (string.IsNullOrEmpty(clientSecretJson))
                    throw new ArgumentNullException("clientSecretJson");
                if (!File.Exists(clientSecretJson))
                    throw new Exception("clientSecretJson file does not exist.");

                // These are the scopes of permissions you need. It is best to request only what you need and not all of them               
                using (var stream = new FileStream(clientSecretJson, FileMode.Open, FileAccess.Read))
                {
                    string credPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
                    credPath = Path.Combine(credPath, ".credentials/", System.Reflection.Assembly.GetExecutingAssembly().GetName().Name);

                    // Requesting Authentication or loading previously stored authentication for userName
                    var credential = GoogleWebAuthorizationBroker.AuthorizeAsync(GoogleClientSecrets.Load(stream).Secrets,
                                                                             scopes,
                                                                             userName,
                                                                             CancellationToken.None,
                                                                             new FileDataStore(credPath, true)).Result;

                    credential.GetAccessTokenForRequestAsync();
                    return credential;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Get user credentials failed.", ex);
            }
        }

       private static CalendarService GetService(UserCredential credential)
        {
            try
            {
                if (credential == null)
                    throw new ArgumentNullException("credential");

                // Create Calendar API service.
                return new CalendarService(new BaseClientService.Initializer()
                {
                    HttpClientInitializer = credential,
                    ApplicationName = "Calendar Oauth2 Authentication Sample"
                });
            }
            catch (Exception ex)
            {
                throw new Exception("Get Calendar service failed.", ex);
            }
        }
    }
}

我在项目中使用的范围:

https://www.googleapis.com/auth/calendar,  
https://www.googleapis.com/auth/calendar.events,
https://www.googleapis.com/auth/calendar.events.readonly  

您需要 Google 开发人员仪表板 (https://console.developers.google.com/apis/dashboard?pli=1) 中的 API 密钥才能连接到您的日历并在日历中读取或写入事件。普通的用户名和密码将不起作用(据我所知)。 Google 的文档非常简单明了,解释了从 API 检索事件的每个步骤。 https://developers.google.com/calendar/api/quickstart/dotnet

了解 SDK 后,您可以增强您的应用程序以将事件添加到您的日历中。 如果我有时间,我会 link 我的 GitHub 回购协议中的一个例子,你可以参考。

编辑:正如 DalmTo 提到的,我没有创建 API 密钥。我使用开发人员仪表板创建了客户端凭据。快速入门指南中也提到了如何创建这些凭据。

I will appreciate if there is way to make a connection by password and username instead of API & SDK.

不,这称为客户端登录,google在 2015 年关闭了该选项。

I want to add a functionality to add a event in my personal google calendar.

我假设个人 google 日历是指标准的 Gmail 帐户 google 日历。

为此,您需要使用 Oauth2 请求离线访问授权您的应用程序一次。之后你应该有一个刷新令牌存储。

此代码合理地向前推进

Oauth2Authentication.cs

using Google.Apis.Auth.OAuth2;
using Google.Apis.Calendar.v3;
using Google.Apis.Services;
using Google.Apis.Util.Store;
using System;
using System.IO;
using System.Threading;

namespace GoogleSamplecSharpSample.Calendarv3.Auth
{
    public static class Oauth2Example
    {
        /// <summary>
        /// ** Installed Aplication only ** 
        /// This method requests Authentcation from a user using Oauth2.  
        /// </summary>
        /// <param name="clientSecretJson">Path to the client secret json file from Google Developers console.</param>
        /// <param name="userName">Identifying string for the user who is being authentcated.</param>
        /// <param name="scopes">Array of Google scopes</param>
        /// <returns>CalendarService used to make requests against the Calendar API</returns>
        public static CalendarService GetCalendarService(string clientSecretJson, string userName, string[] scopes)
        {
            try
            {
                if (string.IsNullOrEmpty(userName))
                    throw new ArgumentNullException("userName");
                if (string.IsNullOrEmpty(clientSecretJson))
                    throw new ArgumentNullException("clientSecretJson");
                if (!File.Exists(clientSecretJson))
                    throw new Exception("clientSecretJson file does not exist.");

                var cred = GetUserCredential(clientSecretJson, userName, scopes);
                return GetService(cred);

            }
            catch (Exception ex)
            {
                throw new Exception("Get Calendar service failed.", ex);
            }
        }

        /// <summary>
        /// ** Installed Aplication only ** 
        /// This method requests Authentcation from a user using Oauth2.  
        /// Credentials are stored in System.Environment.SpecialFolder.Personal
        /// Documentation https://developers.google.com/accounts/docs/OAuth2
        /// </summary>
        /// <param name="clientSecretJson">Path to the client secret json file from Google Developers console.</param>
        /// <param name="userName">Identifying string for the user who is being authentcated.</param>
        /// <param name="scopes">Array of Google scopes</param>
        /// <returns>authencated UserCredential</returns>
        private static UserCredential GetUserCredential(string clientSecretJson, string userName, string[] scopes)
        {
            try
            {
                if (string.IsNullOrEmpty(userName))
                    throw new ArgumentNullException("userName");
                if (string.IsNullOrEmpty(clientSecretJson))
                    throw new ArgumentNullException("clientSecretJson");
                if (!File.Exists(clientSecretJson))
                    throw new Exception("clientSecretJson file does not exist.");

                // These are the scopes of permissions you need. It is best to request only what you need and not all of them               
                using (var stream = new FileStream(clientSecretJson, FileMode.Open, FileAccess.Read))
                {
                    string credPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
                    credPath = Path.Combine(credPath, ".credentials/", System.Reflection.Assembly.GetExecutingAssembly().GetName().Name);

                    // Requesting Authentication or loading previously stored authentication for userName
                    var credential = GoogleWebAuthorizationBroker.AuthorizeAsync(GoogleClientSecrets.Load(stream).Secrets,
                                                                             scopes,
                                                                             userName,
                                                                             CancellationToken.None,
                                                                             new FileDataStore(credPath, true)).Result;

                    credential.GetAccessTokenForRequestAsync();
                    return credential;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Get user credentials failed.", ex);
            }
        }

        /// <summary>
        /// This method get a valid service
        /// </summary>
        /// <param name="credential">Authecated user credentail</param>
        /// <returns>CalendarService used to make requests against the Calendar API</returns>
        private static CalendarService GetService(UserCredential credential)
        {
            try
            {
                if (credential == null)
                    throw new ArgumentNullException("credential");

                // Create Calendar API service.
                return new CalendarService(new BaseClientService.Initializer()
                {
                    HttpClientInitializer = credential,
                    ApplicationName = "Calendar Oauth2 Authentication Sample"
                });
            }
            catch (Exception ex)
            {
                throw new Exception("Get Calendar service failed.", ex);
            }
        }
    }
}

此代码会将您个人 google 日历帐户的凭据存储在计算机上 credPath 目录中的一个文件中。如果您将其存储在服务器上,您可能需要更改此目录。

当您第一次 运行 时(我建议在本地执行此操作),它将使用刷新令牌填充该文件。然后,代码将在需要时使用刷新令牌来请求新的访问令牌。

对此有几点说明。您需要在 google 云控制台中将您的项目设置为生产环境,否则您的刷新令牌只有 7 天有效。您还必须确保此刷新令牌每六个月使用一次,否则它将过期。如果无法加载刷新令牌,则此代码将失败,因为它是为已安装的应用程序设计的。这可能是一件好事,因为您不需要 Web 托管应用程序来请求用户同意他们的个人 google 日历帐户。

服务帐号备注。

大多数 google api 支持称为服务帐户身份验证的东西。它用于预授权帐户访问。 Google 日历仅支持 Google 工作区帐户的服务帐户授权,不支持标准 gmail 帐户。

如果您想使用服务帐户执行此操作会更容易,但同样您需要注册一个工作区帐户,然后您只能使用它而不是标准 gmail 帐户。