2
votes

I'm writing a program to allow a user to upload files to their Google Drive account. I have the upload part working and am using OAuth2. The issue I'm currently having is getting a list of folders from the users Drive account.

I found some code that is supposed to do this using the .setUserCredentials method, but it doesn't work:

DocumentsService service1 = new DocumentsService("project");            
        service1.setUserCredentials("user","pass");

        FolderQuery query1 = new FolderQuery();

        // Make a request to the API and get all documents.
        DocumentsFeed feed = service1.Query(query1);

        // Iterate through all of the documents returned
        foreach (DocumentEntry entry in feed.Entries)
        {
            var blech = entry.Title.Text;
        }

Nothing is returned. Ideally, I want to use OAuth2 to do this. I've been trying with the following code, trying to set the authentication token, but I always get denied access:

String CLIENT_ID = "clientid";
String CLIENT_SECRET = "secretid";

var docprovider = new NativeApplicationClient(GoogleAuthenticationServer.Description, CLIENT_ID, CLIENT_SECRET);
var docstate = GetDocAuthentication(docprovider);

DocumentsService service1 = new DocumentsService("project");

service1.SetAuthenticationToken(docstate.RefreshToken);
FolderQuery query1 = new FolderQuery();

DocumentsFeed feed = service1.Query(query1); //get error here

        // Iterate through all of the documents returned
        foreach (DocumentEntry entry in feed.Entries)
        {
            // Print the title of this document to the screen
            var blech = entry.Title.Text;
        }

..

    private static IAuthorizationState GetDocAuthentication(NativeApplicationClient client)
    {
        const string STORAGE = "storagestring";
        const string KEY = "keystring";
        string scope = "https://docs.google.com/feeds/default/private/full/-/folder";            
        // Check if there is a cached refresh token available.
        IAuthorizationState state = AuthorizationMgr.GetCachedRefreshToken(STORAGE, KEY);
        if (state != null)
        {
            try
            {
                client.RefreshToken(state);
                return state; // Yes - we are done.
            }
            catch (DotNetOpenAuth.Messaging.ProtocolException ex)
            {

            }
        }

        // Retrieve the authorization from the user.
        state = AuthorizationMgr.RequestNativeAuthorization(client, scope);
        AuthorizationMgr.SetCachedRefreshToken(STORAGE, KEY, state);
        return state;
    }

Specifically, I get "Execution of request failed: https://docs.google.com/feeds/default/private/full/-/folder - The remote server returned an error: (401) Unauthorized".

I've also tried:

var docauth = new OAuth2Authenticator<NativeApplicationClient>(docprovider, GetDocAuthentication);
DocumentsService service1 = new DocumentsService("project");
service1.SetAuthenticationToken(docauth.State.AccessToken);

but "State" is always null, so I get a null object error. What am I doing wrong and how is this done?

4

4 Answers

3
votes

You should use the Drive SDK, not the Documents List API, which allows you to list folders. You can use "root" as a folderId if you want to list the root directory.

2
votes

I actually implemented the v3 version of the GDrive SDK for .NET and needed to search for folders as well.

I prefer requesting uniquely all folders instead of getting all files and then performing a LinQ query to keep just the folders.

This is my implementation:

private async Task<bool> FolderExistsAsync(string folderName)
{
    var response = await GetAllFoldersAsync();
    return response.Files
                   .Where(x => x.Name.ToLower() == folderName.ToLower())
                   .Any();
}

private async Task<Google.Apis.Drive.v3.Data.FileList> GetAllFoldersAsync()
{
    var request = _service.Files.List();
    request.Q = "mimeType = 'application/vnd.google-apps.folder'";
    var response = await request.ExecuteAsync();
    return response;
}

You could request the name on the Q this way as well:

request.Q = $"mimeType = 'application/vnd.google-apps.folder' and name = '{folderName}'";

Which would lead and simplify things to (obviating null checking):

private async Task<bool> FolderExistsAsync(string folderName)
{
    var response = await GetDesiredFolder(folderName);
    return response.Files.Any();
}

private async Task<FileList> GetDesiredFolder(string folderName)
{
    var request = _service.Files.List();
    request.Q = $"mimeType = 'application/vnd.google-apps.folder' and name = '{folderName}'";
    var response = await request.ExecuteAsync();
    return response;
}
0
votes
private IEnumerable<DocumentEntry> GetFolders(string id) {
    if (IsLogged) {
        var query = new FolderQuery(id)
        {
            ShowFolders = true
        };

        var feed = GoogleDocumentsService.Query(query);

        return feed.Entries.Cast<DocumentEntry>().Where(x => x.IsFolder).OrderBy(x => x.Title.Text);
    }

    return null;
}

    ...
var rootFolders = GetFolders("root");
if (rootFolders != null){
    foreach(var folder in rootFolders){
        var subFolders = GetFolders(folder.ResourceId);
        ...
    }
}

where GoogleDocumentsService is a instance of DocumentsService and IsLogged is a success logged flag.

0
votes

I got this way to get list of folders from google drive

  FilesResource.ListRequest filelist= service.Files.List();
  filelist.Execute().Items.ToList().Where(x => x.MimeType == "application/vnd.google-apps.folder").ToList()