GoogleDriveAPI C# Windows-Service - c#

I have a working C# programm which downloads and uploads files from Google Drive. The next step I wanted to do is to run my programm with a service periodically every 5 minutes. The service starts every 5 minutes, but my programm fails to authenticate to the GoogleDrive API (the credentials are null) and I don't know why.
I install and uninstall the service from my GUI program.
Note: I'm new to windows-services
public async Task Run()
{
UserCredential credential = null;
System.IO.FileStream stream = null;
try
{
stream = new System.IO.FileStream(#"C:\Users\carl\Documents\Visual Studio 2013\Projects\ServiceTest1\GoogleDrive\client_secrets.json", System.IO.FileMode.Open, System.IO.FileAccess.Read);
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
"Cloud Manager",
CancellationToken.None,
new FileDataStore("ServiceTest1")
).Result;
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
if(stream != null)
{
stream.Dispose();
}
}
await credential.RefreshTokenAsync(CancellationToken.None);
// Create the service.
var service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "CloudManagerGD",
});
// For debug purpose only.
FileList fl = await service.Files.List().ExecuteAsync();
About about = await service.About.Get().ExecuteAsync();
await GetFiles(service, "trollol", fl);
await PostFiles(service, "trollol", fl);
}

Related

Export / download file from Google Drive using C# produces an empty, zero-byte file

I'm attempting to download a file from Google Drive using C# & Google.Apis.Drive.v3 and I'm getting an empty, zero-byte file (see code below). I'm uploading files OK, but can't get the download to work. Any help would be greatly appreciated.
code
static string[] Scopes = { DriveService.Scope.Drive };
static string ApplicationName = "Test001";
private DriveService _service = null;
public async Task downloadFile(string url, string lstrDownloadFile)
{
// Authorize API access
UserCredential credential;
using (var stream = new FileStream("credentials.json", FileMode.Open, FileAccess.Read))
{
// The file token.json stores the user's access and refresh tokens, and is created
// automatically when the authorization flow completes for the first time.
string credPath = "token.json";
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true)).Result;
Debug.WriteLine("Credential file saved to: " + credPath);
}
// Create Drive API service.
_service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
// Attempt download
// Iterate through file-list and find the relevant file
FilesResource.ListRequest listRequest = _service.Files.List();
listRequest.Fields = "nextPageToken, files(id, name, mimeType, originalFilename, size)";
Google.Apis.Drive.v3.Data.File lobjGoogleFile = null;
foreach (var item in listRequest.Execute().Files)
{
if (url.IndexOf(string.Format("id={0}", item.Id)) > -1)
{
Debug.WriteLine(string.Format("{0}: {1}", item.OriginalFilename, item.MimeType));
lobjGoogleFile = item;
break;
}
}
FilesResource.ExportRequest request = _service.Files.Export(lobjGoogleFile.Id, lobjGoogleFile.MimeType);
Debug.WriteLine(request.MimeType);
MemoryStream lobjMS = new MemoryStream();
await request.DownloadAsync(lobjMS);
// At this point the MemoryStream has a length of zero?
lobjMS.Position = 0;
var lobjFS = new System.IO.FileStream(lstrDownloadFile, System.IO.FileMode.Create, System.IO.FileAccess.Write);
await lobjMS.CopyToAsync(lobjFS);
}
It's possible that it's something as simple as not having enabled the Drive API on your project.
I recommend you add the following code. There's likely a download error which is preventing the stream from being filled.
FilesResource.ExportRequest request = ...
request.MediaDownloader.ProgressChanged += progress =>
{
switch (progress.Status)
{
case DownloadStatus.Failed:
{
Console.WriteLine("Failed: " + progress.Exception?.Message);
break;
}
// other status case statements if you need them
}
};
MemoryStream lobjMS = ...
Then you can drop a breakpoint into the Failed case or look at the exception in the console.

Google Drive API integration is not working with live URL

i am trying to upload documents using google Drive API integration, working fine in case of localhost but not working on live domain.
using (var stream = new FileStream(#"" + folderPathForCredentials, FileMode.Open, FileAccess.ReadWrite))
{
// The file token.json stores the user's access and refresh tokens, and is created
// automatically when the authorization flow completes for the first time.
String FolderPath = #"" + folderPathForToken;
String FilePath = Path.Combine(FolderPath, "token.json");
stream.Dispose();
stream.Close();
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
new ClientSecrets
{
ClientId = clientID,
ClientSecret = clientSecret
},
Scopes,
"user",
CancellationToken.None,
new FileDataStore(FilePath, true)).Result;
}
//create Drive API service.
DriveService service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = applicationName,
});
return service;
And this is the code to Upload on Google Drive.
FilesResource.CreateMediaUpload request;
if (System.IO.File.Exists(path))
{
using (var stream = new System.IO.FileStream(path, System.IO.FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
{
request = _service.Files.Create(FileMetaData, stream, FileMetaData.MimeType);
request.Fields = "id";
request.Upload();
stream.Dispose();
stream.Close();
System.IO.File.Delete(path);
//return request.ResponseBody;
return Json(new JsonData { IsSuccess = true, Message = "Uploaded Successfully", Data = null });
}
}
Let me help in configuring the drive with live domain.

Locally saved credentials google drive api 3

I'm creating a desktop app in C#. The first time i started my app everything went fine they asked me to log-in and the permission. Now i can't log-in with another account since they saved everything locally.I tried deleting the file at ~/.credentials/drive-dotnet-quickstart.json and yes it worked but again only once they resaved the credentials but somewhere else and i can't find where. I want to be able to log-in from different account and since i also need to change the scope for permission issue i have to delete the previously saved credentials. There is how i log-in.
using (var stream =
new FileStream("client_secret.json", FileMode.Open, FileAccess.Read))
{
string credPath = System.Environment.GetFolderPath(
System.Environment.SpecialFolder.Personal);
credPath = Path.Combine(credPath, ".credentials/drive-dotnet-quickstart.json");
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true)).Result;
}
Console.WriteLine(credential.ToString());
service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
How can i delete the saved credentials ?
How can i disable the credentials saving mechanism ?
Thank you.
You can "Log out" by calling await credential.RevokeTokenAsync() or use another userID in GoogleWebAuthorizationBroker.AuthorizeAsync
using (var stream = new FileStream("client_secret.json", FileMode.Open, FileAccess.Read))
{
var flow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecretsStream = stream,
Scopes = new[] { DriveService.Scope.DriveReadonly },
DataStore = new FileDataStore(credPath, true)
});
credential = new UserCredential(flow, userId,
await flow.LoadTokenAsync(userId, CancellationToken.None)
);
bool res = await credential.RevokeTokenAsync(CancellationToken.None);
//credential = await GoogleWebAuthorizationBroker
// .AuthorizeAsync(
// stream,
// new[] { DriveService.Scope.DriveReadonly },
// userId,
// CancellationToken.None,
// new FileDataStore("oauth/drive"))
// ;
//Console.WriteLine("Credential file saved");
}
To check if credential is existed in local
await new FileDataStore(credPath, true).GetAsync<TokenResponse>(userId) != null
//or
await flow.LoadTokenAsync(userId, CancellationToken.None) != null
Just delete the token file which in "credPath" folder

How to create a window handle for invoke?

I am trying to fill a checkboxlist clbWiedergabelisten with playlist names of the authenticating user under youtube. This is my code
private async Task RunAbrufen()
{
UserCredential credential;
using (var stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read))
{
credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
// This OAuth 2.0 access scope allows for read-only access to the authenticated
// user's account, but not other types of account access.
new[] { YouTubeService.Scope.YoutubeReadonly },
"user",
CancellationToken.None,
new FileDataStore(this.GetType().ToString())
);
}
var youtubeService = new YouTubeService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = this.GetType().ToString()
});
var playlistListRequest = youtubeService.Playlists.List("snippet");
playlistListRequest.Mine = true;
// Retrieve the contentDetails part of the playlist resource for the authenticated user's playlist.
var playlistListResponse = await playlistListRequest.ExecuteAsync();
this.Invoke((MethodInvoker)delegate
{
clbWiedergabelisten.Items.Clear();
});
foreach (var playlist in playlistListResponse.Items)
{
Console.WriteLine(playlist.Snippet.Title);
this.Invoke((MethodInvoker)delegate
{
clbWiedergabelisten.Items.Add(playlist.Snippet.Title);
});
}
}
it is being run by
try
{
await new Form1().RunAbrufen();
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message);
}
But each time it says that a window handle has to be created before invoke can be used. How to do that?

Google api authorization raises the browser

I'm writing a small desktop app that will upload file to google drive. So everything is fine when I'm sign in my google account, but when I'm not, program raises browser on this page "https://accounts.google.com/ServiceLogin". I'm using this code:
ClientSecrets secret = new ClientSecrets();
secret.ClientId = "my_client_id";
secret.ClientSecret = "my_client_secret";
UserCredential credential = GoogleWebAuthorizationBroker.AuthorizeAsync(secret, new[] { DriveService.Scope.Drive }, "user", CancellationToken.None).Result;
var service = new DriveService(new BaseClientService.Initializer() { HttpClientInitializer = credential, ApplicationName = "TestUpload" });
File body = new File();
body.Title = "Title123";
body.Description = "Decription123";
body.MimeType = "image/png";
byte[] arr = System.IO.File.ReadAllBytes(fileName);
System.IO.MemoryStream stream = new System.IO.MemoryStream(arr);
FilesResource.InsertMediaUpload request = service.Files.Insert(body, stream, "image/png");
request.Upload();
So how can I authorize programmatically with out raising the browser?
Most of your problem is the fact that you are not saving the Authentication. You are requesting access but not saving it. In the following example fileDataStore stores the authentication information in a file on your pc in %AppData% this way next time you run the program no authentication will be needed, and it also wont require that you are logged into Google at the time.
//Scopes for use with the Google Drive API
string[] scopes = new string[] { DriveService.Scope.Drive,
DriveService.Scope.DriveFile};
// here is where we Request the user to give us access, or use the Refresh Token that was previously stored in %AppData%
UserCredential credential =
GoogleWebAuthorizationBroker
.AuthorizeAsync(new ClientSecrets { ClientId = CLIENT_ID
, ClientSecret = CLIENT_SECRET }
,scopes
,Environment.UserName
,CancellationToken.None
,new FileDataStore("Daimto.GoogleDrive.Auth.Store")
).Result;
DriveService service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Drive API Sample",
});
public static File uploadFile(DriveService _service, string _uploadFile, string _parent) {
if (System.IO.File.Exists(_uploadFile))
{
File body = new File();
body.Title = System.IO.Path.GetFileName(_uploadFile);
body.Description = "File uploaded by Diamto Drive Sample";
body.MimeType = GetMimeType(_uploadFile);
body.Parents = new List<ParentReference>() { new ParentReference() { Id = _parent } };
// File's content.
byte[] byteArray = System.IO.File.ReadAllBytes(_uploadFile);
System.IO.MemoryStream stream = new System.IO.MemoryStream(byteArray);
try
{
FilesResource.InsertMediaUpload request = _service.Files.Insert(body, stream, GetMimeType(_uploadFile));
request.Upload();
return request.ResponseBody;
}
catch (Exception e)
{
Console.WriteLine("An error occurred: " + e.Message);
return null;
}
}
else {
Console.WriteLine("File does not exist: " + _uploadFile);
return null;
}
}
This code is ripped from the Google Drive C# upload tutorial, if you want more information on what its doing and how it works you may want to check that. There is also a working Sample project in the Google-Dotnet-Samples project on GitHub. The tutorial is based upon that sample project.

Categories

Resources