Google Drive .Net API. No metadata for files available - c#

I'm trying to get Folders and Files from Google Drive, and there is some non-obvious stuff I can't understand.
First of all, I'm getting 37 items as a result - and that's wrong, because I never had 37 files on my Drive, so where all those files came from ?
Second, I'm not receiving file metadata like "Size" or "Extension" or "Parents" - all these properties are "null" for at least half of all items returned - can someone explain what means is "Parents" are "null"?
And the last thing, can I get files and folders step-by-step, like in OneDrive, e.g., get all files and folders from root of a drive, and later get children from selected folder (or download item if it's file)?
As far as I know, I have to get all files and folders and then build a tree to show it to user, as for me that's not good, because of multi-parenting stuff etc.
Here's code I use to get files and properties:
public UserCredential Authorize()
{
UserCredential credential = null;
using (var stream =
new FileStream("path_to_secret.json", FileMode.Open, FileAccess.Read))
{
string credPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
credPath = Path.Combine(credPath, "path_to_save_creds.json");
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true)).Result;
}
return credential;
}
public List<File> RetrieveAllFiles(DriveService service)
{
List<File> result = new List<File>();
FilesResource.ListRequest request = service.Files.List();
request.Fields =
"nextPageToken, files(name, id, size, kind, parents, sharedWithMeTime, shared, sharingUser, fileExtension, viewedByMe, viewedByMeTime, trashed)";
request.Spaces = "drive";
do
{
try
{
FileList files = request.Execute();
result.AddRange(files.Files);
request.PageToken = files.NextPageToken;
}
catch (Exception e)
{
/*handle exception here*/
}
} while (!String.IsNullOrEmpty(request.PageToken));
return result;
}
Here's how do I call methods described above:
UserCredential credential = Authorize();
var service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
var googleFiles = RetrieveAllFiles(service);
At this point, I have 37 items, and such properties as "fileExtension", "viewedByMe", "parents" are null. Can someone explain what happens?

First, you might want to check how your authorization to see who's account is being accessed.
Second, try checking the OAuth 2.0 Playground as suggested in the related SO post to test whether something wrong in your code or in the API. Also stated in the post that files like folders, Google Docs which are simply links will be null.
For the Tree Command like function for your Google Drive, it will all depend on how your approach is. I found a tutorial using Apps Script which will show the basic steps on getting a hierarchical tree diagram for your Drive files.
Hope this helps.

Related

Create external shortcut in shared drive by using Google drive api

I am trying to create an external shortcut to some web on Google shared drive. There is the documentation: https://developers.google.com/drive/api/v3/third-party-shortcuts but I have no idea how to pass URL to the page I want.
var credential = GoogleCredential.FromJson(jsonSecret)
.CreateScoped(Scopes)
.CreateWithUser("myemail#company.com")
.UnderlyingCredential as ServiceAccountCredential;
DriveService _driveService = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "to-teamdrive"
});
var fileMetadata = new File()
{
Name = "Test shortcut",
MimeType = "application/vnd.google-apps.drive-sdk",
Parents = new List<string> { "0AKSia6LzF-hvuk9PVA"}
};
var uploadRequest = _driveService.Files.Create(fileMetadata);
uploadRequest.SupportsAllDrives = true;
uploadRequest.Fields = "id";
var file = uploadRequest.Execute();
Additionally, executing this code throws:
Message="The application associated with this shortcut file does not support shared drives."
I can create a "link" in my drive when skipping Parents property but even then I do not know how to add URL to this "link". It creates empty... file... on my drive.
Looks like those external links were not something I was looking for. To solve my problem it is enough to create a file with name: 'name.url', mimeType 'text/x-url' and content similar to this:
[InternetShortcut]
URL=<URL here>
I have no idea if this is common or works only for my organization (we have some modifications done to the google apps).

Can i view and open a file in google drive in browser using C#

I have done necessary steps to enable google drive API with my google account.
https://developers.google.com/sheets/api/quickstart/dotnet?refresh=1
Below code only returns the value for the files contain data and editable link.
How can i open the file in google drive in a browser using c# with google drive API?
Can you please share any other solution?
static void Main(string[] args)
{
try
{
static string[] Scopes = { SheetsService.Scope.Spreadsheets };
static string ApplicationName = "Google Sheets API .NET Quickstart";
UserCredential credential;
using (var stream = new FileStream("credentials.json", FileMode.Open, FileAccess.ReadWrite))
{
string credPath = "token.json";
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true)).Result;
Console.WriteLine("Credential file saved to: " + credPath);
}
var service = new SheetsService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
String spreadsheetId = "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms";
List<string> ranges = new List<string>();
bool includeGridData = false;
SpreadsheetsResource.GetRequest request = service.Spreadsheets.Get(spreadsheetId);
request.Ranges = ranges;
request.IncludeGridData = includeGridData;
Spreadsheet response = request.Execute();
Console.WriteLine(JsonConvert.SerializeObject(response));
Console.Read();
}
catch (Exception e)
{
var ex = e;
Console.WriteLine(e.Message);
}
}
Thanks,
Sangeetha P.
The Google drive API is a file store api. It allows you to upload, download, delete files. It contains a folder list hierarchy list of your files.
It does not have the ability to open your files and see the continence. To do this in C# you will need to download the file locally and program something in your application that can open the file. The response from this api will be Json. You may be able to download the file as a stream and put it some place but thats really not what you should be doing.
Alternately depending upon the type of file you can check for a weblink or download link parameter in the file metadata. This will open the file in google docs on the users browser if they have permissions enough to see the file.
Google sheets files can be opens using the google sheets api, Google doc files can be opened using the google docs api. These may be better options for you to get a formatted version of the contents of your file. But you will still need to create your own application to showthese files.

Upload file to Google Team Drive

I've been scouring the internet for a few hours trying to figure out what is necessary to upload a file that will be contained within a Team Drive.
I've read most of the documentation, the only interesting bits / mention of team drives I found are here, but unfortunately there's no specifics:
https://developers.google.com/drive/v3/web/manage-uploads
https://developers.google.com/drive/v3/web/manage-teamdrives
https://developers.google.com/drive/v3/web/about-files
I'm using the .Net gapi nuget package (v3). Create a service like the following:
string[] scopes = new string[] { DriveService.Scope.Drive, DriveService.Scope.DriveFile };
var secrets = new ClientSecrets
{
ClientId = "...",
ClientSecret = "...",
};
var credential = GoogleWebAuthorizationBroker.AuthorizeAsync(secrets, scopes, Environment.UserName, CancellationToken.None).Result;
var service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "...",
});
I have the Id of the Team Drive I'm targetting, and I can successfully retrieve the TeamDrive by the following code, but there are no interesting methods here for uploading:
var teamDrive = service.Teamdrives.Get(driveFolderId).Execute();
I've currently been trying to use the normal CreateMediaUpload way of creating a file.
File body = new File();
body.Name = name;
body.MimeType = "application/octet-stream";
FilesResource.CreateMediaUpload request = service.Files.Create(body, stream, "text/plain");
request.Upload();
There's a few interesting properties on File, namely Parents and also TeamDriveId. When setting the TeamDriveId to the Team Drive Id, the file ends up in my personal drive in the root directory. When setting the parent to the Team Drive Id, I can't seem to find the file anywhere.
There are no errors thrown, and the result of request.Upload() indicates Success/Complete every time (even if the file doesn't show up). Where else should I be looking to set the parent team drive? There's no other interesting properties on File, DriveService, or TeamDrive so I'm pretty lost.
In addition to setting to the parent to the team drive id, you must also set the SupportsTeamDrives property to true in the request.
The code would then look similar to the following (I've noted the important lines):
File body = new File();
body.Name = name;
body.MimeType = "application/octet-stream";
body.Parents = new List<string> { driveFolderId }; // <--------
FilesResource.CreateMediaUpload request = service.Files.Create(body, stream, "application/octet-stream");
request.SupportsTeamDrives = true; // <--------
request.Upload();
The key here is that the Team Drives permission scheme is completely different to the personal drive permission scheme, so you need to explicitly opt-in to it to prove you understand the differences.
An extra bit of info, if you want to list or search for files in a team drive, you must also specify IncludeTeamDriveItems and Corpora on the request (in addition to SupportsTeamDrives).
A Search might then look like this
var existingSearch = service.Files.List();
existingSearch.Fields = "nextPageToken, files(id, name)";
existingSearch.Q = $"'{driveFolderId}' in parents and name = '{name}'";
if (isFolderTeamDrive)
{
existingSearch.SupportsTeamDrives = true;
existingSearch.Corpora = "teamDrive";
existingSearch.IncludeTeamDriveItems = true;
existingSearch.TeamDriveId = driveFolderId;
}
var existingResponse = existingSearch.Execute();

Creating folder using Google Drive API gives invalid_grant but can create actual file with same connection

I can setup a Google user content connection with Google API and can get folders and even upload/create files to folders. But the same connection used to create a new regular folder anywhere gives the error invalid_grant with no further information. I am passing in a valid folderId to set as parent. I have tried different scopes and a long shot of syncing my clock like I have seen on other solutions. I can't seem to figure out the issue. Anyone else have seen this?
Here is code that works to upload a file to a folder:
public async Task<string> Upload(string localFilePath, string folderId, string fileName, string refreshToken, string userId)
{
var file = new File();
file.MimeType = GetMimeType(localFilePath);
file.Name = fileName;
file.Parents = new List<string> { folderId };
var driveService = await GetDriveService(refreshToken, userId);
// File's content.
var byteArray = System.IO.File.ReadAllBytes(localFilePath);
var stream = new System.IO.MemoryStream(byteArray);
var request = driveService.Files.Create(file, stream, file.MimeType);
await request.UploadAsync();
return request.ResponseBody.Id;
}
Here is what I've been trying in creating a folder:
public async Task<string> CreateFolder(string folderId, string folderName, string refreshToken, string userId)
{
var newFolderId = string.Empty;
var driveService = await GetDriveService(refreshToken, userId);
FilesResource.ListRequest list = driveService.Files.List();
var file = new File();
file.MimeType = "application/vnd.google-apps.folder";
file.Name = folderName;
file.Parents = new List<string> { folderId };
var request = driveService.Files.Create(file);
request.Fields = "Id";
var newFolder = await request.ExecuteAsync();
return newFolder.Id;
}
And, here is the method in defining driveService:
private async Task<DriveService> GetDriveService(string refreshToken, string userId)
{
var credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
clientSecrets: new ClientSecrets { ClientId = "xyz.apps.googleusercontent.com", ClientSecret = "xyz" },
scopes: new string[] { DriveService.Scope.Drive, DriveService.Scope.DriveFile },
dataStore: new MemoryDataStore(userId, refreshToken),
user: userId,
taskCancellationToken: CancellationToken.None);
var driveService = new DriveService(new BaseClientService.Initializer
{
HttpClientInitializer = credential,
ApplicationName = "XYZ"
});
return driveService;
}
As mentioned in creating a folder,
In the Drive API, a folder is essentially a file — one identified by the special folder MIME type application/vnd.google-apps.folder. You can create a new folder by inserting a file with this MIME type and a folder title. Do not include an extension when setting a folder title.
Please try using the given code:
File fileMetadata = new File();
fileMetadata.setName("Invoices");
fileMetadata.setMimeType("application/vnd.google-apps.folder");
File file = driveService.files().create(fileMetadata)
.setFields("id")
.execute();
System.out.println("Folder ID: " + file.getId());
I apologize, I am a victim of a copy/paste or fat finger error that I just did not notice unfortunately until now. I am managing multiple cloud connections in this app for similar purposes, and at the beginning of the call in this case to create folder I either copy/pasted or fat fingered an enum value that was improperly requesting to get the saved refreshtoken from a different cloud provider ala one drive or dropbox. Once switched to pull the saved google refreshtoken, it works. Well, at least there is a working example of create folder and upload file above :-) Btw, the line request.Fields = "Id"; needs to be request.Fields = "id"; where id needs to be lower case...otherwise a different error pops up saying the field is invalid. Thanks.

YouTube Data API v3: deleting videos using a service account: Unauthorized client or scope in request

I'm trying to delete one or more videos using a simple C# app (I intend to use a Windows Service later) and I'm getting this error:
Google.Apis.Auth.OAuth2.Responses.TokenResponseException: Error:"unauthorized_client", Description:"Unauthorized client or scope in request.", Uri:""
at Google.Apis.Requests.ClientServiceRequest`1.Execute() in c:\code\google.com\google-api-dotnet-client\default\Tools\Google.Apis.Release\bin\Debug\test\default\Src\GoogleApis\Apis\Requests\ClientServiceRequest.cs:line 93
Uploading videos works perfectly. For both operations, I use the same initialization method:
private static YouTubeService AuthorizeYoutubeService()
{
string serviceAccountEmail = "...#developer.gserviceaccount.com";
string keyFilePath = "Warehouse<...>.p12";
string userAccountEmail = "login#gmail.com";
if (!File.Exists(keyFilePath))
{
System.Windows.Forms.MessageBox.Show("Secret file not found!");
return null;
}
var scope = new string[] { YouTubeService.Scope.Youtube };
var cert = new X509Certificate2(keyFilePath, "notasecret", X509KeyStorageFlags.Exportable);
try
{
ServiceAccountCredential credential = new ServiceAccountCredential
(new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = scope,
User = userAccountEmail
}.FromCertificate(cert));
var service = new YouTubeService(new BaseClientService.Initializer
{
HttpClientInitializer = credential,
ApplicationName = "warehouse"
});
return service;
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
return null;
}
}
The difference compared to simply uploading videos, is the defined Scope: YouTubeService.Scope.YoutubeUpload. When I try to delete a video using it, I get an insufficientPermissions (403) error.
So after looking in the documentation I've changed it to YouTubeService.Scope.Youtube.
Here's the code I'm trying to use:
var youtubeService = AuthorizeYoutubeService();
foreach (string id in deleteIds)
{
var videoDeleteRequest = youtubeService.Videos.Delete(id);
var result = videoDeleteRequest.Execute();
}
Where deleteIds is a list of 11 character strings containing IDs of existing videos.
I have YouTube Data API enabled in the developers console.
I've installed the API via NuGet, I don't think there's anything wrong with the packages.
I'm quite new to Google development, and all similar questions were about the calendar API.
I appreciate any help.
What I ended up doing is reseting the list of apps connected to the Google account and setting it up again from scratch. My app was added 2 times for some reason.

Categories