Google API没有应用程序与此操作的指定文件相关联

时间:2014-12-30 21:10:34

标签: vb.net google-api google-calendar-api google-cloud-datastore

我能够成功连接到Google Calendar API并在我的计算机上本地运行时同步事件。但是,当Web应用程序在服务器上运行时,我收到以下错误:

No application is associated with the specified file for this operation
    at Microsoft.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
    at Microsoft.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccess(Task task)
    at Google.Apis.Auth.OAuth2.GoogleWebAuthorizationBroker.<AuthorizeAsync>d__1.MoveNext()

我不明白为什么它存在文件关联问题,因为我没有使用FileDataStore而是使用数据库来存储数据。在本地计算机上以调试模式使用Visual Studio时,一切正常,但在上载到生产服务器时会发生错误。

这是我用来连接API的代码:

Private Shared Function BuildService(EmployeeID As String) As Google.Apis.Calendar.v3.CalendarService
    '// Google OAuth for User Calendar
    Dim credential As UserCredential = GoogleWebAuthorizationBroker.AuthorizeAsync(New ClientSecrets() With { _
            .ClientId = GoogleAPI.ClientID, _
            .ClientSecret = GoogleAPI.ClientSecret _
 }, New String() {Google.Apis.Calendar.v3.CalendarService.Scope.Calendar}, EmployeeID, CancellationToken.None, New GoogleDataStore()).Result

    ' Create the service.
    Dim service = New Google.Apis.Calendar.v3.CalendarService(New BaseClientService.Initializer() With { _
                .HttpClientInitializer = credential, _
                .ApplicationName = "Influence Calandar App" _
            })


    Return service
End Function

这是我用来实现IDataStore的GoogleDataStore类:

Imports System.Collections.Generic
Imports System.Linq
Imports System.Text
Imports Google.Apis.Util.Store
Imports System.Data.SqlClient
Imports System.Threading.Tasks
Imports Google.Apis.Json

Public Class GoogleDataStore
Implements IDataStore

''' <summary>Gets the full folder path.</summary>

Private Property _ConnectionExists() As [Boolean]
    Get
        Return m__ConnectionExists
    End Get
    Set(value As [Boolean])
        m__ConnectionExists = Value
    End Set
End Property
Private m__ConnectionExists As [Boolean]
Public ReadOnly Property connectionExists() As [Boolean]
    Get
        Return _ConnectionExists
    End Get
End Property


''' <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 Sub New()
    Dim myConnection As SqlConnection = Me.connectdb()
    ' Opens a connection to the database.
    If _ConnectionExists Then
        ' check if the Table Exists;
        Try
            Dim myReader As SqlDataReader = Nothing
            Dim myCommand As New SqlCommand("select 1 from GoogleUser where 1 = 0", myConnection)
            myReader = myCommand.ExecuteReader()
            While myReader.Read()
                Dim hold = myReader("Column1")
            End While
        Catch
            ' table doesn't exist we create it
            Dim myCommand As 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()
        End Try
    End If

    myConnection.Close()
End Sub

''' <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 Function StoreAsync(Of T)(key As String, value As T) As Task Implements IDataStore.StoreAsync
    If String.IsNullOrEmpty(key) Then
        Throw New ArgumentException("Key MUST have a value")
    End If
    Dim serialized = NewtonsoftJsonSerializer.Instance.Serialize(value)

    Dim myConnection As SqlConnection = Me.connectdb()
    If Not _ConnectionExists Then
        Throw New Exception("Not connected to the database")
    End If

    ' Try and find the Row in the DB.
    Using command As New SqlCommand("select Userid from GoogleUser where UserName = @username", myConnection)
        command.Parameters.AddWithValue("@username", key)

        Dim hold As String = Nothing
        Dim myReader As SqlDataReader = command.ExecuteReader()
        While myReader.Read()
            hold = myReader("Userid").ToString()
        End While
        myReader.Close()

        If hold Is Nothing Then
            Try
                ' New User we insert it into the database
                Dim insertString As String = "INSERT INTO [dbo].[GoogleUser]  ([username],[RefreshToken],[Userid]) " + " VALUES (@key,@value,'1' )"

                Dim commandins As New SqlCommand(insertString, myConnection)
                commandins.Parameters.AddWithValue("@key", key)
                commandins.Parameters.AddWithValue("@value", serialized)
                commandins.ExecuteNonQuery()
            Catch ex As Exception
                Throw New Exception("Error inserting new row: " + ex.Message)
            End Try
        Else
            Try
                ' Existing User We update it                        
                Dim insertString As String = "update [dbo].[GoogleUser] " + " set  [RefreshToken] = @value  " + " where username = @key"

                Dim commandins As New SqlCommand(insertString, myConnection)
                commandins.Parameters.AddWithValue("@key", key)
                commandins.Parameters.AddWithValue("@value", serialized)
                commandins.ExecuteNonQuery()
            Catch ex As Exception
                Throw New Exception("Error updating user: " + ex.Message)
            End Try
        End If
    End Using

    myConnection.Close()
    Return TaskEx.Delay(0)
End Function

''' <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 Function DeleteAsync(Of T)(key As String) As Task Implements IDataStore.DeleteAsync
    If String.IsNullOrEmpty(key) Then
        Throw New ArgumentException("Key MUST have a value")
    End If
    Dim myConnection As SqlConnection = Me.connectdb()
    If Not _ConnectionExists Then
        Throw New Exception("Not connected to the database")
    End If

    ' Deletes the users data.                        
    Dim deleteString As String = "delete [dbo].[GoogleUser] from " + " where username = @key"
    Dim commandins As New SqlCommand(deleteString, myConnection)
    commandins.Parameters.AddWithValue("@key", key)
    commandins.ExecuteNonQuery()

    myConnection.Close()
    Return TaskEx.Delay(0)
End Function

''' <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 Function GetAsync(Of T)(key As String) As Task(Of T) Implements IDataStore.GetAsync
    'Key is the user string sent with AuthorizeAsync
    If String.IsNullOrEmpty(key) Then
        Throw New ArgumentException("Key MUST have a value")
    End If
    Dim tcs As New TaskCompletionSource(Of T)()

    ' Note: create a method for opening the connection.
    Dim myConnection As SqlConnection = Me.connectdb()

    ' Try and find the Row in the DB.
    Using command As New SqlCommand("select RefreshToken from GoogleUser where UserName = @username;", myConnection)
        command.Parameters.AddWithValue("@username", key)

        Dim RefreshToken As String = Nothing
        Dim myReader As SqlDataReader = command.ExecuteReader()
        While myReader.Read()
            RefreshToken = myReader("RefreshToken").ToString()
        End While

        If RefreshToken Is Nothing Then
            ' we don't have a record so we request it of the user.
            tcs.SetResult(Nothing)
        Else

            Try
                ' we have it we use that.
                tcs.SetResult(NewtonsoftJsonSerializer.Instance.Deserialize(Of T)(RefreshToken))
            Catch ex As Exception
                tcs.SetException(ex)

            End Try
        End If
    End Using

    Return tcs.Task
End Function

''' <summary>
''' Clears all values in the data store. This method deletes all files in <see cref="FolderPath"/>.
''' </summary>
Public Function ClearAsync() As Task Implements IDataStore.ClearAsync
    Dim myConnection As SqlConnection = Me.connectdb()
    If Not _ConnectionExists Then
        Throw New Exception("Not connected to the database")
    End If

    ' Removes all data from the Table.
    Dim truncateString As String = "truncate table [dbo].[GoogleUser] "
    Dim commandins As New SqlCommand(truncateString, myConnection)
    commandins.ExecuteNonQuery()

    myConnection.Close()
    Return TaskEx.Delay(0)
End Function

''' <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 Shared Function GenerateStoredKey(key As String, t As Type) As String
    Return String.Format("{0}-{1}", t.FullName, key)
End Function

'Handel's creating the connection to the database
Private Function connectdb() As SqlConnection
    Dim myConnection As SqlConnection = Nothing
    Try
        myConnection = New SqlConnection(ConfigurationManager.ConnectionStrings("db1251ConnectionString").ConnectionString)
        Try
            myConnection.Open()
            ' ensuring that we are able to make a connection to the database.
            If myConnection.State = System.Data.ConnectionState.Open Then
                _ConnectionExists = True
            Else
                Throw New ArgumentException("Error unable to open connection to the database.")
            End If
        Catch ex As Exception

            Throw New ArgumentException("Error opening Connection to the database: " + ex.Message)

        End Try
    Catch ex As Exception

        Throw New ArgumentException("Error creating Database Connection: " + ex.Message)
    End Try

    Return myConnection
End Function

End Class

任何帮助将不胜感激。我一直试图找出错误但到目前为止没有运气。由于我没有尝试访问文件,所以“没有应用程序与此操作的指定文件关联”的其他帖子都没有帮助。 “GoogleWebAuthorizationBroker”尝试打开文件,尽管被告知要使用GoogleDataStore类而不是FileDataStore,如果是这样,我该如何阻止它?

我正在运行一个托管在具有Windows Azure的VM上的vb.net Web应用程序。

1 个答案:

答案 0 :(得分:1)

我终于可以通过从GoogleWebAuthorizationBroker切换到GoogleAuthorizationCodeFlow来进行身份验证。

希望如果您收到同样的错误,下面的代码会对您有所帮助。

Private Sub GetGoogleService()
    Dim datafolder As String = Server.MapPath("App_Data/CalendarService.api.auth.store")
    Dim scopes As IList(Of String) = New List(Of String)()
    Dim UserId As String = aMP.currentEmployeeID 

    scopes.Add(Google.Apis.Calendar.v3.CalendarService.Scope.Calendar)
    Dim myclientsecret As New ClientSecrets() With { _
      .ClientId = GoogleAPI.ClientID, _
      .ClientSecret = GoogleAPI.ClientSecret _
    }

    Dim flow As GoogleAuthorizationCodeFlow

    flow = New GoogleAuthorizationCodeFlow(New GoogleAuthorizationCodeFlow.Initializer() With { _
      .DataStore = New FileDataStore(datafolder), _
      .ClientSecrets = myclientsecret, _
      .Scopes = scopes _
    })

    Dim uri As String = Request.Url.ToString()

    Dim code = Request("code")
    If code IsNot Nothing Then
        Dim token = flow.ExchangeCodeForTokenAsync(UserId, code, uri.Substring(0, uri.IndexOf("?")), CancellationToken.None).Result

        ' Extract the right state.
        Dim oauthState = AuthWebUtility.ExtracRedirectFromState(flow.DataStore, UserId, Request("state")).Result
        Response.Redirect(oauthState)
    Else
        Dim result = New AuthorizationCodeWebApp(flow, uri, uri).AuthorizeAsync(UserId, CancellationToken.None).Result
        If result.RedirectUri IsNot Nothing Then
            ' Redirect the user to the authorization server.
            Response.Redirect(result.RedirectUri)
        Else
            ' The data store contains the user credential, so the user has been already authenticated.
            'Response.Write("User Already Authorized")
            Me.isConnected = New Google.Apis.Calendar.v3.CalendarService(New BaseClientService.Initializer() With { _
               .HttpClientInitializer = result.Credential, _
               .ApplicationName = "Calandar App" _
           })
        End If
    End If

End Sub