MicrosoftDocs / WindowsCommunityToolkitDocs

Creative Commons Attribution 4.0 International
179 stars 155 forks source link

The authentication windows prompts every time requested. #299

Open miracletower opened 4 years ago

miracletower commented 4 years ago

Hi, I`m using graph in my Uwp project, with the support from login button control. And I use IProvider.Graph as the service client object as what the sample does. My app is intended to synchronize lots of files between onedrive and local files, so that many local files will be uploaded to a specific onedrive folder. For now, with the help of this control,.I can successfully login, and start the uploading sequence. But the problem is, after uploading several files( approximately 7-10 files), the authentication windows will start to prompt eveytime the graphserviceclient trying to upload a file. If I close the authentication window, the login button control is also logged out. I spent days search for solutions, but with no luck. Please tell me where could the problem be. The provider? My tenant setting?(should it be administrator?)The login button control? Or I should have my application verified?

Thank you very much.


Document Details

Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.

michael-hawker commented 4 years ago

Thanks @miracletower for the report, can you share the specific code calls you're calling from the Graph API?

We just provide the object from the Graph SDK, so once you've logged in, it should just be using everything from the Client Library. You may get more traction filing an issue directly on their repo as we also use their auth providers built on top of the Identity library.

FYI @darrelmiller

miracletower commented 4 years ago

@michael-hawker Thank you so much for you reply. I re-organized the issue description in detail to make it much more clear.

1.Description

Batch uploading files from the app's localstate folder, up into a onedrive folder, will start to fail after 7 ~ 10 times' success , unless you re-input your live id and password again and again for the authentication window raised up by every uploading request after that. (even when the login button stays in Logged-in state as the picture below shows). authenticaion prompts while logged in

Here is a screenshot of files in my onedrive's folder when the unexpected prompt happens ( each time from 7 to 10 files could be uploaded on start). files on onedrive

2.The Demo Project and Sample Data

Since my project is quite complicated, I wrote a brand new project to demonstrate this issue, to make it simple and clean. According to my test on the project, the authentication windows start to prompt after 8 files uploaded to onedrive.

GraphDemo.zip

GrahDemo is the demo Uwp Project, please launch it first, login with your live Id, then use the built-in button to open its local state folder ( for you convenience) and copy my sample data files into it. at last, please click the start button. LocalState.zip

3.Specific Core Code

the core code is as below:

`private IProvider _provider; private Microsoft.Graph.GraphServiceClient _graphClient;

//files to be synchronized List filesToBeSynchronized;

    private bool checkLoggedin()
    {
        if (_provider == null)
        {
            _provider = ProviderManager.Instance.GlobalProvider;
            _graphClient = _provider.Graph;
        }
        return _provider != null && _provider.State == ProviderState.SignedIn;
    }

private async void Start_Click(object sender, RoutedEventArgs e) { if (!checkLoggedin()) { return; } //All files are uploaded to a folder called "snowwriting" //so get file id for the folder access in advance. targetFolderId = await initializeTargetFolderId(); if (string.IsNullOrEmpty(targetFolderId)) { var dlg = new MessageDialog("The target folder is now available.", "failure"); await dlg.ShowAsync(); return; } btnStart.IsEnabled = false; generateLocalFileList(); txtStatus.Text = "synchronizing..."; foreach (string file in filesToBeSynchronized) { //upload the file, and set its description to original local directory path,

region authentication windows prompts after 7 files uploaded

            //After uploaded 7 files, the authentication windows prompts on each uploading request.
            await uploadFile(file, Path.GetDirectoryName(file));
            #endregion
        }
        txtStatus.Text = "synchronizing finished";
        btnStart.IsEnabled = true;
    }

private async Task<string> initializeTargetFolderId()
    {
        var driveItems = await _graphClient.Me.Drive.Root.Children.Request().GetAsync();
        //try to get the id of folder "snowwriting", which is the target uploading folder
        //create the folder if it does not exists.
        var appRootItem = driveItems.Where(d => d.Name == "SnowWriting").FirstOrDefault();
        if (appRootItem == null)
        {
            var driveItem = new Microsoft.Graph.DriveItem
            {
                Name = "SnowWriting",
                Folder = new Microsoft.Graph.Folder { },
                AdditionalData = new Dictionary<string, object>() { { "@microsoft.graph.conflictBehavior", "rename" } }
            };
            appRootItem = await _graphClient.Me.Drive.Root.Children.Request().AddAsync(driveItem);
            if (appRootItem == null)
                return string.Empty;
        }
        return appRootItem.Id;
    }

    private async Task uploadFile(string filePath, string dirPathforDescription)
    {
        try
        {
            FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
            // Read byte[] from file
            byte[] bytes = new byte[fileStream.Length];
            fileStream.Read(bytes, 0, bytes.Length);
            fileStream.Close();

            using (MemoryStream ms = new MemoryStream(bytes))
            {
                string fileName = System.IO.Path.GetFileName(filePath);
                if (bytes.Length <= 4 * 1024000)
                {
                    var result = await _graphClient.Me.Drive.Items[targetFolderId].ItemWithPath(fileName).Content.Request().PutAsync<Microsoft.Graph.DriveItem>(ms);
                    if (result != null)
                    {
                        //After uploading the file, set the file's description to it's orginal local path;
                        Microsoft.Graph.DriveItem item = new Microsoft.Graph.DriveItem { Description = dirPathforDescription };
                        await _graphClient.Me.Drive.Items[result.Id].Request().UpdateAsync(item);
                    }
                }
                else
                {
                    // Get the provider. 
                    // POST /v1.0/drive/items/01KGPRHTV6Y2GOVW7725BZO354PWSELRRZ:/_hamiltion.png:/microsoft.graph.createUploadSession
                    // The CreateUploadSesssion action doesn't seem to support the options stated in the metadata.         
                    var maxChunkSize = 320 * 1024; // 320 KB - Change this to your chunk size. 5MB is the default.
                    var uploadSession = await _graphClient.Drive.Items[targetFolderId].ItemWithPath(filePath).CreateUploadSession().Request().PostAsync();

                    var provider = new Microsoft.Graph.ChunkedUploadProvider(uploadSession, _graphClient, ms, maxChunkSize);

                    // Setup the chunk request necessities
                    var chunkRequests = provider.GetUploadChunkRequests();
                    var readBuffer = new byte[maxChunkSize];
                    var trackedExceptions = new List<Exception>();
                    Microsoft.Graph.DriveItem itemResult = null;
                    //upload the chunks
                    foreach (var request in chunkRequests)
                    {
                        // Do your updates here: update progress bar, etc.
                        // ...
                        // Send chunk request
                        var result = await provider.GetChunkRequestResponseAsync(request, readBuffer, trackedExceptions);

                        if (result.UploadSucceeded)
                        {
                            itemResult = result.ItemResponse;
                        }
                    }
                    if (itemResult != null)
                    {
                        //After uploading the file, set the file's description to it's orginal local path;
                        Microsoft.Graph.DriveItem item = new Microsoft.Graph.DriveItem { Description = dirPathforDescription };
                        await ProviderManager.Instance.GlobalProvider.Graph.Me.Drive.Items[itemResult.Id].Request().UpdateAsync(item);
                    }
                    // Check that upload succeeded
                    if (itemResult == null)
                    {
                        // Retry the upload
                        //await uploadFile(filePath);
                    }
                }
            }
        }
        catch (Microsoft.Graph.ServiceException e)
        {
            //Assert.Fail("Something happened, check out a trace. Error code: {0}", e.Error.Code);
            var dlg = new MessageDialog($"Something happened, check out a trace. Error code: {e.Error.Code}", "sync error");
            await dlg.ShowAsync();
        }

    }`

I have no idea if this is a restriction for the number of uploading files within a onedrive session or what, but it really stops my project to get its last step done.

michael-hawker commented 4 years ago

Thanks @miracletower for the detailed info, can you copy your post & file that issue over on the .NET SDK Client repo?

Have you noticed if any exceptions are thrown or more details outputted when the auth window pops-up the first time again after starting the uploads?

miracletower commented 4 years ago

The post action that brings up the auth window is as below: var result = await _graphClient.Me.Drive.Items[targetFolderId].ItemWithPath(fileName).Content.Request().PutAsync<Microsoft.Graph.DriveItem>(ms); ms is a memorystream from a file. And the file, from which the uploading start to fail, is not specified.Because in my original project, and the demo project, files are being uploaded in different sequences, and each time the successful uploading number might differs. If you input liveId and pswd at the auth window, the next file could be successfully uploaded as previous files. So I don't think it has something to do with a specific file. I tried to use await Task.Delay(10000) before each uploading, but the auth window was remaining to pop-up after 7-10 files' success. Futhermore, there isn't any exceptions. since the unexpected pop-up is being "awaited" as a part of the "Content.Request().PutAsync" code. If you cancel it, an authentication failure exception will be catched, because user canceled the loggin, but for the next file in the sequence, the window will pop-up at the "PutAsync" action again. Thank you very much. @michael-hawker