Google 日历 API v3 - 在服务器上部署时请求超时



我尝试登录本地主机,一切正常。

代码:

    public static bool LoginGoogleCalendar(string clientId, string clientSecret, string idGCalendarUser, string calendarServiceScope, string folder)
    {
        try
        {

            UserCredential credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
                                        new ClientSecrets
                                        {
                                            ClientId = clientId,
                                            ClientSecret = clientSecret,
                                        },
                                        new[] { calendarServiceScope },
                                        idGCalendarUser,
                                        CancellationToken.None, new FileDataStore(folder)).Result;
            return true;
        }
        catch (Exception ex)
        {
            Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
            return false;
        }
    }

(我正确设置了文件数据存储的授权)

在 Google 开发者控制台中:

重定向 URI:http://localhost/authorize/Javascript Origins: http://localhost:8081

我使用 Visual Studio 2013, IIS 8

当我尝试登录服务器时,将阻止整个服务器几分钟,之后的答案是:System.Web.HttpException 请求超时。

在 Google 开发者控制台中:

重定向 URI:http://pippo.pluto.it/authorize/Javascript 起源:http://pippo.pluto.it

在服务器上:IIS 7

对我示例的引用:https://developers.google.com/google-apps/calendar/instantiate

我遇到了同样的问题。互联网上的很多例子告诉你使用这个类。对于 Web 应用程序,这不是要使用的类。此类非常适合"脱机"应用程序,但是当您在IIS服务器上使用此类时,它将尝试在服务器上打开弹出窗口,但它不会允许它。

我使用的类:GoogleAuthorizationCodeFlow

using Google.Apis.Analytics.v3;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Auth.OAuth2.Flows;
using Google.Apis.Auth.OAuth2.Requests;
using Google.Apis.Auth.OAuth2.Web;
using Google.Apis.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
namespace GoogleOauth2DemoWebApp
{
    public class GoogleOauth
    {
        public AnalyticsService Handle(string _userId, string _connectionString, string _googleRedirectUri, string _applicationName, string[] _scopes)
        {
            try
            {
                string UserId = _userId;//The user ID wil be for examlpe the users gmail address.
                AnalyticsService service;
                GoogleAuthorizationCodeFlow flow;
                //use extended class to create google authorization code flow
                flow = new ForceOfflineGoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
                {
                    DataStore = new DbDataStore(_connectionString),//DataStore class to save the token in a SQL database.
                    ClientSecrets = new ClientSecrets { ClientId = "XXX-YOUR CLIENTID-XXX", ClientSecret = "XXX-YOURCLIENTSECRET-XXX" },
                    Scopes = _scopes,
                });

                var uri = HttpContext.Current.Request.Url.ToString();
                string redirecturi = _googleRedirectUri;//This is the redirect URL set in google developer console.
                var code = HttpContext.Current.Request["code"];
                if (code != null)
                {
                    var token = flow.ExchangeCodeForTokenAsync(UserId, code,
                        uri.Substring(0, uri.IndexOf("?")), CancellationToken.None).Result;
                    var test = HttpContext.Current.Request["state"];
                    // Extract the right state.
                    var oauthState = AuthWebUtility.ExtracRedirectFromState(
                         flow.DataStore, UserId, HttpContext.Current.Request["state"]).Result;
                    HttpContext.Current.Response.Redirect(oauthState);
                }
                else
                {
                    var result = new AuthorizationCodeWebApp(flow, redirecturi, uri).AuthorizeAsync(UserId,
                         CancellationToken.None).Result;
                    if (result.RedirectUri != null)
                    {
                        // Redirect the user to the authorization server.
                        HttpContext.Current.Response.Redirect(result.RedirectUri);
                    }
                    else
                    {
                        // The data store contains the user credential, so the user has been already authenticated.
                        service = new AnalyticsService(new BaseClientService.Initializer()
                        {
                            HttpClientInitializer = result.Credential,
                            ApplicationName = _applicationName
                        });
                        return service;
                    }
                }
                return null;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        internal class ForceOfflineGoogleAuthorizationCodeFlow : GoogleAuthorizationCodeFlow
        {
            public ForceOfflineGoogleAuthorizationCodeFlow(GoogleAuthorizationCodeFlow.Initializer initializer) : base(initializer) { }
            public override AuthorizationCodeRequestUrl CreateAuthorizationCodeRequest(string redirectUri)
            {
                var ss = new Google.Apis.Auth.OAuth2.Requests.GoogleAuthorizationCodeRequestUrl(new Uri(AuthorizationServerUrl));
                ss.AccessType = "offline";
                ss.ApprovalPrompt = "force";
                ss.ClientId = ClientSecrets.ClientId;
                ss.Scope = string.Join(" ", Scopes);
                ss.RedirectUri = redirectUri;
                return ss;
            }
        };
    }
}

我还使用数据存储类。 将令牌保存到服务器上的文件中不是最佳做法。我使用了一个SQL数据库。

数据存储类的示例。它会为你做一个表格,不是最好的方法,但测试足够好。

using Google.Apis.Json;
using Google.Apis.Util.Store;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GoogleOauth2DemoWebApp
{
    public class DbDataStore : IDataStore
    {
        readonly string connectionString;

        public string ConnectionString { get { return connectionString; } }
        private Boolean _ConnectionExists { get; set; }
        public Boolean connectionExists { get { return _ConnectionExists; } }

        /// <summary>
        /// Constructs a new file data store with the specified folder. This folder is created (if it doesn't exist 
        /// yet) under the current directory
        /// </summary>
        /// <param name="folder">Folder name</param>
        public DbDataStore(String _connectionString)
        {
            connectionString = _connectionString;
            SqlConnection myConnection = this.connectdb();   // Opens a connection to the database.
            if (_ConnectionExists)
            {
                // check if the Table Exists;
                try
                {
                    SqlDataReader myReader = null;
                    SqlCommand myCommand = new SqlCommand("select 1 from GoogleUser where 1 = 0",
                                             myConnection);
                    myReader = myCommand.ExecuteReader();
                    while (myReader.Read())
                    {
                        var hold = myReader["Column1"];
                    }
                }
                catch
                {
                    // table doesn't exist we create it
                    SqlCommand myCommand = new SqlCommand("CREATE TABLE [dbo].[GoogleUser]( " +
                                                          " [username] [nvarchar](4000) NOT NULL," +
                                                          " [RefreshToken] [nvarchar](4000) NOT NULL," +
                                                          " [Userid] [nvarchar](4000) NOT NULL" +
                                                           " ) ON [PRIMARY]", myConnection);
                    myCommand.ExecuteNonQuery();
                }
            }
            myConnection.Close();
        }
        /// <summary>
        /// Stores the given value for the given key. It creates a new file (named <see cref="GenerateStoredKey"/>) in 
        /// <see cref="FolderPath"/>.
        /// </summary>
        /// <typeparam name="T">The type to store in the data store</typeparam>
        /// <param name="key">The key</param>
        /// <param name="value">The value to store in the data store</param>
        public Task StoreAsync<T>(string key, T value)
        {
            if (string.IsNullOrEmpty(key))
            {
                throw new ArgumentException("Key MUST have a value");
            }
            var serialized = NewtonsoftJsonSerializer.Instance.Serialize(value);
            SqlConnection myConnection = this.connectdb();
            if (!_ConnectionExists)
            {
                throw new Exception("Not connected to the database");
            }
            // Try and find the Row in the DB.
            using (SqlCommand command = new SqlCommand("select Userid from GoogleUser where UserName = @username", myConnection))
            {
                command.Parameters.AddWithValue("@username", key);
                string hold = null;
                SqlDataReader myReader = command.ExecuteReader();
                while (myReader.Read())
                {
                    hold = myReader["Userid"].ToString();
                }
                myReader.Close();

                if (hold == null)
                {
                    try
                    {
                        // New User we insert it into the database
                        string insertString = "INSERT INTO [dbo].[GoogleUser]  ([username],[RefreshToken],[Userid]) " +
                                              " VALUES (@key,@value,'1' )";
                        SqlCommand commandins = new SqlCommand(insertString, myConnection);
                        commandins.Parameters.AddWithValue("@key", key);
                        commandins.Parameters.AddWithValue("@value", serialized);
                        commandins.ExecuteNonQuery();
                    }
                    catch (Exception ex)
                    {
                        throw new Exception("Error inserting new row: " + ex.Message);
                    }

                }
                else
                {
                    try
                    {
                        // Existing User We update it                        
                        string insertString = "update [dbo].[GoogleUser] " +
                                              " set  [RefreshToken] = @value  " +
                                              " where username = @key";
                        SqlCommand commandins = new SqlCommand(insertString, myConnection);
                        commandins.Parameters.AddWithValue("@key", key);
                        commandins.Parameters.AddWithValue("@value", serialized);
                        commandins.ExecuteNonQuery();
                    }
                    catch (Exception ex)
                    {
                        throw new Exception("Error updating user: " + ex.Message);
                    }
                }
            }

            myConnection.Close();
            return TaskEx.Delay(0);
        }
        /// <summary>
        /// Deletes the given key. It deletes the <see cref="GenerateStoredKey"/> named file in <see cref="FolderPath"/>.
        /// </summary>
        /// <param name="key">The key to delete from the data store</param>
        public Task DeleteAsync<T>(string key)
        {
            if (string.IsNullOrEmpty(key))
            {
                throw new ArgumentException("Key MUST have a value");
            }
            SqlConnection myConnection = this.connectdb();
            if (!_ConnectionExists)
            {
                throw new Exception("Not connected to the database");
            }
            // Deletes the users data.                        
            string deleteString = "delete from [dbo].[GoogleUser] " +
                                  "where username = @key";
            SqlCommand commandins = new SqlCommand(deleteString, myConnection);
            commandins.Parameters.AddWithValue("@key", key);
            commandins.ExecuteNonQuery();

            myConnection.Close();
            return TaskEx.Delay(0);
        }
        /// <summary>
        /// Returns the stored value for the given key or <c>null</c> if the matching file (<see cref="GenerateStoredKey"/>
        /// in <see cref="FolderPath"/> doesn't exist.
        /// </summary>
        /// <typeparam name="T">The type to retrieve</typeparam>
        /// <param name="key">The key to retrieve from the data store</param>
        /// <returns>The stored object</returns>
        public Task<T> GetAsync<T>(string key)
        {
            //Key is the user string sent with AuthorizeAsync
            if (string.IsNullOrEmpty(key))
            {
                throw new ArgumentException("Key MUST have a value");
            }
            TaskCompletionSource<T> tcs = new TaskCompletionSource<T>();

            // Note: create a method for opening the connection.
            SqlConnection myConnection = new SqlConnection(this.ConnectionString);
            myConnection.Open();
            // Try and find the Row in the DB.
            using (SqlCommand command = new SqlCommand("select RefreshToken from GoogleUser where UserName = @username;", myConnection))
            {
                command.Parameters.AddWithValue("@username", key);
                string RefreshToken = null;
                SqlDataReader myReader = command.ExecuteReader();
                while (myReader.Read())
                {
                    RefreshToken = myReader["RefreshToken"].ToString();
                }
                if (RefreshToken == null)
                {
                    // we don't have a record so we request it of the user.
                    tcs.SetResult(default(T));
                }
                else
                {
                    try
                    {
                        // we have it we use that.
                        tcs.SetResult(NewtonsoftJsonSerializer.Instance.Deserialize<T>(RefreshToken));
                    }
                    catch (Exception ex)
                    {
                        tcs.SetException(ex);
                    }
                }
            }
            return tcs.Task;
        }
        /// <summary>
        /// Clears all values in the data store. This method deletes all files in <see cref="FolderPath"/>.
        /// </summary>
        public Task ClearAsync()
        {
            SqlConnection myConnection = this.connectdb();
            if (!_ConnectionExists)
            {
                throw new Exception("Not connected to the database");
            }
            // Removes all data from the Table.
            string truncateString = "truncate table [dbo].[GoogleUser] ";
            SqlCommand commandins = new SqlCommand(truncateString, myConnection);
            commandins.ExecuteNonQuery();
            myConnection.Close();
            return TaskEx.Delay(0);
        }
        /// <summary>Creates a unique stored key based on the key and the class type.</summary>
        /// <param name="key">The object key</param>
        /// <param name="t">The type to store or retrieve</param>
        public static string GenerateStoredKey(string key, Type t)
        {
            return string.Format("{0}-{1}", t.FullName, key);
        }

        //Handel's creating the connection to the database
        private SqlConnection connectdb()
        {
            SqlConnection myConnection = null;
            try
            {
                myConnection = new SqlConnection(this.ConnectionString);
                try
                {
                    myConnection.Open();
                    // ensuring that we are able to make a connection to the database.
                    if (myConnection.State == System.Data.ConnectionState.Open)
                    {
                        _ConnectionExists = true;
                    }
                    else
                    {
                        throw new ArgumentException("Error unable to open connection to the database.");
                    }
                }
                catch (Exception ex)
                {
                    throw new ArgumentException("Error opening Connection to the database: " + ex.Message);
                }
            }
            catch (Exception ex)
            {
                throw new ArgumentException("Error creating Database Connection: " + ex.Message);
            }
            return myConnection;
        }
    }
}

使用该类:

GoogleOauth g = new GoogleOauth();
                AnalyticsService service = g.Handle(userEmailAddress, 
                    connectionString, redirectUrl,
                    "YOURAPLICATIONNAME",
                    new[] {AnalyticsService.Scope.AnalyticsReadonly});
                DataResource.RealtimeResource.GetRequest request = service.Data.Realtime.Get(String.Format("ga:{0}", profileId), "rt:activeUsers");
                RealtimeData feed = request.Execute();

如果人们感兴趣,我可以将示例项目上传到github。

最新更新