I'm trying to write code to read files in a OneDrive folder of mine and, in the future, create, move and delete them.
The scrap of code below works, but it requests a new authentication (shows Microsoft's OAuth window) for each iteration in the For Each ... Next
.
What am I doing wrong here?
Imports Microsoft.Graph
Public Class FormGraphClient
Private Shared client As GraphServiceClient
Private Async Sub FormGraphClient_Load(sender As Object, e As EventArgs) Handles MyBase.Load
client = AuthenticationHelper.GetAuthenticatedClient
Dim formsmonitor_items = Await client.Me.Drive.Root.ItemWithPath("FormsMonitor").Children.Request.GetAsync
Dim forms As New Dictionary(Of String, String)
For Each form In formsmonitor_items
If form.Name Like "*.json" Then
Using formstream = Await client.Me.Drive.Items.Item(form.Id).Content.Request.GetAsync
Using reader = New IO.StreamReader(formstream)
forms(form.Name) = reader.ReadToEnd
End Using
End Using
End If
Next
End Sub
End Class
I'm using also this helper class:
Imports System.Net.Http.Headers
Imports Microsoft.Graph
Imports Microsoft.Identity.Client
Public Class AuthenticationHelper
Shared clientId As String = "my-client-id"
Public Shared Scopes As String() = {"User.Read", "Files.ReadWrite.All"}
Public Shared IdentityClientApp As PublicClientApplication = New PublicClientApplication(clientId)
Public Shared TokenForUser As String = Nothing
Public Shared Expiration As DateTimeOffset
Private Shared graphClient As GraphServiceClient = Nothing
Public Shared Function GetAuthenticatedClient() As GraphServiceClient
If graphClient Is Nothing Then
Try
graphClient = New GraphServiceClient(
"https://graph.microsoft.com/v1.0",
New DelegateAuthenticationProvider(
Async Function(requestMessage)
Dim token = Await GetTokenForUserAsync()
requestMessage.Headers.Authorization = New AuthenticationHeaderValue("bearer", token)
requestMessage.Headers.Add("SampleID", "uwp-csharp-apibrowser-sample")
End Function))
Return graphClient
Catch ex As Exception
Debug.WriteLine("Could not create a graph client: " & ex.Message)
End Try
End If
Return graphClient
End Function
Public Shared Async Function GetTokenForUserAsync() As Task(Of String)
Dim authResult As AuthenticationResult
Dim ex As Exception = Nothing
Try
authResult = Await IdentityClientApp.AcquireTokenSilentAsync(Scopes, IdentityClientApp.GetUser("[email protected]"))
TokenForUser = authResult.AccessToken
Catch ex
If TokenForUser Is Nothing OrElse Expiration <= DateTimeOffset.UtcNow.AddMinutes(5) Then
End If
End Try
If ex IsNot Nothing Then
Try
authResult = Await IdentityClientApp.AcquireTokenAsync(Scopes)
TokenForUser = authResult.AccessToken
Expiration = authResult.ExpiresOn
Catch ex
End Try
End If
Return TokenForUser
End Function
End Class
I checked up samples here and there, and came up with this wrapper class. I think I'll work on it more, but for the moment, it solved the problem mentioned at this post:
Imports System.Net.Http
Imports System.Net.Http.Headers
Imports Microsoft.Graph
Imports Microsoft.Identity.Client
Public Class MsGraph
Private Const baseUrl As String = "https://graph.microsoft.com/v1.0"
Private ReadOnly client_id As String
Private ReadOnly scopes As String()
Private authSuccess As Boolean
Private clientApp As PublicClientApplication
Public Sub New(app_client_id As String, ParamArray app_scopes As String())
client_id = app_client_id
If Not app_scopes.Contains("User.Read", StringComparer.InvariantCultureIgnoreCase) Then
app_scopes = {"User.Read"}.Concat(app_scopes).ToArray
End If
scopes = app_scopes
clientApp = New PublicClientApplication(client_id)
Dim authProvider = New DelegateAuthenticationProvider(AddressOf AuthenticateRequestAsync)
Try
Client = New GraphServiceClient(baseUrl, authProvider)
Catch ex As Exception
Stop
End Try
End Sub
Public ReadOnly Property Client As GraphServiceClient
Public Async Function AuthenticateRequestAsync(request As HttpRequestMessage) As Task
request.Headers.Authorization = New AuthenticationHeaderValue("bearer", Await GetTokenForUserAsync())
End Function
Private Async Function GetTokenForUserAsync() As Task(Of String)
Dim success As Boolean
Dim authResult As AuthenticationResult = Nothing
If clientApp.Users.Any Then
Try
authResult = Await clientApp.AcquireTokenSilentAsync(scopes, clientApp.Users.FirstOrDefault())
success = True
Catch ex As Exception
Stop
End Try
Else
Try
authResult = Await clientApp.AcquireTokenAsync(scopes)
success = True
Catch ex As Exception
Stop
End Try
End If
authSuccess = success
Return authResult?.AccessToken
End Function
End Class