Warm tip: This article is reproduced from serverfault.com, please click

vb.net-验证/刷新Google API访问令牌并避免“文件正在使用”异常?

(vb.net - Authenticating / Refreshing Google API access token and avoiding a "file in use" exception?)

发布于 2020-11-30 21:02:22

这是我使用Google API进行身份验证的方式:

Private Function DoAuthentication(ByRef rStrToken As String, ByRef rParameters As OAuth2Parameters) As Boolean
    Dim credential As UserCredential
    Dim Secrets = New ClientSecrets() With {
        .ClientId = m_strClientID,
        .ClientSecret = m_strClientSecret
    }

    m_Scopes.Add(CalendarService.Scope.Calendar)

    Try
        credential = GoogleWebAuthorizationBroker.AuthorizeAsync(Secrets, m_Scopes,
                                                                 "user", CancellationToken.None,
                                                                 New FileDataStore("XXXXX.Application")).Result()

        If credential.Token.IsExpired(Google.Apis.Util.SystemClock.Default) Then
            credential.RefreshTokenAsync(CancellationToken.None)
        End If


        ' Create the calendar service using an initializer instance
        Dim initializer As New BaseClientService.Initializer() With {
            .HttpClientInitializer = credential,
            .ApplicationName = "xxx"
        }
        m_Service = New CalendarService(initializer)

        rStrToken = credential.Token.AccessToken.ToString()
        rParameters.AccessToken = credential.Token.AccessToken
        rParameters.RefreshToken = credential.Token.RefreshToken
    Catch ex As Exception
        ' We encountered some kind of problem, perhaps they have not yet authenticated?
        ' Can we isolate that as the exception?
        m_logger.Error(ex, "DoAuthentication")

        Return False
    End Try

    Return True
End Function

然后在我的Main

Dim parameters As New OAuth2Parameters
If (DoAuthentication(strToken, parameters)) Then
    iResult = RESULT_SUCCESS_OAUTH
Else
    Return RESULT_FAILED_OAUTH
End If

然后继续。问题是,有时即使“身份验证”成功完成,它也开始运行其余代码。然后我得到一个例外:

2020-11-30 18:47:03.6762|ERROR|GoogleAuthandSync.Program|AddEventsToCalendarXML|System.IO.IOException: The process cannot access the file 'C:\Users\USERNAME\AppData\Roaming\XXXXX.Application\Google.Apis.Auth.OAuth2.Responses.TokenResponse-user' because it is being used by another process.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)

如何验证/刷新令牌,并确保我们准备好进行操作,以便此异常停止?并非总是如此。

(为了安全起见,我在上面的代码/错误文本中将令牌文件重命名为)。


我应该使用Await关键字吗?

在此处输入图片说明

If credential.Token.IsExpired(Google.Apis.Util.SystemClock.Default) Then
    Await credential.RefreshTokenAsync(CancellationToken.None)
End If

那会有所作为吗?我注意到在此示例代码中,他们使用await

Questioner
Andrew Truckle
Viewed
11
Andrew Truckle 2020-12-01 22:16:09

鼓励我在GitHub上问这个问题(请参阅讨论)。

事实证明,我并不需要像以前那样使用RefreshTokenAsync我能够简化我的代码,并将其转换为如下所示的Async方法:

Private Async Function DoAuthenticationAsync() As Task(Of Boolean)
    Dim credential As UserCredential
    Dim Secrets = New ClientSecrets() With {
        .ClientId = m_strClientID,
        .ClientSecret = m_strClientSecret
    }

    Try
        credential = Await GoogleWebAuthorizationBroker.AuthorizeAsync(Secrets, m_Scopes,
                                                             "user", CancellationToken.None,
                                                             New FileDataStore("XXXXX.Application"))

        ' Create the calendar service using an initializer instance
        Dim initializer As New BaseClientService.Initializer() With {
            .HttpClientInitializer = credential,
            .ApplicationName = "XXXXX"
        }

        m_Service = New CalendarService(initializer)

    Catch ex As Exception
        ' We encountered some kind of problem, perhaps they have not yet authenticated?
        ' Can we isolate that as the exception?
        m_logger.Error(ex, "DoAuthentication")

        Return False
    End Try

    Return True
End Function

然后,我不得不将Main函数中的所有代码移到一个任务中:

Private Async Function Run() As Task(Of Integer)
    ...
End Function

最后,我进行了Main如下调整

Public Function Main() As Integer
    Return RunAsync.Result
End Function